def _h777_enter_programming_mode(radio): serial = radio.pipe try: serial.write("\x02") time.sleep(0.1) serial.write("PROGRAM") ack = serial.read(1) except: raise errors.RadioError("Error communicating with radio") if not ack: raise errors.RadioError("No response from radio") elif ack != CMD_ACK: raise errors.RadioError("Radio refused to enter programming mode") try: serial.write("\x02") ident = serial.read(8) except: raise errors.RadioError("Error communicating with radio") if not ident.startswith("P3107"): print util.hexprint(ident) raise errors.RadioError("Radio returned unknown identification string") try: serial.write(CMD_ACK) ack = serial.read(1) except: raise errors.RadioError("Error communicating with radio") if ack != CMD_ACK: raise errors.RadioError("Radio refused to enter programming mode")
def do_download(radio, start, end, blocksize): """Initiate a download of @radio between @start and @end""" image = "" for i in range(start, end, blocksize): cmd = struct.pack(">cHb", "R", i, blocksize) if os.getenv("CHIRP_DEBUG"): print util.hexprint(cmd) radio.pipe.write(cmd) length = len(cmd) + blocksize resp = radio.pipe.read(length) if len(resp) != (len(cmd) + blocksize): print util.hexprint(resp) raise Exception("Failed to read full block (%i!=%i)" % \ (len(resp), len(cmd) + blocksize)) radio.pipe.write("\x06") radio.pipe.read(1) image += resp[4:] if radio.status_fn: status = chirp_common.Status() status.cur = i status.max = end status.msg = "Cloning from radio" radio.status_fn(status) return memmap.MemoryMap(image)
def _do_ident(radio, magic): serial = radio.pipe serial.setTimeout(1) print "Sending Magic: %s" % util.hexprint(magic) for byte in magic: serial.write(byte) time.sleep(0.01) ack = serial.read(1) if ack != "\x06": if ack: print repr(ack) raise errors.RadioError("Radio did not respond") serial.write("\x02") ident = serial.read(8) print "Ident:\n%s" % util.hexprint(ident) serial.write("\x06") ack = serial.read(1) if ack != "\x06": raise errors.RadioError("Radio refused clone") return ident
def do_download(radio): print "download" _h777_enter_programming_mode(radio) data = "" status = chirp_common.Status() status.msg = "Cloning from radio" status.cur = 0 status.max = radio._memsize for addr in range(0, radio._memsize, BLOCK_SIZE): status.cur = addr + BLOCK_SIZE radio.status_fn(status) block = _h777_read_block(radio, addr, BLOCK_SIZE) data += block if DEBUG: print "Address: %04x" % addr print util.hexprint(block) _h777_exit_programming_mode(radio) return memmap.MemoryMap(data)
def tyt_uvf8d_upload(radio): """Upload to TYT TH-UVF8D""" data = uvf8d_identify(radio) radio.pipe.setTimeout(1) if data != radio._mmap[:32]: raise errors.RadioError("Model mis-match: \n%s\n%s" % (util.hexprint(data), util.hexprint(radio._mmap[:32]))) for i in range(0, 0x4000, 0x20): addr = i + 0x20 msg = struct.pack(">cHb", "W", i, 0x20) msg += radio._mmap[addr:(addr + 0x20)] radio.pipe.write(msg) ack = radio.pipe.read(1) if ack != "A": raise errors.RadioError("Radio did not ack block %i" % i) if radio.status_fn: status = chirp_common.Status() status.cur = i status.max = 0x4000 status.msg = "Cloning to radio" radio.status_fn(status) # End of clone? radio.pipe.write("ENDW") # Checksum? final_data = radio.pipe.read(3)
def _send(radio, cmd, addr, length, data=None): frame = struct.pack(">cHb", cmd, addr, length) if data: frame += data frame += chr(_checksum(frame[1:])) frame += "\x06" _echo_write(radio, frame) LOG.debug("Sent:\n%s" % util.hexprint(frame)) if data: result = radio.pipe.read(1) if result != "\x06": LOG.debug( "Ack was: %s" % repr(result)) raise errors.RadioError("Radio did not accept block at %04x" % addr) return result = _read(radio, length + 6) LOG.debug("Got:\n%s" % util.hexprint(result)) header = result[0:4] data = result[4:-2] ack = result[-1] if ack != "\x06": LOG.debug("Ack was: %s" % repr(ack)) raise errors.RadioError("Radio NAK'd block at %04x" % addr) _cmd, _addr, _length = struct.unpack(">cHb", header) if _addr != addr or _length != _length: LOG.debug( "Expected/Received:") LOG.debug(" Length: %02x/%02x" % (length, _length)) LOG.debug( " Addr: %04x/%04x" % (addr, _addr)) raise errors.RadioError("Radio send unexpected block") cs = _checksum(result[1:-2]) if cs != ord(result[-2]): LOG.debug( "Calculated: %02x" % cs) LOG.debug( "Actual: %02x" % ord(result[-2])) raise errors.RadioError("Block at 0x%04x failed checksum" % addr) return data
def _download(radio, memsize=0x10000, blocksize=0x80): """Download from TYT TH-9800""" data = _identify(radio) LOG.info("ident:", util.hexprint(data)) offset = 0x100 for addr in range(offset, memsize, blocksize): msg = struct.pack(">cHB", "R", addr, blocksize) radio.pipe.write(msg) block = radio.pipe.read(blocksize + 4) if len(block) != (blocksize + 4): LOG.debug(util.hexprint(block)) raise errors.RadioError("Radio sent a short block") radio.pipe.write("A") ack = radio.pipe.read(1) if ack != "A": LOG.debug(util.hexprint(ack)) raise errors.RadioError("Radio NAKed block") data += block[4:] if radio.status_fn: status = chirp_common.Status() status.cur = addr status.max = memsize status.msg = "Cloning from radio" radio.status_fn(status) radio.pipe.write("ENDR") return memmap.MemoryMap(data)
def do_download(radio): do_ident(radio) data = "KT511 Radio Program data v1.08\x00\x00" data += ("\x00" * 16) firstack = None for i in range(0, 0x1000, 16): frame = struct.pack(">cHB", "R", i, 16) radio.pipe.write(frame) result = radio.pipe.read(20) if frame[1:4] != result[1:4]: LOG.debug(util.hexprint(result)) raise errors.RadioError("Invalid response for address 0x%04x" % i) radio.pipe.write("\x06") ack = radio.pipe.read(1) if not firstack: firstack = ack else: if not ack == firstack: LOG.debug("first ack: %s ack received: %s", util.hexprint(firstack), util.hexprint(ack)) raise errors.RadioError("Unexpected response") data += result[4:] do_status(radio, "from", i) return memmap.MemoryMap(data)
def download(radio): data = "" radio.pipe.setTimeout(1) for block in radio._block_lengths: print "Doing block %i" % block if block > 112: step = 16 else: step = block for i in range(0, block, step): #data += read_exact(radio.pipe, step) chunk = radio.pipe.read(step*2) print "Length of chunk: %i" % len(chunk) data += chunk print "Reading %i" % i time.sleep(0.1) send(radio.pipe, ACK) if radio.status_fn: status = chirp_common.Status() status.max = radio._memsize status.cur = len(data) status.msg = "Cloning from radio" radio.status_fn(status) r = radio.pipe.read(100) send(radio.pipe, ACK) print "R: %i" % len(r) print util.hexprint(r) print "Got: %i Expecting %i" % (len(data), radio._memsize) return memmap.MemoryMap(data)
def _do_ident(radio): """Put the radio in PROGRAM mode & identify it""" # set the serial discipline radio.pipe.baudrate = 115200 radio.pipe.parity = "N" radio.pipe.timeout = STIMEOUT # flush input buffer _clean_buffer(radio) magic = "V66LINK" _rawsend(radio, magic) # Ok, get the ident string ident = _rawrecv(radio, 9) # check if ident is OK if ident != radio.IDENT: # bad ident msg = "Incorrect model ID, got this:" msg += util.hexprint(ident) LOG.debug(msg) raise errors.RadioError("Radio identification failed.") # DEBUG LOG.info("Positive ident, got this:") LOG.debug(util.hexprint(ident)) return True
def _download_chunk(self, addr): if addr % 16: raise Exception("Addr 0x%04x not on 16-byte boundary" % addr) cmd = "AL~F%04XR\r\n" % addr self._send(cmd) resp = self._read(RLENGTH).strip() if len(resp) == 0: raise errors.RadioError("No response from radio") if ":" not in resp: raise errors.RadioError("Unexpected response from radio") addr, _data = resp.split(":", 1) data = "" for i in range(0, len(_data), 2): data += chr(int(_data[i:i+2], 16)) if len(data) != 16: print "Response was:" print "|%s|" print "Which I converted to:" print util.hexprint(data) raise Exception("Radio returned less than 16 bytes") return data
def _write(self, addr, block): # write a single block msg = struct.pack(">4sHH", "WRIE", addr, len(block)) + block LOG.debug("sending " + util.hexprint(msg)) self.pipe.write(msg) data = self.pipe.read(1) LOG.debug("received " + util.hexprint(data)) if ord(data) != CMD_ACK: raise errors.RadioError( "Radio refused to accept block 0x%04x" % addr)
def _upload(radio, memsize=0xF400, blocksize=0x80): """Upload to TYT TH-9800""" data = _identify(radio) radio.pipe.timeout = 1 if data != radio._mmap[:radio._mmap_offset]: raise errors.RadioError( "Model mis-match: \n%s\n%s" % (util.hexprint(data), util.hexprint(radio._mmap[:radio._mmap_offset]))) # in the factory software they update the last program date when # they upload, So let's do the same today = date.today() y = today.year m = today.month d = today.day _info = radio._memobj.info ly = _info.prog_yr lm = _info.prog_mon ld = _info.prog_day LOG.debug("Updating last program date:%d/%d/%d" % (lm, ld, ly)) LOG.debug(" to today:%d/%d/%d" % (m, d, y)) _info.prog_yr = y _info.prog_mon = m _info.prog_day = d offset = 0x0100 for addr in range(offset, memsize, blocksize): mapaddr = addr + radio._mmap_offset - offset LOG.debug("addr: 0x%04X, mmapaddr: 0x%04X" % (addr, mapaddr)) msg = struct.pack(">cHB", "W", addr, blocksize) msg += radio._mmap[mapaddr:(mapaddr + blocksize)] LOG.debug(util.hexprint(msg)) radio.pipe.write(msg) ack = radio.pipe.read(1) if ack != "A": LOG.debug(util.hexprint(ack)) raise errors.RadioError("Radio did not ack block 0x%04X" % addr) if radio.status_fn: status = chirp_common.Status() status.cur = addr status.max = memsize status.msg = "Cloning to radio" radio.status_fn(status) # End of clone radio.pipe.write("ENDW") # Checksum? final_data = radio.pipe.read(3) LOG.debug("final:", util.hexprint(final_data))
def _read(self, addr, blocksize): # read a single block msg = struct.pack(">4sHH", "READ", addr, blocksize) LOG.debug("sending " + util.hexprint(msg)) self.pipe.write(msg) block = self.pipe.read(blocksize) LOG.debug("received " + util.hexprint(block)) if len(block) != blocksize: raise Exception("Unable to read block at addr %04X expected" " %i got %i bytes" % (addr, blocksize, len(block))) return block
def _t18_enter_programming_mode(radio): serial = radio.pipe try: serial.write("\x02") time.sleep(0.1) serial.write("1ROGRAM") ack = serial.read(1) except: raise errors.RadioError("Error communicating with radio") if not ack: raise errors.RadioError("No response from radio") elif ack != CMD_ACK: raise errors.RadioError("Radio refused to enter programming mode") try: serial.write("\x02") ident = serial.read(8) except: raise errors.RadioError("Error communicating with radio") if not ident.startswith("SMP558"): LOG.debug(util.hexprint(ident)) raise errors.RadioError("Radio returned unknown identification string") try: serial.write(CMD_ACK) ack = serial.read(1) except: raise errors.RadioError("Error communicating with radio") if ack != CMD_ACK: raise errors.RadioError("Radio refused to enter programming mode") try: serial.write("\x05") response = serial.read(6) except: raise errors.RadioError("Error communicating with radio") if not response == ("\xFF" * 6): LOG.debug(util.hexprint(response)) raise errors.RadioError("Radio returned unexpected response") try: serial.write(CMD_ACK) ack = serial.read(1) except: raise errors.RadioError("Error communicating with radio") if ack != CMD_ACK: raise errors.RadioError("Radio refused to enter programming mode")
def _ident(radio): radio.pipe.timeout = 1 _echo_write(radio, "PROGRAM") response = radio.pipe.read(3) if response != "QX\x06": LOG.debug("Response was:\n%s" % util.hexprint(response)) raise errors.RadioError("Radio did not respond. Check connection.") _echo_write(radio, "\x02") response = radio.pipe.read(16) LOG.debug(util.hexprint(response)) if radio._file_ident not in response: LOG.debug("Response was:\n%s" % util.hexprint(response)) raise errors.RadioError("Unsupported model")
def _ident(radio): radio.pipe.timeout = 1 _echo_write(radio, "PROGRAM") response = radio.pipe.read(3) if response != "QX\x06": LOG.debug("Response was:\n%s" % util.hexprint(response)) raise errors.RadioError("Unsupported model") _echo_write(radio, "\x02") response = radio.pipe.read(16) LOG.debug(util.hexprint(response)) if response[1:8] not in valid_model: LOG.debug("Response was:\n%s" % util.hexprint(response)) raise errors.RadioError("Unsupported model")
def read_exact(s, count): data = "" i = 0 while len(data) < count: if i == 3: print util.hexprint(data) raise errors.RadioError("Failed to read %i (%i) from radio" % (count, len(data))) elif i > 0: print "Retry %i" % i data += s.read(count - len(data)) i += 1 return data
def _ident(radio): radio.pipe.timeout = 1 _echo_write(radio,"PROGRAM") response = radio.pipe.read(3) if response != "QX\06": LOG.debug( "Response was :\n%s" % util.hexprint(response)) raise errors.RadioError("Unsupported model") _echo_write(radio, "\x02") response = radio.pipe.read(16) LOG.debug(util.hexprint(response)) if response[1:8] != "TH-9000": LOG.error( "Looking for:\n%s" % util.hexprint("TH-9000")) LOG.error( "Response was:\n%s" % util.hexprint(response)) raise errors.RadioError("Unsupported model")
def _download(radio): """Get the memory map""" # put radio in program mode ident = _ident_radio(radio) # identify radio radio_ident = _get_radio_firmware_version(radio) LOG.info("Radio firmware version:") LOG.debug(util.hexprint(radio_ident)) # UI progress status = chirp_common.Status() status.cur = 0 status.max = radio._mem_size / radio._recv_block_size status.msg = "Cloning from radio..." radio.status_fn(status) data = "" for addr in range(0, radio._mem_size, radio._recv_block_size): frame = _make_frame("S", addr, radio._recv_block_size) # DEBUG LOG.info("Request sent:") LOG.debug(util.hexprint(frame)) # sending the read request _rawsend(radio, frame) if radio._ack_block: ack = _rawrecv(radio, 1) if ack != "\x06": raise errors.RadioError( "Radio refused to send block 0x%04x" % addr) # now we read d = _recv(radio, addr, radio._recv_block_size) _rawsend(radio, "\x06") time.sleep(0.05) # aggregate the data data += d # UI Update status.cur = addr / radio._recv_block_size status.msg = "Cloning from radio..." radio.status_fn(status) data += ident return data
def _clone_from_radio(radio): md = get_model_data(radio.pipe) if md[0:4] != radio.get_model(): print "This model: %s" % util.hexprint(md[0:4]) print "Supp model: %s" % util.hexprint(radio.get_model()) raise errors.RadioError("I can't talk to this model") if radio.is_hispeed(): start_hispeed_clone(radio, CMD_CLONE_OUT) else: send_clone_frame(radio.pipe, CMD_CLONE_OUT, radio.get_model(), raw=True) print "Sent clone frame" stream = RadioStream(radio.pipe) addr = 0 _mmap = memmap.MemoryMap(chr(0x00) * radio.get_memsize()) last_size = 0 while True: frames = stream.get_frames() if not frames: break for frame in frames: if frame.cmd == CMD_CLONE_DAT: src, dst = process_data_frame(frame, _mmap) if last_size != (dst - src): print "ICF Size change from %i to %i at %04x" % (last_size, dst - src, src) last_size = dst - src if addr != src: print "ICF GAP %04x - %04x" % (addr, src) addr = dst elif frame.cmd == CMD_CLONE_END: print "End frame (%i):\n%s" % (len(frame.payload), util.hexprint(frame.payload)) print "Last addr: %04x" % addr if radio.status_fn: status = chirp_common.Status() status.msg = "Cloning from radio" status.max = radio.get_memsize() status.cur = addr radio.status_fn(status) return _mmap
def _download(radio): data = "" for _i in range(0, 10): data = radio.pipe.read(8) if data == IDBLOCK: break if DEBUG: print "Header:\n%s" % util.hexprint(data) if len(data) != 8: raise Exception("Failed to read header") _send(radio.pipe, ACK) data = "" while len(data) < radio._block_sizes[1]: time.sleep(0.1) chunk = radio.pipe.read(38) if DEBUG: print "Got: %i:\n%s" % (len(chunk), util.hexprint(chunk)) if len(chunk) == 8: print "END?" elif len(chunk) != 38: print "Should fail?" break #raise Exception("Failed to get full data block") else: cs = 0 for byte in chunk[:-1]: cs += ord(byte) if ord(chunk[-1]) != (cs & 0xFF): raise Exception("Block failed checksum!") data += chunk[5:-1] _send(radio.pipe, ACK) if radio.status_fn: status = chirp_common.Status() status.max = radio._block_sizes[1] status.cur = len(data) status.msg = "Cloning from radio" radio.status_fn(status) if DEBUG: print "Total: %i" % len(data) return memmap.MemoryMap(data)
def _safe_read(pipe, count): buf = "" first = True for _i in range(0, 60): buf += pipe.read(count - len(buf)) #print "safe_read: %i/%i\n" % (len(buf), count) if buf: if first and buf[0] == chr(CMD_ACK): #print "Chewed an ack" buf = buf[1:] # Chew an echo'd ack if using a 2-pin cable first = False if len(buf) == count: break print util.hexprint(buf) return buf
def _puxing_prep(radio): radio.pipe.write("\x02PROGRA") ack = radio.pipe.read(1) if ack != "\x06": raise Exception("Radio did not ACK first command") radio.pipe.write("M\x02") ident = radio.pipe.read(8) if len(ident) != 8: print util.hexprint(ident) raise Exception("Radio did not send identification") radio.pipe.write("\x06") if radio.pipe.read(1) != "\x06": raise Exception("Radio did not ACK ident")
def send(self, src, dst, serial, willecho=True): """Send the frame over @serial, using @src and @dst addresses""" raw = struct.pack("BBBBBB", 0xFE, 0xFE, src, dst, self._cmd, self._sub) raw += str(self._data) + chr(0xFD) LOG.debug("%02x -> %02x (%i):\n%s" % (src, dst, len(raw), util.hexprint(raw))) serial.write(raw) if willecho: echo = serial.read(len(raw)) if echo != raw and echo: LOG.debug("Echo differed (%i/%i)" % (len(raw), len(echo))) LOG.debug(util.hexprint(raw)) LOG.debug(util.hexprint(echo))
def do_ident(radio): radio.pipe.setTimeout(3) radio.pipe.write("PROGRAM") ack = radio.pipe.read(1) if ack != '\x06': raise errors.RadioError("Radio did not ack programming mode") radio.pipe.write("\x02") ident = radio.pipe.read(8) print util.hexprint(ident) if not ident.startswith('HKT511'): raise errors.RadioError("Unsupported model") radio.pipe.write("\x06") ack = radio.pipe.read(1) if ack != "\x06": raise errors.RadioError("Radio did not ack ident")
def _upload(radio): """Upload procedure""" # put radio in program mode _ident_radio(radio) # identify radio radio_ident = _get_radio_firmware_version(radio) LOG.info("Radio firmware version:") LOG.debug(util.hexprint(radio_ident)) # identify image image_ident = _get_image_firmware_version(radio) LOG.info("Image firmware version:") LOG.debug(util.hexprint(image_ident)) if radio_ident != "0xFF" * 16 and image_ident == radio_ident: _ranges = radio._ranges else: _ranges = [(0x0000, 0x0DF0), (0x0E00, 0x1800)] # UI progress status = chirp_common.Status() status.cur = 0 status.max = radio._mem_size / radio._send_block_size status.msg = "Cloning to radio..." radio.status_fn(status) # the fun start here for start, end in _ranges: for addr in range(start, end, radio._send_block_size): # sending the data data = radio.get_mmap()[addr:addr + radio._send_block_size] frame = _make_frame("X", addr, radio._send_block_size, data) _rawsend(radio, frame) time.sleep(0.05) # receiving the response ack = _rawrecv(radio, 1) if ack != "\x06": msg = "Bad ack writing block 0x%04x" % addr raise errors.RadioError(msg) # UI Update status.cur = addr / radio._send_block_size status.msg = "Cloning to radio..." radio.status_fn(status)
def _finish(radio): endframe = "\x45\x4E\x44" _echo_write(radio, endframe) result = radio.pipe.read(1) if result != "\x06": LOG.debug("Got:\n%s" % util.hexprint(result)) raise errors.RadioError("Radio did not finish cleanly")
def _recv(radio, addr, length=BLOCK_SIZE): """Get data from the radio """ # read 4 bytes of header hdr = _rawrecv(radio, 4) # check for unexpected extra command byte c, a, l = struct.unpack(">BHB", hdr) if hdr[0:2] == "WW" and a != addr: # extra command byte detected # throw away the 1st byte and add the next byte in the buffer hdr = hdr[1:] + _rawrecv(radio, 1) # read 64 bytes (0x40) of data data = _rawrecv(radio, (BLOCK_SIZE)) # DEBUG LOG.info("Response:") LOG.debug(util.hexprint(hdr + data)) c, a, l = struct.unpack(">BHB", hdr) if a != addr or l != length or c != ord("W"): _exit_program_mode(radio) LOG.error("Invalid answer for block 0x%04x:" % addr) LOG.debug("CMD: %s ADDR: %04x SIZE: %02x" % (c, a, l)) raise errors.RadioError("Unknown response from the radio") return data
def do_download(radio): LOG.debug("download") _rt23_enter_programming_mode(radio) data = "" status = chirp_common.Status() status.msg = "Cloning from radio" status.cur = 0 status.max = radio._memsize for addr in range(0, radio._memsize, BLOCK_SIZE): status.cur = addr + BLOCK_SIZE radio.status_fn(status) block = _rt23_read_block(radio, addr, BLOCK_SIZE) if addr == 0 and block.startswith("\xFF" * 6): block = "P31183" + "\xFF" * 10 data += block LOG.debug("Address: %04x" % addr) LOG.debug(util.hexprint(block)) _rt23_exit_programming_mode(radio) return memmap.MemoryMap(data)
def __str__(self): string = "Frame VFO=%i (len = %i)\n" % (self.get_vfo(), len(self.get_payload())) string += util.hexprint(self.get_payload()) string += "\n" return string
def sync_in(self): "Initiate a radio-to-PC clone operation" LOG.debug('Cloning from radio') status = chirp_common.Status() status.msg = 'Cloning from radio' status.cur = 0 status.max = self._memsize self.status_fn(status) self._enter_programming_mode() data = '' for addr in range(0, self._memsize, self.BLOCK_SIZE): status.cur = addr + self.BLOCK_SIZE self.status_fn(status) block = self._read_block(addr, self.BLOCK_SIZE) data += block LOG.debug('Address: %04x', addr) LOG.debug(util.hexprint(block)) self._exit_programming_mode() self._mmap = memmap.MemoryMap(data) self.process_mmap()
def set_memory(self, mem): f = self._get_template_memory() if mem.empty: f.set_location(mem.number) f.make_empty() self._send_frame(f) return #f.set_data(MemoryMap(self.get_raw_memory(mem.number))) #f.initialize() memobj = f.get_obj() memobj.number = mem.number memobj.freq = int(mem.freq) memobj.mode = self._rf.valid_modes.index(mem.mode) if self._rf.has_name: memobj.name = mem.name.ljust(9)[:9] if self._rf.valid_tmodes: memobj.tmode = self._rf.valid_tmodes.index(mem.tmode) if self._rf.valid_duplexes: memobj.duplex = self._rf.valid_duplexes.index(mem.duplex) if self._rf.has_ctone: memobj.ctone = int(mem.ctone * 10) memobj.rtone = int(mem.rtone * 10) print repr(memobj) self._send_frame(f) f = self._recv_frame() print "Result:\n%s" % util.hexprint(f.get_data())
def _download_chunk(self, addr): if addr % 0x40: raise Exception("Addr 0x%04x not on 64-byte boundary" % addr) cmd = "AL~F%05XR\r" % addr self._send(cmd) # Response: "\r\n[ ... data ... ]\r\n # data is encoded in hex, hence we read two chars per byte _data = self._read(2 + 2 * 64 + 2).strip() if len(_data) == 0: raise errors.RadioError("No response from radio") data = "" for i in range(0, len(_data), 2): data += chr(int(_data[i:i + 2], 16)) if len(data) != 64: LOG.debug("Response was:") LOG.debug("|%s|") LOG.debug("Which I converted to:") LOG.debug(util.hexprint(data)) raise Exception("Chunk from radio has wrong size") return data
def _download_chunk(self, addr): if addr % 16: raise Exception("Addr 0x%04x not on 16-byte boundary" % addr) cmd = "AL~F%04XR\r\n" % addr self._send(cmd) resp = self._read(RLENGTH).strip() if len(resp) == 0: raise errors.RadioError("No response from radio") if ":" not in resp: raise errors.RadioError("Unexpected response from radio") addr, _data = resp.split(":", 1) data = "" for i in range(0, len(_data), 2): data += chr(int(_data[i:i + 2], 16)) if len(data) != 16: LOG.debug("Response was:") LOG.debug("|%s|") LOG.debug("Which I converted to:") LOG.debug(util.hexprint(data)) raise Exception("Radio returned less than 16 bytes") return data
def _rt21_enter_programming_mode(radio): serial = radio.pipe try: serial.write("PRMZUNE") ack = serial.read(1) except: raise errors.RadioError("Error communicating with radio") if not ack: raise errors.RadioError("No response from radio") elif ack != CMD_ACK: raise errors.RadioError("Radio refused to enter programming mode") try: serial.write("\x02") ident = serial.read(8) except: raise errors.RadioError("Error communicating with radio") if not ident.startswith("P3207"): LOG.debug(util.hexprint(ident)) raise errors.RadioError("Radio returned unknown identification string") try: serial.write(CMD_ACK) ack = serial.read(1) except: raise errors.RadioError("Error communicating with radio") if ack != CMD_ACK: raise errors.RadioError("Radio refused to enter programming mode")
def SHX8800_prep(radio): """Prepare radio device for transmission""" _rawsend(radio, "PROGROM") _rawsend(radio, "SHX") _rawsend(radio, "U") ack = _rawrecv(radio, 1) if ack != CMD_ACK: raise errors.RadioError("Radio did not ACK first command") _rawsend(radio, "F") ident = _rawrecv(radio, 8) if len(ident) != 8: LOG.debug(util.hexprint(ident)) raise errors.RadioError("Radio did not send identification") LOG.info("Ident: " + util.hexprint(ident))
def _process_frames(self): if not self.data.startswith("\xFE\xFE"): LOG.error("Out of sync with radio:\n%s" % util.hexprint(self.data)) raise errors.InvalidDataError("Out of sync with radio") elif len(self.data) < 5: return [] # Not enough data for a full frame frames = [] while self.data: try: cmd = ord(self.data[4]) except IndexError: break # Out of data try: frame, rest = parse_frame_generic(self.data) if not frame: break elif frame.src == 0xEE and frame.dst == 0xEF: # PC echo, ignore pass else: frames.append(frame) self.data = rest except errors.InvalidDataError, e: LOG.error("Failed to parse frame (cmd=%i): %s" % (cmd, e)) return []
def do_download(radio): LOG.debug("download") _rt22_enter_programming_mode(radio) data = "" status = chirp_common.Status() status.msg = "Cloning from radio" status.cur = 0 status.max = radio._memsize for addr in range(0, radio._memsize, radio._block_size): status.cur = addr + radio._block_size radio.status_fn(status) block = _rt22_read_block(radio, addr, radio._block_size) data += block LOG.debug("Address: %04x" % addr) LOG.debug(util.hexprint(block)) data += radio.MODEL.ljust(8) _rt22_exit_programming_mode(radio) return memmap.MemoryMap(data)
def do_download(radio): LOG.debug("download") _r2_enter_programming_mode(radio) data = "" status = chirp_common.Status() status.msg = "Cloning from radio" status.cur = 0 status.max = radio._memsize for addr in range(0, radio._memsize, radio._block_size): status.cur = addr + radio._block_size radio.status_fn(status) block = _r2_read_block(radio, addr, radio._block_size) data += block LOG.debug("Address: %04x" % addr) LOG.debug(util.hexprint(block)) data += radio.MODEL.ljust(8) _r2_exit_programming_mode(radio) return memmap.MemoryMap(data)
def send(self, src, dst, serial, willecho=True): """Send the frame over @serial, using @src and @dst addresses""" raw = struct.pack("BBBBBB", 0xFE, 0xFE, src, dst, self._cmd, self._sub) raw += str(self._data) + chr(0xFD) if DEBUG: print "%02x -> %02x (%i):\n%s" % (src, dst, len(raw), util.hexprint(raw)) serial.write(raw) if willecho: echo = serial.read(len(raw)) if echo != raw and echo: print "Echo differed (%i/%i)" % (len(raw), len(echo)) print util.hexprint(raw) print util.hexprint(echo)
def do_download(radio): LOG.debug("download") _h777_enter_programming_mode(radio) data = b"" status = chirp_common.Status() status.msg = "Cloning from radio" status.cur = 0 status.max = radio._memsize for addr in range(0, radio._memsize, BLOCK_SIZE): status.cur = addr + BLOCK_SIZE radio.status_fn(status) block = _h777_read_block(radio, addr, BLOCK_SIZE) data += block LOG.debug("Address: %04x" % addr) LOG.debug(util.hexprint(block)) _h777_exit_programming_mode(radio) return memmap.MemoryMapBytes(data)
def do_program(radio): """Feidaxin program mode and identification dance""" # try to get the radio in program mode ack = do_magic(radio) if not ack: erc = "Radio did not accept program mode, " erc += "check your cable and radio; then try again." raise errors.RadioError(erc) # now we request identification send(radio, "M") send(radio, "\x02") ident = raw_recv(radio, 8) ################# WARNING ########################################## # Feidaxin radios has a "send id" procedure in the initial handshake # but it's worthless, once you do a hardware reset the ident area # get all 0xFF. # # Even FDX-288 software appears to match the model by any other # mean, so I detected on a few images that the 3 first bytes are # unique to each radio model, so for now we use that method untill # proven otherwise #################################################################### LOG.debug("Radio's ID string:") LOG.debug(util.hexprint(ident)) # final ACK send(radio, CMD_ACK) check_ack(radio, "Radio refused to enter programming mode")
def set_variant(self): """Select and set the correct variables for the class acording to the correct variant of the radio""" rid = get_radio_id(self._mmap) # indentify the radio variant and set the enviroment to it's values try: self._upper, low, high, self._kind = self.VARIANTS[rid] self._range = [low * 1000000, high * 1000000] # put the VARIANT in the class, clean the model / CHs / Type # in the same layout as the KPG program self._VARIANT = self.MODEL + " [" + str(self._upper) + "CH]: " self._VARIANT += self._kind + ", " self._VARIANT += str(self._range[0] / 1000000) + "-" self._VARIANT += str(self._range[1] / 1000000) + " Mhz" # DEBUG #print self._VARIANT except KeyError: LOG.debug("Wrong Kenwood radio, ID or unknown variant") LOG.debug(util.hexprint(rid)) raise errors.RadioError( "Wrong Kenwood radio, ID or unknown variant, see LOG output.")
def _upload(radio): data = radio.pipe.read(256) # Clear buffer _send(radio.pipe, radio.IDBLOCK) _wait_for_ack(radio.pipe) # write 16 Byte block # If there should be a problem, see remarks in _download(radio) _send( radio.pipe, "\xCC\x77\x01\x00\x0C\x07\x0C\x07" "\x00\x00\x00\x00\x00\x00\x00\x00") _wait_for_ack(radio.pipe) for block_nr in range(NB_OF_BLOCKS): data = radio.get_mmap()[block_nr * BLOCK_LEN:(block_nr + 1) * BLOCK_LEN] LOG.debug("Writing block_nr %i:\n%s", block_nr, util.hexprint(data)) _send(radio.pipe, data) _wait_for_ack(radio.pipe) if radio.status_fn: status = chirp_common.Status() status.max = NB_OF_BLOCKS * BLOCK_LEN status.cur = block_nr * BLOCK_LEN status.msg = "Cloning to radio" radio.status_fn(status) block_nr += 1
def _write_block(self, block_addr, block_size): cmd = struct.pack('>cHb', self.CMD_WRITE, block_addr, block_size) data = self.get_mmap()[block_addr:block_addr + 8] LOG.debug('Writing Data:\n%s%s', util.hexprint(cmd), util.hexprint(data)) try: self._write(cmd + data) if self._read(1) != self.CMD_ACK: raise Exception('No ACK') except Exception: msg = 'Failed to send block to radio at %04x' % block_addr LOG.debug(msg, exc_info=True) raise errors.RadioError(msg)
def do_program(radio): """Feidaxin program mode and identification dance""" # try to get the radio in program mode ack = do_magic(radio) if not ack: erc = "Radio did not accept program mode, " erc += "check your cable and radio; then try again." raise errors.RadioError(erc) # now we request identification send(radio, "M") send(radio, "\x02") ident = raw_recv(radio, 8) # ################ WARNING ########################################## # Feidaxin radios has a "send id" procedure in the initial handshake # but it's worthless, once you do a hardware reset the ident area # get all 0xFF. # # Even FDX-288 software appears to match the model by any other # mean, so I detected on a few images that the 3 first bytes are # unique to each radio model, so for now we use that method untill # proven otherwise # ################################################################### LOG.debug("Radio's ID string:") LOG.debug(util.hexprint(ident)) # final ACK send(radio, CMD_ACK) check_ack(radio, "Radio refused to enter programming mode")
def check_ver(ver_response, allowed_types): ''' Check the returned radio version is one we approve of ''' LOG.debug('ver_response = ') LOG.debug(util.hexprint(ver_response)) resp = bitwise.parse(VER_FORMAT, ver_response) verok = False if resp.hdr == 0x49 and resp.ack == 0x06: model, version = [ cstring_to_py_string(bitwise.get_string(s)).strip() for s in (resp.model, resp.version) ] LOG.debug('radio model: \'%s\' version: \'%s\'' % (model, version)) LOG.debug('allowed_types = %s' % allowed_types) if model in allowed_types: LOG.debug('model in allowed_types') if version in allowed_types[model]: LOG.debug('version in allowed_types[model]') verok = True else: raise errors.RadioError('Failed to parse version response') return verok
def _ip620_enter_programming_mode(self): try: self.pipe.write("iUHOUXUN") self.pipe.write("\x02") time.sleep(0.2) _ack = self.pipe.read(1) except errors.RadioError: raise except Exception as e: raise errors.RadioError("Error communicating with radio: %s" % e) if not _ack: raise errors.RadioError("No response from radio") elif _ack != CMD_ACK: raise errors.RadioError("Radio refused to enter programming mode") try: self.pipe.write("\x02") _ident = self.pipe.read(8) except errors.RadioError: raise except Exception as e: raise errors.RadioError("Error communicating with radio: %s" % e) if not _ident.startswith("\x06\x4B\x47\x36\x37\x01\x56\xF8"): print(util.hexprint(_ident)) raise errors.RadioError("Radio returned unknown identification string") try: self.pipe.write(CMD_ACK) _ack = self.pipe.read(1) except errors.RadioError: raise except Exception as e: raise errors.RadioError("Error communicating with radio: %s" % e) if _ack != CMD_ACK: raise errors.RadioError("Radio refused to enter programming mode")
def _read_block(radio, addr): """Read data block from the radio, addr must be aligned to _recv_block_size """ frame = _make_frame(radio._read_cmd, addr, radio._recv_block_size) # DEBUG LOG.info("Request sent:") LOG.debug(util.hexprint(frame)) # sending the read request _rawsend(radio, frame) if radio._ack_block: ack = _rawrecv(radio, 1) if ack != "\x06": raise errors.RadioError("Radio refused to send block 0x%04x" % addr) # now we read data = _recv(radio, addr, radio._recv_block_size) _rawsend(radio, "\x06") time.sleep(0.05) return data
def _upload(radio): """Upload procedure""" # put radio in program mode _ident_radio(radio) addr = 0x0f80 frame = _make_frame("R", addr, radio._recv_block_size) # DEBUG LOG.info("Request sent:") LOG.debug(util.hexprint(frame)) # sending the read request _rawsend(radio, frame) # now we read d = _recv(radio, addr, radio._recv_block_size) time.sleep(0.05) _rawsend(radio, "\x06") ack = _rawrecv(radio, 1) if ack != "\x06": raise errors.RadioError( "Radio refused to send block 0x%04x" % addr) _ranges = radio._ranges # UI progress status = chirp_common.Status() status.cur = 0 status.max = radio._mem_size / radio._send_block_size status.msg = "Cloning to radio..." radio.status_fn(status) # the fun start here for start, end in _ranges: for addr in range(start, end, radio._send_block_size): # sending the data data = radio.get_mmap()[addr:addr + radio._send_block_size] frame = _make_frame("W", addr, radio._send_block_size, data) _rawsend(radio, frame) #time.sleep(0.05) # receiving the response ack = _rawrecv(radio, 1) if ack != "\x06": msg = "Bad ack writing block 0x%04x" % addr raise errors.RadioError(msg) # UI Update status.cur = addr / radio._send_block_size status.msg = "Cloning to radio..." radio.status_fn(status)
def _firmware_version_from_image(radio): version = _firmware_version_from_data(radio.get_mmap(), radio._fw_ver_file_start, radio._fw_ver_file_stop) if CHIRP_DEBUG: print "_firmware_version_from_image: " + util.hexprint(version) return version
def _rawrecv(radio, amount=0): """Raw read from the radio device""" # var to hold the data to return data = "" try: if amount == 0: data = radio.pipe.read() else: data = radio.pipe.read(amount) # DEBUG if debug is True: LOG.debug("<== (%d) bytes:\n\n%s" % (len(data), util.hexprint(data))) # fail if no data is received if len(data) == 0: raise errors.RadioError("No data received from radio") except: raise errors.RadioError("Error reading data from radio") return data
def set_variant(self): """Select and set the correct variables for the class acording to the correct variant of the radio""" rid = get_radio_id(self._mmap) # indentify the radio variant and set the enviroment to it's values try: self._upper, low, high, self._kind = self.VARIANTS[rid] # Frequency ranges: some model/variants are able to work the near # ham bands, even if they are outside the OEM ranges. # By experimentation we found that a +/- 4% at the edges is in most # cases safe and will cover the near ham band in full self._range = [low * 1000000 * 0.96, high * 1000000 * 1.04] # put the VARIANT in the class, clean the model / CHs / Type # in the same layout as the KPG program self._VARIANT = self.MODEL + " [" + str(self._upper) + "CH]: " # In the OEM string we show the real OEM ranges self._VARIANT += self._kind + ", %d - %d MHz" % (low, high) # DEBUG #print self._VARIANT except KeyError: LOG.debug("Wrong Kenwood radio, ID or unknown variant") LOG.debug(util.hexprint(rid)) raise errors.RadioError( "Wrong Kenwood radio, ID or unknown variant, see LOG output.")
def set_variant(self): """Select and set the correct variables for the class acording to the correct variant of the radio""" rid = get_rid(self._mmap) # indentify the radio variant and set the enviroment to it's values try: self._upper, low, high, self._kind = self.VARIANTS[rid] self._range = [low * 1000000, high * 1000000] # put the VARIANT in the class, clean the model / CHs / Type # in the same layout as the KPG program self._VARIANT = self.MODEL + " [" + str(self._upper) + "CH]: " self._VARIANT += self._kind + ", " self._VARIANT += str(self._range[0]/1000000) + "-" self._VARIANT += str(self._range[1]/1000000) + " Mhz" # DEBUG #print self._VARIANT except KeyError: LOG.debug("Wrong Kenwood radio, ID or unknown variant") LOG.debug(util.hexprint(rid)) raise errors.RadioError( "Wrong Kenwood radio, ID or unknown variant, see LOG output.")
def download(radio): status = chirp_common.Status() drain(radio.pipe) status.msg = " Power on AP510 now, waiting " radio.status_fn(status) new = enter_setup(radio.pipe) status.cur = 1 status.max = 5 status.msg = "Downloading" radio.status_fn(status) if new: radio.pipe.write("\r\nDISP\r\n") else: radio.pipe.write("@DISP") buf = "" for status.cur in range(status.cur, status.max): buf += radio.pipe.read(1024) if buf.endswith("\r\n"): status.cur = status.max radio.status_fn(status) break radio.status_fn(status) else: raise errors.RadioError("Incomplete data received.") LOG.debug("%04i P<R: %s" % (len(buf), util.hexprint(buf).replace("\n", "\n "))) return buf
def _finish(radio): endframe = "\x45\x4E\x44" _echo_write(radio, endframe) result = radio.pipe.read(1) # TYT radios acknowledge the "endframe" command, Luiton radios do not. if result != "" and result != "\x06": LOG.error( "Got:\n%s" % util.hexprint(result)) raise errors.RadioError("Radio did not finish cleanly")
def _send(pipe, data): time.sleep(0.035) # Same delay as "FT7100 Programmer" from RT Systems # pipe.write(data) --> It seems, that the single bytes are sent too fast # so send character per character with a delay for ch in data: pipe.write(ch) time.sleep(0.0012) # 0.0011 is to short. No ACK after a few packets echo = pipe.read(len(data)) if data == "": raise Exception("Failed to read echo." " Maybe serial hardware not connected." " Maybe radio not powered or not in receiving mode.") if data != echo: LOG.debug("expecting echo\n%s\n", util.hexprint(data)) LOG.debug("got echo\n%s\n", util.hexprint(echo)) raise Exception("Got false echo. Expected: '{}', got: '{}'.".format( data, echo))
def _identify(self): """Do the identification dance""" for _i in range(0, 10): self._write_record(CMD_ID) _chksum_err, _resp = self._read_record() LOG.debug("Got:\n%s" % util.hexprint(_resp)) if _chksum_err: LOG.error("Checksum error: retrying ident...") time.sleep(0.100) continue LOG.debug("Model %s" % util.hexprint(_resp[0:9])) if _resp[0:9] == self._model: return if len(_resp) == 0: raise Exception("Radio not responding") else: raise Exception("Unable to identify radio")