def _download(radio): data = bytes(b"") chunk = bytes(b"") for i in range(0, 30): chunk += radio.pipe.read(radio._block_lengths[0]) if chunk: break if len(chunk) != radio._block_lengths[0]: raise Exception("Failed to read header (%i)" % len(chunk)) data += chunk _send(radio.pipe, bytes([ACK])) for i in range(0, radio._block_lengths[1], radio._block_size): chunk = radio.pipe.read(radio._block_size) data += chunk if len(chunk) != radio._block_size: break time.sleep(0.01) _send(radio.pipe, ACK) if radio.status_fn: status = chirp_common.Status() status.max = radio.get_memsize() status.cur = i + len(chunk) status.msg = "Cloning from radio" radio.status_fn(status) data += radio.pipe.read(1) _send(radio.pipe, bytes([ACK])) return memmap.MemoryMapBytes(data)
def expand_mmap(self, zone_sizes): """Remap memory into zones of the specified sizes, copying things around to keep the contents, as appropriate.""" old_zones = self._zones old_memobj = self._memobj self._mmap = memmap.MemoryMapBytes(bytes(self._mmap.get_packed())) new_format = HEADER_FORMAT addr = self._system_start self._zones = [] for index, count in enumerate(zone_sizes): new_format += SYSTEM_MEM_FORMAT % { 'addr': addr, 'count': max(count, 2), # bitwise bug 'index': index} self._zones.append((addr, count)) addr += 0x20 + (count * 0x30) self._memobj = bitwise.parse(new_format, self._mmap) # Set all known zone addresses and clear the rest for index in range(0, 128): try: self._memobj.zone_starts[index] = self._zones[index][0] except IndexError: self._memobj.zone_starts[index] = 0xFFFF for zone_number, count in enumerate(zone_sizes): dest_zone = getattr(self._memobj, 'zone%i' % zone_number) dest = dest_zone.memories dest_zoneinfo = dest_zone.zoneinfo if zone_number < len(old_zones): LOG.debug('Copying existing zone %i' % zone_number) _, old_count = old_zones[zone_number] source_zone = getattr(old_memobj, 'zone%i' % zone_number) source = source_zone.memories source_zoneinfo = source_zone.zoneinfo if old_count != count: LOG.debug('Zone %i going from %i to %i' % (zone_number, old_count, count)) # Copy the zone record from the source, but then update # the count dest_zoneinfo.set_raw(source_zoneinfo.get_raw()) dest_zoneinfo.count = count source_i = 0 for dest_i in range(0, min(count, old_count)): dest[dest_i].set_raw(source[dest_i].get_raw()) else: LOG.debug('New zone %i' % zone_number) dest_zone.zoneinfo.number = zone_number + 1 dest_zone.zoneinfo.zonetype = 0x31 dest_zone.zoneinfo.count = count dest_zone.zoneinfo.name = ( 'Zone %i' % (zone_number + 1)).ljust(12)
def do_download(radio): radio.pipe.parity = "E" radio.pipe.timeout = 1 do_ident(radio) data = bytes(b"") for addr in range(0, 0x0400, 8): send(radio, make_frame(bytes(b"R"), addr, 8)) _addr, _data = recv(radio) if _addr != addr: raise errors.RadioError("Radio sent unexpected address") data += _data radio.pipe.write(b"\x06") ack = radio.pipe.read(1) if ack != bytes(b"\x06"): raise errors.RadioError("Radio refused block at %04x" % addr) status = chirp_common.Status() status.cur = addr status.max = 0x0400 status.msg = "Cloning to radio" radio.status_fn(status) radio.pipe.write(b"\x45") data = (b"\x45\x58\x33\x34\x30\x32\xff\xff" + (b"\xff" * 8) + data) return memmap.MemoryMapBytes(data)
def __clone_in(radio): pipe = radio.pipe status = chirp_common.Status() status.msg = "Cloning from radio" status.max = radio.get_memsize() start = time.time() data = bytes(b"") blocks = 0 for block in radio._block_lengths: blocks += 1 if blocks == len(radio._block_lengths): chunk = _chunk_read(pipe, block, radio.status_fn) else: chunk = _safe_read(pipe, block) pipe.write(bytes([CMD_ACK])) if not chunk: raise errors.RadioError("No response from radio") if radio.status_fn: status.cur = len(data) radio.status_fn(status) data += chunk if len(data) != radio.get_memsize(): raise errors.RadioError("Received incomplete image from radio") LOG.debug("Clone completed in %i seconds" % (time.time() - start)) return memmap.MemoryMapBytes(data)
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 test_int_array(self): data = memmap.MemoryMapBytes(bytes(b'\x00\x01\x02\x03')) obj = bitwise.parse('u8 foo[4];', data) for i in range(4): self.assertEqual(i, obj.foo[i]) obj.foo[i] = i * 2 self.assertEqual(b'\x00\x02\x04\x06', data.get_packed())
def test_struct_writes(self): data = memmap.MemoryMapBytes(bytes(b"..")) defn = "struct { u8 bar; u8 baz; } foo;" obj = bitwise.parse(defn, data) obj.foo.bar = 0x12 obj.foo.baz = 0x34 self.assertEqual(data.get_packed(), b"\x12\x34")
def do_download(radio): do_ident(radio) data = b"KT511 Radio Program data v1.08\x00\x00" data += (b"\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(b"\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.MemoryMapBytes(data)
def test_char(self): data = memmap.MemoryMapBytes(bytes(b"c")) obj = bitwise.parse("char foo;", data) self.assertEqual(str(obj.foo), "c") self.assertEqual(obj.foo.size(), 8) obj.foo = "d" self.assertEqual(data.get_packed(), b"d")
def test_string(self): data = memmap.MemoryMapBytes(bytes(b"foobar")) obj = bitwise.parse("char foo[6];", data) self.assertEqual(str(obj.foo), "foobar") self.assertEqual(obj.foo.size(), 8 * 6) obj.foo = "bazfoo" self.assertEqual(data.get_packed(), b"bazfoo")
def test_string_with_various_input_types(self): data = memmap.MemoryMapBytes(bytes(b"foobar")) obj = bitwise.parse("char foo[6];", data) self.assertEqual('foobar', str(obj.foo)) self.assertEqual(6, len(b'barfoo')) obj.foo = b'barfoo' self.assertEqual('barfoo', str(obj.foo)) obj.foo = [ord(c) for c in 'fffbbb'] self.assertEqual('fffbbb', str(obj.foo))
def test_bit_array(self): defn = "bit foo[24];" data = memmap.MemoryMapBytes(bytes(b"\x00\x80\x01")) obj = bitwise.parse(defn, data) for i, v in [(0, False), (8, True), (23, True)]: self.assertEqual(bool(obj.foo[i]), v) for i in range(0, 24): obj.foo[i] = i % 2 self.assertEqual(data.get_packed(), b"\x55\x55\x55")
def test_string_invalid_chars(self): data = memmap.MemoryMapBytes(bytes(b"\xFFoobar1")) obj = bitwise.parse("struct {char foo[7];} bar;", data) if six.PY3: expected = '\xffoobar1' else: expected = '\\xffoobar1' self.assertIn(expected, repr(obj.bar))
def sync_in(self): try: data = do_download(self) self._mmap = memmap.MemoryMapBytes(data) except errors.RadioError: raise except Exception as e: LOG.exception('General failure') raise errors.RadioError('Failed to download from radio: %s' % e) self.process_mmap()
def test_bitfield_u8(self): defn = "u8 foo:4, bar:4;" data = memmap.MemoryMapBytes(bytes(b"\x12")) obj = bitwise.parse(defn, data) self.assertEqual(obj.foo, 1) self.assertEqual(obj.bar, 2) self.assertEqual(obj.foo.size(), 4) self.assertEqual(obj.bar.size(), 4) obj.foo = 0x8 obj.bar = 0x1 self.assertEqual(data.get_packed(), b"\x81")
def _test_def(self, definition, name, _data, value): data = memmap.MemoryMapBytes(bytes(_data)) obj = bitwise.parse(definition, data) self.assertEqual(int(getattr(obj, name)), value) self.assertEqual(getattr(obj, name).size(), len(_data) * 8) setattr(obj, name, 0) self.assertEqual(data.get_packed(), (b"\x00" * len(_data))) setattr(obj, name, 42) if definition.startswith("b"): expected = (len(_data) == 2 and b"\x00" or b"") + b"\x42" else: expected = b"\x42" + (len(_data) == 2 and b"\x00" or b"") raw = data.get_packed() self.assertEqual(raw, expected)
def _asbytes(mmap): if hasattr(mmap, 'get_byte_compatible'): return mmap.get_byte_compatible() elif isinstance(mmap, bytes): # NOTE: this won't work for update(), but nothing should be calling # this with a literal expecting that to work return memmap.MemoryMapBytes(bytes(mmap)) elif isinstance(mmap, str): # NOTE: this won't work for update(), but nothing should be calling # this with a literal expecting that to work return memmap.MemoryMap( bitwise.string_straight_encode(mmap)).get_byte_compatible() else: raise TypeError('Unable to convert %s to bytes' % (type(mmap).__name__))
def _clone_from_radio(radio): md = get_model_data(radio) if md[0:4] != radio.get_model(): LOG.info("This model: %s" % util.hexprint(md[0:4])) LOG.info("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, CMD_CLONE_OUT, radio.get_model(), raw=True) LOG.debug("Sent clone frame") stream = RadioStream(radio.pipe) addr = 0 _mmap = memmap.MemoryMapBytes(bytes(b'\x00') * 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(radio, frame, _mmap) if last_size != (dst - src): LOG.debug("ICF Size change from %i to %i at %04x" % (last_size, dst - src, src)) last_size = dst - src if addr != src: LOG.debug("ICF GAP %04x - %04x" % (addr, src)) addr = dst elif frame.cmd == CMD_CLONE_END: LOG.debug("End frame (%i):\n%s" % (len(frame.payload), util.hexprint(frame.payload))) LOG.debug("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 do_download(radio): do_ident(radio) data = b"TRI350 Radio Program data v1.08\x00" data += (b"\x00" * 16) firstack = None for i in range(0, 0x1000, 16): frame = struct.pack(">cHB", b"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.MemoryMapBytes(data)
def _test_bitfield_24(self, variant, data): defn = "u%s24 foo:12, bar:6, baz:6;" % variant data = memmap.MemoryMapBytes(bytes(data)) obj = bitwise.parse(defn, data) self.assertEqual(int(obj.foo), 4) self.assertEqual(int(obj.bar), 3) self.assertEqual(int(obj.baz), 2) self.assertEqual(obj.foo.size(), 12) self.assertEqual(obj.bar.size(), 6) self.assertEqual(obj.baz.size(), 6) obj.foo = 1 obj.bar = 2 obj.baz = 3 if variant == 'l': self.assertEqual(data.get_packed(), b"\x83\x10\x00") else: self.assertEqual(data.get_packed(), b"\x00\x10\x83")
def load_mmap(self, filename): """Load the radio's memory map from @filename""" mapfile = open(filename, "rb") data = mapfile.read() if self.MAGIC in data: data, self._metadata = self._strip_metadata(data) if ('chirp_version' in self._metadata and is_version_newer(self._metadata.get('chirp_version'))): LOG.warning( 'Image is from version %s but we are %s' % (self._metadata.get('chirp_version'), CHIRP_VERSION)) if self.NEEDS_COMPAT_SERIAL: self._mmap = memmap.MemoryMap(data) else: self._mmap = memmap.MemoryMapBytes(bytes(data)) mapfile.close() self.process_mmap()
def _test_bitfield_16(self, variant, data): defn = "u%s16 foo:4, bar:8, baz:4;" % variant data = memmap.MemoryMapBytes(bytes(data)) obj = bitwise.parse(defn, data) self.assertEqual(int(obj.foo), 1) self.assertEqual(int(obj.bar), 0x23) self.assertEqual(int(obj.baz), 4) self.assertEqual(obj.foo.size(), 4) self.assertEqual(obj.bar.size(), 8) self.assertEqual(obj.baz.size(), 4) obj.foo = 0x2 obj.bar = 0x11 obj.baz = 0x3 if variant == "l": self.assertEqual(data.get_packed(), b"\x13\x21") else: self.assertEqual(data.get_packed(), b"\x21\x13")
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 _test_checksum(self, mmap): cs = yaesu_clone.YaesuChecksum(0, 2, 3) self.assertEqual(42, cs.get_existing(mmap)) self.assertEqual(0x8A, cs.get_calculated(mmap)) try: mmap = mmap.get_byte_compatible() mmap[0] = 3 except AttributeError: # str or bytes try: # str mmap = memmap.MemoryMap('\x03' + mmap[1:]) except TypeError: # bytes mmap = memmap.MemoryMapBytes(b'\x03' + mmap[1:]) cs.update(mmap) self.assertEqual(95, cs.get_calculated(mmap))
def _test_type(self, datatype, _data, value): data = memmap.MemoryMapBytes(bytes(_data)) obj = bitwise.parse("%s foo;" % datatype, data) self.assertEqual(int(obj.foo), value) self.assertEqual(obj.foo.size(), len(data) * 8) obj.foo = 0 self.assertEqual(int(obj.foo), 0) self.assertEqual(data.get_packed(), (b"\x00" * (obj.size() // 8))) obj.foo = value self.assertEqual(int(obj.foo), value) self.assertEqual(data.get_packed(), _data) obj.foo = 7 # Compare against the equivalent real division so we get consistent # results on py2 and py3 self.assertEqual(7 // 2, obj.foo // 2) self.assertEqual(7 / 2, obj.foo / 2) self.assertEqual(7 / 2.0, obj.foo / 2.0)
def _clone_in(self): # Be very patient with the radio self.pipe.timeout = 2 start = time.time() data = bytes(b"") blocks = 0 status = chirp_common.Status() status.msg = _("Cloning from radio") nblocks = len(self._block_lengths) + 39 status.max = nblocks for block in self._block_lengths: if blocks == 8: # repeated read of 40 block same size (memory area) repeat = 40 else: repeat = 1 for _i in range(0, repeat): data += self._read(block, blocks, blocks == nblocks - 1) self.pipe.write(bytes([CMD_ACK])) blocks += 1 status.cur = blocks self.status_fn(status) if not self._US_model: status.msg = _("Clone completed, checking for spurious bytes") self.status_fn(status) moredata = self.pipe.read(2) if moredata: raise Exception( _("Radio sent data after the last awaited block, " "this happens when the selected model is a non-US " "but the radio is a US one. " "Please choose the correct model and try again.")) LOG.info("Clone completed in %i seconds" % (time.time() - start)) return memmap.MemoryMapBytes(data)
def _run(self, serial): error = None live = isinstance(self._wrapper._dst, chirp_common.LiveRadio) clone = isinstance(self._wrapper._dst, chirp_common.CloneModeRadio) if not clone and not live: raise TestSkippedError('Does not support clone') try: radio = self._wrapper._dst.__class__(serial) radio.status_fn = lambda s: True except Exception as e: error = e if not live: if error is not None: raise TestFailedError("Clone radio tried to read from " + "serial on init") else: if not isinstance(error, errors.RadioError): raise TestFailedError("Live radio didn't notice serial " + "was dead on init") return [] # Nothing more to test on an error'd live radio error = None try: radio.sync_in() except Exception as e: error = e if error is None: raise TestFailedError("Radio did not raise exception " + "with %s data" % serial, "On sync_in()") elif not isinstance(error, errors.RadioError): raise TestFailedError("Radio did not raise RadioError " + "with %s data" % serial, "sync_in() Got: %s (%s)\n%s" % (error.__class__.__name__, error, get_tb())) if radio.NEEDS_COMPAT_SERIAL: radio._mmap = memmap.MemoryMap("\x00" * (1024 * 128)) else: radio._mmap = memmap.MemoryMapBytes(bytes(b"\x00") * (1024 * 128)) error = None try: radio.sync_out() except Exception as e: error = e if error is None: raise TestFailedError("Radio did not raise exception " + "with %s data" % serial, "On sync_out()") elif not isinstance(error, errors.RadioError): raise TestFailedError("Radio did not raise RadioError " + "with %s data" % serial, "sync_out(): Got: %s (%s)" % (error.__class__.__name__, error)) if serial.mismatch: raise TestFailedError("Radio tried to write the wrong " "type of data to the %s pipe." % ( serial.__class__.__name__), "TestClone:%s\n%s" % ( serial.__class__.__name__, serial.mismatch_at)) return []
def test_struct_get_raw_small(self): data = memmap.MemoryMapBytes(bytes(b".")) defn = "struct { u8 bar; } foo;" obj = bitwise.parse(defn, data) self.assertEqual('.', obj.get_raw()) self.assertEqual(b'.', obj.get_raw(asbytes=True))
def test_sync_out(self): self.radio._mmap = memmap.MemoryMapBytes( bytes(b'\x00') * self.radio.get_memsize()) self.radio._mmap[50] = bytes(b'abcdefgh') self.radio.sync_out() self.assertEqual(b'abcdefgh', self.simulator._memory[50:58])
def test_with_MemoryMapBytes(self): mmap = memmap.MemoryMapBytes(bytes(b'...\x2A')) self._test_checksum(mmap)