def _is_orig(self): version_tag = _firmware_version_from_image(self) if CHIRP_DEBUG: print "@_is_orig, version_tag:", util.hexprint(version_tag) try: if 'BFB' in version_tag: idx = version_tag.index("BFB") + 3 version = int(version_tag[idx:idx + 3]) return version < 291 if any(tag in version_tag for tag in ['BF82', 'B82', 'USA', 'BJ55']): return False except: pass raise errors.RadioError("Unable to parse version string %s" % version_tag)
def do_download(radio): do_ident(radio) data = "TH350 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) data += result[4:] do_status(radio, "from", i) return memmap.MemoryMap(data)
def _h777_write_block(radio, block_addr, block_size): serial = radio.pipe cmd = struct.pack(">cHb", 'W', block_addr, BLOCK_SIZE) data = radio.get_mmap()[block_addr:block_addr + 8] LOG.debug("Writing Data:") LOG.debug(util.hexprint(cmd + data)) try: serial.write(cmd + data) if serial.read(1) != CMD_ACK: raise Exception("No ACK") except: raise errors.RadioError("Failed to send block " "to radio at %04x" % block_addr)
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 _detect_baud(self): for baud in [9600, 19200, 38400, 57600]: self.pipe.baudrate = baud try: self.pipe.write("\r\r") except: break self.pipe.read(32) try: id = self.get_id() LOG.info("Radio %s at %i baud" % (id, baud)) return True except errors.RadioError: pass raise errors.RadioError("No response from radio")
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 _download(radio): """Get the memory map""" # put radio in program mode ident = _ident_radio(radio) # 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("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) ####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 += radio.MODEL.ljust(8) return data
def do_getcanadacounties(self): try: service = self._client.service provincelist = service.getCountryInfo(2, self._auth) provinces = {} clist = [] for province in provincelist: provinces[province[2]] = province[0] provinceinfo = service.getStateInfo(province[0], self._auth) for county in provinceinfo.countyList: if (county[1] != 'UNKNOWN' and county[1] != 'N/A' and county[1] != 'Provincewide'): # some counties are actually cities but whatever fml clist.append( [province[0], province[2], county[0], county[1]]) except WebFault, err: raise errors.RadioError(err)
def _ip620_read_block(self, block_addr): _cmd = struct.pack(">cHb", 'R', block_addr, READ_BLOCK_SIZE) _expectedresponse = "W" + _cmd[1:] LOG.debug("Reading block %04x..." % (block_addr)) try: self.pipe.write(_cmd) _response = self.pipe.read(4 + READ_BLOCK_SIZE) if _response[:4] != _expectedresponse: raise Exception("Error reading block %04x." % (block_addr)) _block_data = _response[4:] self.pipe.write(CMD_ACK) _ack = self.pipe.read(1) except: raise errors.RadioError("Failed to read block at %04x" % block_addr) if _ack != CMD_ACK: raise Exception("No ACK reading block %04x." % (block_addr)) return _block_data
def download(radio): if command(radio.pipe, "0M PROGRAM") != "0M": raise errors.RadioError("No response from radio") data = "" for i in range(0, 0x7F): data += read_block(radio.pipe, i) if radio.status_fn: s = chirp_common.Status() s.msg = "Cloning from radio" s.max = 256 * 0x7E s.cur = len(data) radio.status_fn(s) radio.pipe.write("E") return memmap.MemoryMap(data)
def get_id(ser): """Get the ID of the radio attached to @ser""" global LAST_BAUD bauds = [9600, 19200, 38400, 57600] bauds.remove(LAST_BAUD) bauds.insert(0, LAST_BAUD) for i in bauds: print "Trying ID at baud %i" % i ser.setBaudrate(i) ser.write("\r") ser.read(25) resp = command(ser, "ID") if " " in resp: LAST_BAUD = i return resp.split(" ")[1] raise errors.RadioError("No response from radio")
def load(self, filename=None): if filename is None and self._filename is None: raise errors.RadioError("Need a location to load from") if filename: self._filename = filename self._blank() f = file(self._filename, "rU") header = f.readline().strip() f.seek(0, 0) reader = csv.reader(f, delimiter=chirp_common.SEPCHAR, quotechar='"') good = 0 lineno = 0 for line in reader: lineno += 1 if lineno == 1: header = line self.file_has_rTone = "rToneFreq" in header self.file_has_cTone = "cToneFreq" in header continue if len(header) > len(line): LOG.error("Line %i has %i columns, expected %i", lineno, len(line), len(header)) self.errors.append("Column number mismatch on line %i" % lineno) continue try: mem = self._parse_csv_data_line(header, line) if mem.number is None: raise Exception("Invalid Location field" % lineno) except Exception, e: LOG.error("Line %i: %s", lineno, e) self.errors.append("Line %i: %s" % (lineno, e)) continue self._grow(mem.number) self.memories[mem.number] = mem good += 1
def sync_in(self): """Download from radio""" try: _connect_radio(self) data = _read_mem(self) data += _read_settings(self) except errors.RadioError: # Pass through any real errors we raise raise except Exception: # If anything unexpected happens, make sure we raise # a RadioError and log the problem LOG.exception('Unexpected error during download') raise errors.RadioError('Unexpected error communicating ' 'with the radio') self._mmap = memmap.MemoryMap(data) self.process_mmap() return
def variable_len_resp(pipe): """ when length of expected reply is not known, read byte at a time until the ack character is found. """ response = b"" i = 0 toolong = 256 # arbitrary while True: b = pipe.read(1) if b == b'\x06': break else: response += b i += 1 if i > toolong: LOG.debug("Response too long. got" + util.hexprint(response)) raise errors.RadioError("Response from radio too long.") return (response)
def _recv(radio, addr, length): """Get data from the radio """ # read 4 bytes of header hdr = _rawrecv(radio, 4) # read data data = _rawrecv(radio, length) # 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("X"): 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 _h777_write_block(radio, block_addr, block_size): serial = radio.pipe cmd = struct.pack(">cHb", 'W', block_addr, BLOCK_SIZE) data = radio.get_mmap()[block_addr:block_addr + 8] LOG.debug("Writing Data:") LOG.debug(util.hexprint(cmd + data)) try: serial.write(cmd + data) # Time required to write data blocks varies between individual # radios of the Baofeng BF-888S model. The longest seen is # ~0.31s. if serial.read(1) != CMD_ACK: raise Exception("No ACK") except: raise errors.RadioError("Failed to send block " "to radio at %04x" % block_addr)
def set_memory(self, mem): _mem = self._memobj.memories[mem.number] _nam = self._memobj.names[mem.number] if mem.empty: _mem.set_raw(b'\xff' * 16) _nam.set_raw(b'\xff' * 16) return if int(_mem.rxfreq) == 166666665: LOG.debug('Initializing new memory %i' % mem.number) _mem.set_raw(b'\x00' * 16) _nam.name = mem.name.ljust(10) _mem.rxfreq = mem.freq // 10 if mem.duplex == '': _mem.txfreq = mem.freq // 10 elif mem.duplex == 'split': _mem.txfreq = mem.offset // 10 elif mem.duplex == 'off': _mem.txfreq.set_raw(b'\xff\xff\xff\xff') elif mem.duplex == '-': _mem.txfreq = (mem.freq - mem.offset) // 10 elif mem.duplex == '+': _mem.txfreq = (mem.freq + mem.offset) // 10 else: raise errors.RadioError('Unsupported duplex mode %r' % mem.duplex) txtone, rxtone = chirp_common.split_tone_encode(mem) LOG.debug('tx tone is %s' % repr(txtone)) LOG.debug('rx tone is %s' % repr(rxtone)) _mem.txtone = self._encode_tone(*txtone) _mem.rxtone = self._encode_tone(*rxtone) try: _mem.power = POWER_LEVELS.index(mem.power) except ValueError: _mem.power = 0 _mem.narrow = mem.mode == 'NFM' _mem.scan = mem.skip != 'S' if mem.extra: self._set_extra(_mem, mem)
def do_download(radio): '''Download memories from the radio''' # Get the serial port connection serial = radio.pipe try: enter_program_mode(radio) memory_data = bytes() # status info for the UI status = chirp_common.Status() status.cur = 0 status.max = (MEMORY_ADDRESS_RANGE[1] - MEMORY_ADDRESS_RANGE[0]) / MEMORY_RW_BLOCK_SIZE status.msg = 'Cloning from radio...' radio.status_fn(status) for addr in range(MEMORY_ADDRESS_RANGE[0], MEMORY_ADDRESS_RANGE[1] + MEMORY_RW_BLOCK_SIZE, MEMORY_RW_BLOCK_SIZE): read_command = struct.pack('>BHB', 0x52, addr, MEMORY_RW_BLOCK_SIZE) read_response = send_serial_command(serial, read_command, MEMORY_RW_BLOCK_CMD_SIZE) # LOG.debug('read response:\n%s' % util.hexprint(read_response)) address, data, valid = parse_read_response(read_response) memory_data += data # update UI status.cur = (addr - MEMORY_ADDRESS_RANGE[0])\ / MEMORY_RW_BLOCK_SIZE radio.status_fn(status) exit_program_mode(radio) except errors.RadioError as e: raise e except Exception as e: raise errors.RadioError('Failed to download from radio: %s' % e) return memmap.MemoryMapBytes(memory_data)
def do_fetch(self): """Fetches frequencies for all subcategories in a county.""" self._freqs = [] try: service = self._client.service zipcode = service.getZipcodeInfo(self._zip, self._auth) county = service.getCountyInfo(zipcode.ctid, self._auth) except WebFault as err: raise errors.RadioError(err) status = chirp_common.Status() status.max = 0 for cat in county.cats: status.max += len(cat.subcats) status.max += len(county.agencyList) for cat in county.cats: LOG.debug("Fetching category:", cat.cName) for subcat in cat.subcats: LOG.debug("\t", subcat.scName) result = self._client.service.getSubcatFreqs( subcat.scid, self._auth) self._freqs += result status.cur += 1 self.status_fn(status) status.max -= len(county.agencyList) for agency in county.agencyList: agency = self._client.service.getAgencyInfo(agency.aid, self._auth) for cat in agency.cats: status.max += len(cat.subcats) for cat in agency.cats: LOG.debug("Fetching category:", cat.cName) for subcat in cat.subcats: try: LOG.debug("\t", subcat.scName) except AttributeError: pass result = self._client.service.getSubcatFreqs( subcat.scid, self._auth) self._freqs += result status.cur += 1 self.status_fn(status)
def _upload(radio): cur = 0 for block in radio._block_lengths: for _i in range(0, block, radio._block_size): length = min(radio._block_size, block) # LOG.debug("i=%i length=%i range: %i-%i" % # (i, length, cur, cur+length)) _send(radio.pipe, radio.get_mmap()[cur:cur + length]) if radio.pipe.read(1) != ACK: raise errors.RadioError("Radio did not ack block at %i" % cur) cur += length time.sleep(0.05) if radio.status_fn: status = chirp_common.Status() status.cur = cur status.max = radio.get_memsize() status.msg = "Cloning to radio" radio.status_fn(status)
def _upload(radio): _identify(radio) for i in range(0, 0x2000, 0x40): msg = struct.pack('>cHb', 'W', i, 0x40) msg += radio._mmap[i:(i + 0x40)] radio.pipe.write(msg) ack = radio.pipe.read(1) if ack != '\x06': raise errors.RadioError('Radio did not ACK block %i (0x%04x)' % ( i, i)) if radio.status_fn: status = chirp_common.Status() status.cur = i status.max = 0x2000 status.msg = "Cloning from radio" radio.status_fn(status) radio.pipe.write("E")
def get_memory(self, number): print "Getting %i" % number f = self._classes["mem"]() f.set_location(number) self._send_frame(f) mem = chirp_common.Memory() mem.number = number f = self._recv_frame(f) if len(f.get_data()) == 0: raise errors.RadioError("Radio reported error") if f.get_data() and f.get_data()[-1] == "\xFF": mem.empty = True return mem memobj = f.get_obj() print repr(memobj) mem.freq = int(memobj.freq) mem.mode = self._rf.valid_modes[memobj.mode] if self._rf.has_name: mem.name = str(memobj.name).rstrip() if self._rf.valid_tmodes: mem.tmode = self._rf.valid_tmodes[memobj.tmode] if self._rf.has_dtcs: # FIXME mem.dtcs = bitwise.bcd_to_int([memobj.dtcs]) if "Tone" in self._rf.valid_tmodes: mem.rtone = int(memobj.rtone) / 10.0 if "TSQL" in self._rf.valid_tmodes and self._rf.has_ctone: mem.ctone = int(memobj.ctone) / 10.0 if self._rf.valid_duplexes: mem.duplex = self._rf.valid_duplexes[memobj.duplex] return mem
def _r2_write_block(radio, block_addr, block_size): serial = radio.pipe cmd = struct.pack(">cHb", 'W', block_addr, block_size) data = radio.get_mmap()[block_addr:block_addr + block_size] LOG.debug("Writing block %04x..." % (block_addr)) LOG.debug(util.hexprint(cmd + data)) try: for j in range(0, len(cmd)): serial.write(cmd[j]) for j in range(0, len(data)): serial.write(data[j]) if serial.read(1) != CMD_ACK: raise Exception("No ACK") except: _r2_exit_programming_mode(radio) raise errors.RadioError("Failed to send block " "%04x to radio" % block_addr)
def do_upload(radio): radio.pipe.parity = "E" radio.pipe.timeout = 1 do_ident(radio) for addr in range(0, 0x0400, 8): eaddr = addr + 16 send(radio, make_frame("W", addr, 8, radio._mmap[eaddr:eaddr + 8])) ack = radio.pipe.read(1) if ack != "\x06": raise errors.RadioError("Radio refused block at %04x" % addr) radio.pipe.write("\x06") status = chirp_common.Status() status.cur = addr status.max = 0x0400 status.msg = "Cloning to radio" radio.status_fn(status) radio.pipe.write("\x45")
def _read_mem(radio): """Get the memory map""" global BEEPVOL # UI progress status = chirp_common.Status() status.cur = 0 status.max = radio._upper + 10 # 10 P chans status.msg = "Reading Channel Memory..." radio.status_fn(status) result0 = command(radio.pipe, "EX0120000", 12, W8S) BEEPVOL = int(result0[6:12]) result0 = command(radio.pipe, "EX01200000", 0, W8L) # Silence beeps data = "" mrlen = 41 # Expected fixed return string length for chn in range(0, (radio._upper + 11)): # Loop stops at +10 # Request this mem chn r0ch = 999 r1ch = r0ch # return results can come back out of order while (r0ch != chn): # simplex result0 = command(radio.pipe, "MR0%03i" % chn, mrlen, W8S) result0 += read_str(radio) r0ch = int(result0[3:6]) while (r1ch != chn): # split result1 = command(radio.pipe, "MR1%03i" % chn, mrlen, W8S) result1 += read_str(radio) r1ch = int(result1[3:6]) data += radio._parse_mem_spec(result0, result1) # UI Update status.cur = chn status.msg = "Reading Channel Memory..." radio.status_fn(status) if len(data) == 0: # To satisfy run_tests raise errors.RadioError('No data received.') return data
def do_upload(radio): do_ident(radio) data = radio._mmap[0x0030:] for i in range(0, 0x1000, 16): frame = struct.pack(">cHB", "W", i, 16) frame += data[i:i + 16] radio.pipe.write(frame) ack = radio.pipe.read(1) if ack != "\x06": # UV-B5/UV-B6 radios with 27 menus do not support service settings # and will stop ACKing when the upload reaches 0x0F10 if i == 0x0F10: # must be a radio with 27 menus detected - stop upload break else: LOG.debug("Radio NAK'd block at address 0x%04x" % i) raise errors.RadioError("Radio NAK'd block at address 0x%04x" % i) LOG.debug("Radio ACK'd block at address 0x%04x" % i) do_status(radio, "to", i)
def do_download(radio): do_ident(radio) data = "" data += "\xFF" * (0 - len(data)) for addr in range(0, radio._memsize, 0x10): send(radio, make_frame("R", addr, chr(0x10))) _addr, _data = recv(radio) if _addr != addr: raise errors.RadioError("Radio sent unexpected address") data += _data status = chirp_common.Status() status.cur = addr status.max = radio._memsize status.msg = "Cloning from radio" radio.status_fn(status) finish(radio) return memmap.MemoryMap(data)
def do_download(radio): """ Read memory from the radio. call startcomms to go into program mode and check version create an mmap read the memory blocks and place the data into the mmap send "END" """ image = bytearray(radio.get_memsize()) pipe = radio.pipe # Get the serial port connection progressbar = startcomms(radio, "from") for blocknum in range(radio.numblocks): for i in range(0, 3): if getblock(pipe, 16 * blocknum, image): break if i == 2: raise errors.RadioError("read block from radio failed 3 times") progressbar.cur = blocknum radio.status_fn(progressbar) sendcmd(pipe, b"END", 0) return memmap.MemoryMap(bytes(image))
def _recv_block(radio, addr, blocksize): """Receive a block from the radio ROM""" _rawsend(radio, _make_frame("R", addr, blocksize)) # read 4 bytes of header hdr = _rawrecv(radio, 4) # read data data = _rawrecv(radio, blocksize) # DEBUG LOG.debug("Response:") LOG.debug("\n " + util.hexprint(data)) c, a, l = struct.unpack(">BHB", hdr) if a != addr or l != blocksize or c != ord("R"): LOG.error("Invalid answer for block 0x%04x:" % addr) LOG.error("CMD: %s ADDR: %04x SIZE: %02x" % (c, a, l)) raise errors.RadioError("Unknown response from the radio") return data
def _h777_enter_programming_mode(radio): serial = radio.pipe try: serial.write(b"\x02") time.sleep(0.1) serial.write(b"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") original_timeout = serial.timeout try: serial.write(b"\x02") # At least one version of the Baofeng BF-888S has a consistent # ~0.33s delay between sending the first five bytes of the # version data and the last three bytes. We need to raise the # timeout so that the read doesn't finish early. serial.timeout = 0.5 ident = serial.read(8) except: raise errors.RadioError("Error communicating with radio") finally: serial.timeout = original_timeout if not ident.startswith(b"P3107"): 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")