package com.silicondust.libhdhomerun; import java.util.NoSuchElementException; import java.util.Scanner; import com.silicondust.libhdhomerun.HDHomerun_Channels.hdhomerun_channel_entry_t; import com.silicondust.libhdhomerun.HDHomerun_ChannelList; import com.silicondust.libhdhomerun.HDHomerun_Types.hdhomerun_channelscan_program_t; import com.silicondust.libhdhomerun.HDHomerun_Types.hdhomerun_channelscan_result_t; public final class HDHomerun_ChannelScan { public static final int HDHOMERUN_CHANNELSCAN_PROGRAM_NORMAL = 0; public static final int HDHOMERUN_CHANNELSCAN_PROGRAM_NODATA = 1; public static final int HDHOMERUN_CHANNELSCAN_PROGRAM_CONTROL = 2; public static final int HDHOMERUN_CHANNELSCAN_PROGRAM_ENCRYPTED = 3; private HDHomerun_Device mDevice = null; private long mScanned_channels; // uint32_t private HDHomerun_ChannelList mChannel_list = null; private hdhomerun_channel_entry_t mNext_channel = new hdhomerun_channel_entry_t(); public HDHomerun_ChannelScan(HDHomerun_Device hd, final String channelmap) throws Exception { mChannel_list = new HDHomerun_ChannelList(channelmap); mDevice = hd; if (mChannel_list == null) { throw new Exception(); } mNext_channel = mChannel_list.tail; } public int advance(hdhomerun_channelscan_result_t result) { result.clean(); hdhomerun_channel_entry_t entry = mNext_channel; if (entry == null) { return 0; } /* Combine channels with same frequency. */ result.frequency = entry.frequency; result.channel_str = entry.name; while (true) { entry = entry.prev; if (entry == null) { mNext_channel = null; break; } if (entry.frequency != result.frequency) { mNext_channel = entry; break; } result.channel_str += ", " + entry.name; } return 1; } public int detect(hdhomerun_channelscan_result_t result) { mScanned_channels++; /* Find lock. */ int ret = find_lock(result.frequency, result); if (ret <= 0) { return ret; } if (!result.status.lock_supported) { return 1; } /* Detect programs. */ result.program_count = 0; long timeout; // uint64_t if (mDevice.get_model_str().contains("atsc")) { timeout = HDHomerun_OS.getcurrenttime() + 4000; } else { timeout = HDHomerun_OS.getcurrenttime() + 10000; } long complete_time = HDHomerun_OS.getcurrenttime() + 1000; // uint64_t while (true) { boolean changed[] = new boolean[1]; boolean incomplete[] = new boolean [1]; ret = detect_programs(result, changed, incomplete); if (ret <= 0) { return ret; } if (changed[0]) { complete_time = HDHomerun_OS.getcurrenttime() + 1000; } if (!incomplete[0] && (HDHomerun_OS.getcurrenttime() >= complete_time)) { break; } if (HDHomerun_OS.getcurrenttime() >= timeout) { break; } HDHomerun_OS.msleep_approx(250); } /* Lock => skip overlapping channels. */ long max_next_frequency = result.frequency - 5500000; // uint32_t while (true) { if (mNext_channel == null) { break; } if (mNext_channel.frequency <= max_next_frequency) { break; } mNext_channel = mNext_channel.prev; } /* Success. */ return 1; } public byte get_progress() { // uint8_t hdhomerun_channel_entry_t entry = mNext_channel; if (entry == null) { return 100; } long channels_remaining = 1; long frequency = entry.frequency; while (true) { entry = entry.prev; if (entry == null) { break; } if (entry.frequency != frequency) { channels_remaining++; frequency = entry.frequency; } } return (byte) ((mScanned_channels * 100) / (mScanned_channels + channels_remaining)); } private int find_lock(long frequency, hdhomerun_channelscan_result_t result) { // uint32_t /* Set channel. */ String channel_str = String.format("auto:%d", frequency); int ret = mDevice.set_tuner_channel(channel_str); if (ret <= 0) { return ret; } /* Wait for lock. */ ret = mDevice.wait_for_lock(result.status); if (ret <= 0) { return ret; } if (!result.status.lock_supported) { return 1; } /* Wait for symbol quality = 100%. */ long timeout = HDHomerun_OS.getcurrenttime() + 5000; while (true) { ret = mDevice.get_tuner_status(null, result.status); if (ret <= 0) { return ret; } if (result.status.symbol_error_quality == 100) { return 1; } if (HDHomerun_OS.getcurrenttime() >= timeout) { return 1; } HDHomerun_OS.msleep_approx(250); } } private int detect_programs(hdhomerun_channelscan_result_t result, boolean[] pchanged, boolean[] pincomplete) { pchanged[0] = false; pincomplete[0] = false; StringBuilder streaminfo = new StringBuilder(); int ret = mDevice.get_tuner_streaminfo(streaminfo); if (ret <= 0) { return ret; } String next_line = streaminfo.toString(); int program_count = 0; while (true) { String line = next_line; int index = line.indexOf('\n'); if (index == -1) { break; } next_line = line.substring(index + 1); line = line.substring(0, index); if(line.startsWith("tsid=0x")) { try { line = line.substring(7); if(line != null && line.length() > 0) { Scanner scn = new Scanner(line); result.transport_stream_id = scn.nextInt(16); result.transport_stream_id_detected = true; continue; } } catch (NoSuchElementException e) { } } Scanner scn = new Scanner(line); if (program_count >= HDHomerun_Types.HDHOMERUN_CHANNELSCAN_MAX_PROGRAM_COUNT) { continue; } hdhomerun_channelscan_program_t program = new hdhomerun_channelscan_program_t(); program.program_str = line; // %u: %u or %u: %u.%u try { scn.useDelimiter(":"); program.program_number = scn.nextInt(); boolean hasMinor = line.contains("."); if(hasMinor) { int colonNxt = line.indexOf(':') + 2; int decimal = line.indexOf('.'); Scanner major = new Scanner(line.substring(colonNxt, decimal)); program.virtual_major = major.nextInt(); int nameStart = line.indexOf(' ', ++decimal); Scanner minor = new Scanner(line.substring(decimal, nameStart)); program.virtual_minor = minor.nextInt(); } else { scn.useDelimiter(" "); scn.next(); program.virtual_major = scn.nextInt(); } } catch (NoSuchElementException e) { continue; } channelscan_extract_name(program, line); if (line.contains("(control)")) { program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_CONTROL; } else if (line.contains("(encrypted)")) { program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_ENCRYPTED; } else if (line.contains("(no data)")) { program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_NODATA; pincomplete[0] = true; } else { program.type = HDHOMERUN_CHANNELSCAN_PROGRAM_NORMAL; if ((program.virtual_major == 0) || (program.name.length() == 0)) { pincomplete[0] = true; } } if(result.programs[program_count] == null) result.programs[program_count] = program; else if (!result.programs[program_count].compare(program)) { result.programs[program_count] = new hdhomerun_channelscan_program_t(program); pchanged[0] = true; } program_count++; } if (program_count == 0) { pincomplete[0] = true; } if (result.program_count != program_count) { result.program_count = program_count; pchanged[0] = true; } return 1; } private static void channelscan_extract_name(hdhomerun_channelscan_program_t program, final String line) { /* Find start of name. */ int index = line.indexOf(' '); if (index == -1) { return; } index = line.indexOf(' ', ++index); if (index == -1) { return; } ++index; /* Find end of name. */ int endIndex = line.indexOf("(", index); if (-1 == endIndex) { endIndex = line.length(); } if (endIndex <= index) { return; } /* Extract name. */ program.name = line.substring(index, endIndex); } }