async def interact(self, device, args, avr_iface): await avr_iface.programming_enable() signature = await avr_iface.read_signature() device = devices_by_signature[signature] self.logger.info("device signature: %s (%s)", "{:02x} {:02x} {:02x}".format(*signature), "unknown" if device is None else device.name) if args.operation is not None and device is None: raise GlasgowAppletError("cannot operate on unknown device") if args.operation == "read": if args.fuses: fuses = await avr_iface.read_fuse_range(range(device.fuses_size)) if device.fuses_size > 2: self.logger.info("fuses: low %s high %s extra %s", "{:08b}".format(fuses[0]), "{:08b}".format(fuses[1]), "{:08b}".format(fuses[2])) elif device.fuses_size > 1: self.logger.info("fuses: low %s high %s", "{:08b}".format(fuses[0]), "{:08b}".format(fuses[1])) else: self.logger.info("fuse: %s", "{:08b}".format(fuses[0])) if args.lock_bits: lock_bits = await avr_iface.read_lock_bits() self.logger.info("lock bits: %s", "{:08b}".format(lock_bits)) if args.calibration: calibration = \ await avr_iface.read_calibration_range(range(device.calibration_size)) self.logger.info("calibration bytes: %s", " ".join(["%02x" % b for b in calibration])) if args.program: self._check_format(args.program, "program memory") self.logger.info("reading program memory (%d bytes)", device.program_size) output_data(args.program, await avr_iface.read_program_memory_range(range(device.program_size))) if args.eeprom: self._check_format(args.eeprom, "EEPROM") self.logger.info("reading EEPROM (%d bytes)", device.eeprom_size) output_data(args.eeprom, await avr_iface.read_eeprom_range(range(device.eeprom_size))) if args.operation == "write-fuses": if args.high and device.fuses_size < 2: raise GlasgowAppletError("device does not have high fuse") if args.low: self.logger.info("writing low fuse") await avr_iface.write_fuse(0, args.low) written = await avr_iface.read_fuse(0) if written != args.low: raise GlasgowAppletError("verification of low fuse failed: %s" % "{:08b} != {:08b}".format(written, args.low)) if args.high: self.logger.info("writing high fuse") await avr_iface.write_fuse(1, args.high) written = await avr_iface.read_fuse(1) if written != args.high: raise GlasgowAppletError("verification of high fuse failed: %s" % "{:08b} != {:08b}".format(written, args.high)) if args.operation == "write-lock": self.logger.info("writing lock bits") await avr_iface.write_lock_bits(args.bits) written = await avr_iface.read_lock_bits() if written != args.bits: raise GlasgowAppletError("verification of lock bits failed: %s" % "{:08b} != {:08b}".format(written, args.bits)) if args.operation == "write-program": self.logger.info("erasing chip") await avr_iface.chip_erase() self._check_format(args.file, "program memory") data = input_data(args.file) self.logger.info("writing program memory (%d bytes)", sum([len(chunk) for address, chunk in data])) for address, chunk in data: chunk = bytes(chunk) await avr_iface.write_program_memory_range(address, chunk, device.program_page) written = await avr_iface.read_program_memory_range(range(address, len(chunk))) if written != chunk: raise GlasgowAppletError("verification failed at address %#06x: %s != %s" % (address, written.hex(), chunk.hex())) if args.operation == "write-eeprom": self._check_format(args.file, "EEPROM") data = input_data(args.file) self.logger.info("writing EEPROM (%d bytes)", sum([len(chunk) for address, chunk in data])) for address, chunk in data: chunk = bytes(chunk) await avr_iface.write_eeprom_range(address, chunk, device.eeprom_page) written = await avr_iface.read_eeprom_range(range(address, len(chunk))) if written != chunk: raise GlasgowAppletError("verification failed at address %#06x: %s != %s" % (address, written.hex(), chunk.hex())) await avr_iface.programming_disable()
async def interact(self, device, args, nrf24lx1_iface): page_size = 512 if args.device == "LE1": memory_map = _nrf24le1_map buffer_size = 512 elif args.device == "LU1p32k": memory_map = _nrf24lu1p_32k_map buffer_size = 256 elif args.device == "LU1p16k": memory_map = _nrf24lu1p_16k_map buffer_size = 256 else: assert False try: await nrf24lx1_iface.reset_program() async def check_info_page(address): old_status = await nrf24lx1_iface.read_status() try: await nrf24lx1_iface.write_status(FSR_BIT_INFEN) fuse, = await nrf24lx1_iface.read(address, 1) return fuse != 0xff finally: await nrf24lx1_iface.write_status(old_status) async def check_read_protected(): if await check_info_page(0x23): raise ProgramNRF24Lx1Error("MCU is read protected; run `erase --info-page`") if args.operation == "read": await check_read_protected() chunks = [] for memory_area in memory_map: self.logger.info("reading %s memory", memory_area.name) if memory_area.spi_addr & 0x10000: await nrf24lx1_iface.write_status(FSR_BIT_INFEN) else: await nrf24lx1_iface.write_status(0) area_data = await nrf24lx1_iface.read(memory_area.spi_addr & 0xffff, memory_area.size) chunks.append((memory_area.mem_addr, area_data)) output_data(args.file, chunks, fmt="ihex") if args.operation == "program": await check_read_protected() area_index = 0 memory_area = memory_map[area_index] erased_pages = set() for chunk_mem_addr, chunk_data in sorted(input_data(args.file, fmt="ihex"), key=lambda c: c[0]): if len(chunk_data) == 0: continue if chunk_mem_addr < memory_area.mem_addr: raise ProgramNRF24Lx1Error("data outside of memory map at {:#06x}" .format(chunk_mem_addr)) while chunk_mem_addr >= memory_area.mem_addr + memory_area.size: area_index += 1 if area_index >= len(memory_area): raise ProgramNRF24Lx1Error("data outside of memory map at {:#06x}" .format(chunk_mem_addr)) memory_area = memory_map[area_index] if chunk_mem_addr + len(chunk_data) > memory_area.mem_addr + memory_area.size: raise ProgramNRF24Lx1Error("data outside of memory map at {:#06x}" .format(memory_area.mem_addr + memory_area.size)) if memory_area.spi_addr & 0x10000 and not args.info_page: self.logger.warn("data provided for info page, but info page programming " "is not enabled") continue chunk_spi_addr = (chunk_mem_addr - memory_area.mem_addr + memory_area.spi_addr) & 0xffff if memory_area.spi_addr & 0x10000: level = logging.WARN await nrf24lx1_iface.write_status(FSR_BIT_INFEN) else: level = logging.INFO await nrf24lx1_iface.write_status(0) overwrite_pages = set(range( (chunk_spi_addr // page_size), (chunk_spi_addr + len(chunk_data) + page_size - 1) // page_size)) need_erase_pages = overwrite_pages - erased_pages if need_erase_pages: for page in need_erase_pages: page_addr = (memory_area.spi_addr & 0x10000) | (page * page_size) self.logger.log(level, "erasing %s memory at %#06x+%#06x", memory_area.name, page_addr, page_size) await nrf24lx1_iface.write_enable() await nrf24lx1_iface.erase_page(page) await nrf24lx1_iface.wait_status() erased_pages.update(need_erase_pages) self.logger.log(level, "programming %s memory at %#06x+%#06x", memory_area.name, chunk_mem_addr, len(chunk_data)) while len(chunk_data) > 0: await nrf24lx1_iface.write_enable() await nrf24lx1_iface.program(chunk_spi_addr, chunk_data[:buffer_size]) await nrf24lx1_iface.wait_status() chunk_data = chunk_data[buffer_size:] chunk_spi_addr += buffer_size if args.operation == "erase": if args.info_page: await nrf24lx1_iface.write_status(FSR_BIT_INFEN) info_page = await nrf24lx1_iface.read(0x0000, 0x0100) self.logger.warn("backing up info page to %s", args.info_page) if os.path.isfile(args.info_page): raise ProgramNRF24Lx1Error("info page backup file already exists") with open(args.info_page, "wb") as f: output_data(f, [(0x10000, info_page)]) self.logger.warn("erasing code and data memory, and info page") else: await check_read_protected() await nrf24lx1_iface.write_status(0) self.logger.info("erasing code and data memory") try: await nrf24lx1_iface.write_enable() await nrf24lx1_iface.erase_all() await nrf24lx1_iface.wait_status() if args.info_page: self.logger.info("restoring info page DSYS area") await nrf24lx1_iface.write_enable() await nrf24lx1_iface.program(0, info_page[:32]) # DSYS only await nrf24lx1_iface.wait_status() except: if args.info_page: self.logger.error("IMPORTANT: programming failed; restore DSYS manually " "using `program --info-page %s`", args.info_page) raise if args.operation == "protect-read": if await check_info_page(0x23): raise ProgramNRF24Lx1Error("memory read protection is already enabled") self.logger.warn("protecting code and data memory from reads") await nrf24lx1_iface.write_enable() await nrf24lx1_iface.disable_read() await nrf24lx1_iface.wait_status() if args.operation == "enable-debug": if await check_info_page(0x24): raise ProgramNRF24Lx1Error("hardware debugging features already enabled") self.logger.info("enabling hardware debugging features") await nrf24lx1_iface.write_enable() await nrf24lx1_iface.enable_debug() await nrf24lx1_iface.wait_status() finally: await nrf24lx1_iface.reset_application()