package com.silicondust.libhdhomerun_config;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;
import com.silicondust.libhdhomerun.HDHomerun_Channels;
import com.silicondust.libhdhomerun.HDHomerun_Debug;
import com.silicondust.libhdhomerun.HDHomerun_Device;
import com.silicondust.libhdhomerun.HDHomerun_Discover;
import com.silicondust.libhdhomerun.HDHomerun_OS;
import com.silicondust.libhdhomerun.HDHomerun_Pkt;
import com.silicondust.libhdhomerun.HDHomerun_Video;
import com.silicondust.libhdhomerun.HDHomerun_Discover.hdhomerun_discover_device_t;
import com.silicondust.libhdhomerun.HDHomerun_Types.hdhomerun_channelscan_program_t;
import com.silicondust.libhdhomerun.HDHomerun_Types.hdhomerun_channelscan_result_t;
import com.silicondust.libhdhomerun.HDHomerun_Video.hdhomerun_video_stats_t;
public class HDHomerun_Config {
static String appname;
static HDHomerun_Device hd;
static HDHomerun_Debug dbg;
static int help()
{
System.out.println("Usage:\n");
System.out.println(String.format("\t%s discover\n", appname));
System.out.println(String.format("\t%s <id> get help\n", appname));
System.out.println(String.format("\t%s <id> get <item>\n", appname));
System.out.println(String.format("\t%s <id> set <item> <value>\n", appname));
System.out.println(String.format("\t%s <id> scan <tuner> [<filename>]\n", appname));
System.out.println(String.format("\t%s <id> save <tuner> <filename>\n", appname));
System.out.println(String.format("\t%s <id> upgrade <filename>\n", appname));
return -1;
}
static void extract_appname(final String argv0)
{
String arg = argv0;
int index = arg.lastIndexOf('/');
if (index >= 0) {
arg = arg.substring(index + 1);
}
index = arg.lastIndexOf('\\');
if (index >= 0) {
arg = arg.substring(index + 1);
}
appname = arg;
}
static boolean contains(final String arg, final String cmpstr)
{
if (arg.compareTo(cmpstr) == 0) {
return true;
}
if (arg.charAt(0) != '-') {
return false;
}
if (arg.charAt(1) != '-') {
return false;
}
if (arg.substring(2).compareTo(cmpstr) == 0) {
return true;
}
return false;
}
static int parse_ip_addr(final String str)
{
int[] a = new int[4];
Scanner scn = new Scanner(str);
a[0] = scn.nextInt();
scn.next(".");
a[1] = scn.nextInt();
scn.next(".");
a[2] = scn.nextInt();
scn.next(".");
a[3] = scn.nextInt();
if (a[0] == 0 || a[1] == 0 || a[2] == 0 || a[3] == 0) {
return 0;
}
return ((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | (a[3] << 0));
}
static int discover_print(final String target_ip_str)
{
int target_ip = 0;
if (target_ip_str != null && target_ip_str.length() > 0) {
target_ip = parse_ip_addr(target_ip_str);
if (target_ip == 0) {
System.out.println(String.format("invalid ip address: %s\n", target_ip_str));
return -1;
}
}
hdhomerun_discover_device_t[] result_list = new hdhomerun_discover_device_t[64];
int count = HDHomerun_Discover.hdhomerun_discover_find_devices_custom(target_ip, HDHomerun_Pkt.HDHOMERUN_DEVICE_TYPE_TUNER, HDHomerun_Pkt.HDHOMERUN_DEVICE_ID_WILDCARD, result_list, 64);
if (count < 0) {
System.out.println("error sending discover request\n");
return -1;
}
if (count == 0) {
System.out.println("no devices found\n");
return 0;
}
int index;
for (index = 0; index < count; index++) {
hdhomerun_discover_device_t result = result_list[index];
System.out.println(String.format("hdhomerun device %08X found at %d.%d.%d.%d\n",
result.device_id,
(result.ip_addr >> 24) & 0x0FF, (result.ip_addr >> 16) & 0x0FF,
(result.ip_addr >> 8) & 0x0FF, (result.ip_addr >> 0) & 0x0FF
));
}
return count;
}
static int cmd_get(final String item)
{
StringBuilder ret_value = new StringBuilder();
StringBuilder ret_error = new StringBuilder();
if (hd.get_var(item, ret_value, ret_error) < 0) {
System.out.println("communication error sending request to hdhomerun device\n");
return -1;
}
if (ret_error.length() > 0) {
System.out.println(String.format("%s\n", new String(ret_error)));
return 0;
}
System.out.println(String.format("%s\n", new String(ret_value)));
return 1;
}
static int cmd_set_internal(final String item, final String value)
{
StringBuilder ret_error = new StringBuilder();
if (hd.set_var(item, value, null, ret_error) < 0) {
System.out.println("communication error sending request to hdhomerun device\n");
return -1;
}
if (ret_error.length() > 0) {
System.out.println(String.format("%s\n", new String(ret_error)));
return 0;
}
return 1;
}
static int cmd_set(final String item, final String value)
{
if (value.compareTo("-") == 0) {
String buffer = new String();
while (true) {
byte[] b = new byte[1024];
int size = 0;
try {
size = System.in.read(b);
} catch (IOException e) {
break;
}
buffer += new String(b);
if (size < 1024) {
break;
}
}
int ret = cmd_set_internal(item, buffer);
return ret;
}
return cmd_set_internal(item, value);
}
static volatile boolean sigabort_flag = false;
synchronized static boolean isTerminated() {
return sigabort_flag;
}
synchronized static void sigTerm()
{
sigabort_flag = true;
}
private static void register_signal_handlers()
{
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
sigTerm();
}
});
}
private static void writeToFileAndScreen(FileOutputStream fp, String str) {
System.out.print(str);
if(fp != null) {
try {
fp.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
static int cmd_scan(final String tuner_str, final String filename)
{
if (hd.set_tuner_from_str(tuner_str) <= 0) {
System.out.println("invalid tuner number\n");
return -1;
}
StringBuilder ret_error = new StringBuilder();
if (hd.tuner_lockkey_request(ret_error) <= 0) {
System.out.println("failed to lock tuner\n");
if (ret_error.length() > 0) {
System.out.println(String.format("%s\n", new String(ret_error)));
}
return -1;
}
hd.set_tuner_target("none");
StringBuilder channelmap = new StringBuilder();
if (hd.get_tuner_channelmap(channelmap) <= 0) {
System.out.println("failed to query channelmap from device\n");
return -1;
}
String channelmap_scan_group = HDHomerun_Channels.hdhomerun_channelmap_get_channelmap_scan_group(new String(channelmap));
if (null == channelmap_scan_group || channelmap_scan_group.length() == 0) {
System.out.println(String.format("unknown channelmap '%s'\n", new String(channelmap)));
return -1;
}
if (hd.channelscan_init(channelmap_scan_group) <= 0) {
System.out.println("failed to initialize channel scan\n");
return -1;
}
FileOutputStream fp = null;
if (filename != null && filename.length() > 0) {
try {
fp = new FileOutputStream(filename);
}
catch (IOException e) {
System.out.println(String.format("unable to create file: %s\n", filename));
return -1;
}
}
register_signal_handlers();
int ret = 0;
while (!isTerminated()) { //!sigabort_flag) {
hdhomerun_channelscan_result_t result = new hdhomerun_channelscan_result_t();
ret = hd.channelscan_advance(result);
if (ret <= 0) {
break;
}
writeToFileAndScreen(fp, String.format("SCANNING: %d (%s)\n", result.frequency, result.channel_str
));
ret = hd.channelscan_detect(result);
if (ret < 0) {
break;
}
if (ret == 0) {
continue;
}
writeToFileAndScreen(fp, String.format("LOCK: %s (ss=%d snq=%d seq=%d)\n",
result.status.lock_str, result.status.signal_strength,
result.status.signal_to_noise_quality, result.status.symbol_error_quality
));
if (result.transport_stream_id_detected) {
writeToFileAndScreen(fp, String.format("TSID: 0x%04X\n", result.transport_stream_id));
}
int i;
for (i = 0; i < result.program_count; i++) {
hdhomerun_channelscan_program_t program = result.programs[i];
writeToFileAndScreen(fp, String.format("PROGRAM %s\n", program.program_str));
}
}
hd.tuner_lockkey_release();
if (fp != null) {
try {
fp.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ret < 0) {
System.out.println("communication error sending request to hdhomerun device\n");
}
return ret;
}
static void cmd_save_print_stats()
{
hdhomerun_video_stats_t stats = new hdhomerun_video_stats_t();
hd.get_video_stats(stats);
System.out.println(String.format("%d packets received, %d overflow errors, %d network errors, %d transport errors, %d sequence errors\n",
stats.packet_count,
stats.overflow_error_count,
stats.network_error_count,
stats.transport_error_count,
stats.sequence_error_count
));
}
static int cmd_save(final String tuner_str, final String filename)
{
if (hd.set_tuner_from_str(tuner_str) <= 0) {
System.out.println("invalid tuner number\n");
return -1;
}
boolean printToConsole = false;
FileOutputStream fp = null;
if (filename.compareTo("null") == 0) {
fp = null;
} else if (filename.compareTo("-") == 0) {
printToConsole = true;
} else {
try {
fp = new FileOutputStream(filename);
} catch (FileNotFoundException e) {
System.out.println(String.format("unable to create file %s\n", filename));
return -1;
}
}
int ret = hd.stream_start();
if (ret <= 0) {
System.out.println("unable to start stream " + ret);
if (fp != null) {
try {
fp.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return ret;
}
//register_signal_handlers(sigabort_handler, sigabort_handler, siginfo_handler);
hdhomerun_video_stats_t stats_old = new hdhomerun_video_stats_t();
hdhomerun_video_stats_t stats_cur = new hdhomerun_video_stats_t();
hd.get_video_stats(stats_old);
long next_progress = HDHomerun_OS.getcurrenttime() + 1000;
while (isTerminated()) { //!sigabort_flag) {
long loop_start_time = HDHomerun_OS.getcurrenttime();
/*if (siginfo_flag) {
System.out.println("\n");
cmd_save_print_stats();
siginfo_flag = false;
}*/
int[] actual_size = new int[1];
byte[] ptr = hd.stream_recv(HDHomerun_Video.VIDEO_DATA_BUFFER_SIZE_1S, actual_size);
if (null == ptr) {
HDHomerun_OS.msleep_approx(64);
continue;
}
if (fp != null) {
try {
fp.write(ptr, 0, actual_size[0]);
}
catch(IOException e)
{
System.out.println("error writing output\n");
return -1;
}
}
else if(printToConsole)
System.out.println(String.format("Bytes Received : %d", actual_size[0]));
if (loop_start_time >= next_progress) {
next_progress += 1000;
if (loop_start_time >= next_progress) {
next_progress = loop_start_time + 1000;
}
/* Video stats. */
hd.get_video_stats(stats_cur);
if (stats_cur.overflow_error_count > stats_old.overflow_error_count) {
System.out.println("o");
} else if (stats_cur.network_error_count > stats_old.network_error_count) {
System.out.println("n");
} else if (stats_cur.transport_error_count > stats_old.transport_error_count) {
System.out.println("t");
} else if (stats_cur.sequence_error_count > stats_old.sequence_error_count) {
System.out.println("s");
} else {
System.out.println(".");
}
stats_old = stats_cur;
}
long delay = 64 - (HDHomerun_OS.getcurrenttime() - loop_start_time);
if (delay <= 0) {
continue;
}
HDHomerun_OS.msleep_approx(delay);
}
if (fp != null) {
try {
fp.close();
} catch (IOException e) {
e.printStackTrace();
}
}
hd.stream_stop();
System.out.println("\n");
System.out.println("-- Video statistics --\n");
cmd_save_print_stats();
return 0;
}
static int cmd_execute()
{
StringBuilder ret_value = new StringBuilder();
StringBuilder ret_error = new StringBuilder();
if (hd.get_var("/sys/boot", ret_value, ret_error) < 0) {
System.out.println("communication error sending request to hdhomerun device\n");
return -1;
}
if (ret_error.length() > 0) {
System.out.println(String.format("%s\n", ret_error));
return 0;
}
String currStr = new String(ret_value);
int endIndex = currStr.length();
while (true) {
int eol_r = currStr.indexOf('\r');
if (-1 == eol_r) {
eol_r = endIndex;
}
int eol_n = currStr.indexOf('\n');
if (-1 == eol_n) {
eol_n = endIndex;
}
int eol = eol_r;
if (eol_n < eol) {
eol = eol_r;
}
int sep = currStr.indexOf(' ');
if (-1 == sep || sep > eol) {
if(eol == endIndex)
break;
currStr = currStr.substring(eol + 1);
endIndex = currStr.length();
continue;
}
String item = currStr.substring(0, sep);
String value = currStr.substring(sep+1, (eol - (sep+1)));
System.out.println(String.format("set %s \"%s\"\n", item, value));
cmd_set_internal(item, value);
if(eol == endIndex)
break;
currStr = currStr.substring(eol + 1);
endIndex = currStr.length();
}
return 1;
}
static int main_cmd(String[] argc)
{
if (argc.length < 1) {
return help();
}
String cmd = argc[0];
argc = removeFirstArg(argc);
if (contains(cmd, "key")) {
if (argc.length < 2) {
return help();
}
Scanner scn = new Scanner(cmd);
int lockkey = scn.nextInt();
hd.tuner_lockkey_use_value(lockkey);
cmd = argc[0];
argc = removeFirstArg(argc);
}
if (contains(cmd, "get")) {
if (argc.length < 1) {
return help();
}
return cmd_get(argc[0]);
}
if (contains(cmd, "set")) {
if (argc.length < 2) {
return help();
}
return cmd_set(argc[0], argc[1]);
}
if (contains(cmd, "scan")) {
if (argc.length < 1) {
return help();
}
if (argc.length < 2) {
return cmd_scan(argc[0], null);
} else {
return cmd_scan(argc[0], argc[1]);
}
}
if (contains(cmd, "save")) {
if (argc.length < 2) {
return help();
}
return cmd_save(argc[0], argc[1]);
}
if (contains(cmd, "execute")) {
return cmd_execute();
}
return help();
}
private static String[] removeFirstArg(String[] inArg) {
String[] args = new String[inArg.length-1];
for(int i = 0; i < args.length; ++i)
args[i] = inArg[1+i];
return args;
}
static int main_internal(String[] args)
{
//extract_appname(args[0]);
//args = removeFirstArg(args);
if (args.length == 0) {
return help();
}
final String id_str = args[0];
args = removeFirstArg(args);
if (contains(id_str, "help")) {
return help();
}
//dbg = new HDHomerun_Debug();
if (contains(id_str, "discover")) {
if (args.length < 1) {
return discover_print(null);
} else {
return discover_print(args[0]);
}
}
/* Device object. */
try {
hd = new HDHomerun_Device(id_str, dbg);
} catch (Exception e) {
System.out.println(String.format("invalid device id: %s\n", id_str));
return -1;
}
if (null == hd) {
System.out.println(String.format("invalid device id: %s\n", id_str));
return -1;
}
/* Device ID check. */
int device_id_requested = hd.get_device_id_requested();
if (!HDHomerun_Discover.hdhomerun_discover_validate_device_id(device_id_requested)) {
System.out.println(String.format("invalid device id: %08X\n", device_id_requested));
}
/* Connect to device and check model. */
final String model = hd.get_model_str();
if (null == model || model.length() == 0) {
System.out.println("unable to connect to device\n");
hd.destroy();
return -1;
}
/* Command. */
int ret = main_cmd(args);
/* Cleanup. */
hd.destroy();
/* Complete. */
return ret;
}
public static void main(String[] args)
{
int ret = main_internal(args);
if (ret >= 0)
System.out.println("\nSuccess\n");
else
System.out.println("\nFail\n");
return;
}
}