def unpack_package(package_path, target_dir): """ Unpacks a Nordic DFU package. :param str package_path: Path to the package :param str target_dir: Target directory to unpack the package to :return: Manifest Manifest: Returns a manifest back to the user. The manifest is a parse datamodel of the manifest found in the Nordic DFU package. """ if not os.path.isfile(package_path): raise NordicSemiException("Package {0} not found.".format(package_path)) target_dir = os.path.abspath(target_dir) target_base_path = os.path.dirname(target_dir) if not os.path.exists(target_base_path): raise NordicSemiException("Base path to target directory {0} does not exist.".format(target_base_path)) if not os.path.isdir(target_base_path): raise NordicSemiException("Base path to target directory {0} is not a directory.".format(target_base_path)) if os.path.exists(target_dir): raise NordicSemiException( "Target directory {0} exists, not able to unpack to that directory.", target_dir) with ZipFile(package_path, 'r') as pkg: pkg.extractall(target_dir) with open(os.path.join(target_dir, Package.MANIFEST_FILENAME), 'r') as f: _json = f.read() """:type :str """ return Manifest.from_json(_json)
def _wait_for_response(self, opcode): """ Waits for self.response_opcode_received to be set to the expected opcode Will timeout after 10 seconds :param int opcode: The expected opcode :return: """ timeout = 40 start_time = datetime.now() while self.response_opcode_received != opcode: timed_out = datetime.now() - start_time > timedelta(0, timeout) if timed_out: log_message = "Timeout while waiting for response from device." self._send_event(DfuEvent.TIMEOUT_EVENT, log_message=log_message) raise NordicSemiException(log_message) if self.disconnected_event_received: log_message = "Disconnected from device." raise IllegalStateException(log_message) time.sleep(0.1) if self.last_error != DfuErrorCodeBle.SUCCESS: error_message = DfuErrorCodeBle.error_code_lookup(self.last_error) self._send_event(DfuEvent.ERROR_EVENT, log_message=error_message) raise NordicSemiException(error_message) self.response_opcode_received = None
def open(self): super(DfuTransportSerial, self).open() try: self.serial_port = Serial(port=self.com_port, baudrate=self.baud_rate, rtscts=self.flow_control, timeout=self.timeout) except Exception, e: raise NordicSemiException("Serial port could not be opened on {0}. Reason: {1}".format(self.com_port, e.message))
def open(self): super(DfuTransportSerial, self).open() # Touch is enabled, disconnect and reconnect if self.touch > 0: try: touch_port = Serial(port=self.com_port, baudrate=self.touch, rtscts=self.flow_control, timeout=self.timeout) except Exception as e: raise NordicSemiException( "Serial port could not be opened on {0}. Reason: {1}". format(self.com_port, e)) # Wait for serial port stable time.sleep(DfuTransportSerial.SERIAL_PORT_OPEN_WAIT_TIME) touch_port.close() logger.info("Touched serial port %s", self.com_port) # Wait for device go into DFU mode and fully enumerated time.sleep(DfuTransportSerial.TOUCH_RESET_WAIT_TIME) try: self.serial_port = Serial(port=self.com_port, baudrate=self.baud_rate, rtscts=self.flow_control, timeout=self.timeout) except Exception as e: raise NordicSemiException( "Serial port could not be opened on {0}. Reason: {1}".format( self.com_port, e)) logger.info("Opened serial port %s", self.com_port) # Wait for serial port stable time.sleep(DfuTransportSerial.SERIAL_PORT_OPEN_WAIT_TIME) # Toggle DTR to reset the board and enter DFU mode (only if touch is not used) if self.touch == 0: self.serial_port.setDTR(False) time.sleep(0.05) self.serial_port.setDTR(True) # Delay to allow device to boot up time.sleep(DfuTransportSerial.DTR_RESET_WAIT_TIME)
def _wait_for_condition(self, condition_function, expected_condition_value=True, timeout=10, waiting_for="condition"): """ Waits for condition_function to be true Will timeout after 60 seconds :param function condition_function: The function we are waiting for to return true :param str timeout_message: Message that should be logged :return: """ start_time = datetime.now() while condition_function() != expected_condition_value: timeout_message = "Timeout while waiting for {0}.".format( waiting_for) timed_out = datetime.now() - start_time > timedelta(0, timeout) if timed_out: self._send_event(DfuEvent.TIMEOUT_EVENT, log_message=timeout_message) raise NordicSemiException(timeout_message) if not self.is_open(): log_message = "Disconnected from device while waiting for {0}.".format( waiting_for) raise IllegalStateException(log_message) sleep(0.1) if self.get_last_error() != DfuErrorCodeBle.SUCCESS: error_message = "Error occoured while waiting for {0}. Error response {1}." error_code = DfuErrorCodeBle.error_code_lookup( self.get_last_error()) error_message = error_message.format(waiting_for, error_code) self._send_event(DfuEvent.ERROR_EVENT, log_message=error_message) raise NordicSemiException(error_message)
def open(self): super(DfuTransportSerial, self).open() try: self.serial_port = Serial(port=self.com_port, baudrate=self.baud_rate, rtscts=self.flow_control, timeout=self.timeout) except Exception as e: raise NordicSemiException("Serial port could not be opened on {0}. Reason: {1}".format(self.com_port, e)) logger.info("Opened serial port %s", self.com_port) # Wait for the system to reset time.sleep(DfuTransportSerial.SERIAL_PORT_OPEN_WAIT_TIME) # Toggle DTR to reset the board and enter DFU mode self.serial_port.setDTR(False) time.sleep(0.05) self.serial_port.setDTR(True) # Delay to allow device to boot up time.sleep(DfuTransportSerial.NRF52_RESET_WAIT_TIME)
def get_ack_nr(self): def is_timeout(start_time, timeout_sec): return not (datetime.now() - start_time <= timedelta( 0, timeout_sec)) uart_buffer = [] start = datetime.now() while uart_buffer.count(0xC0) < 2: # Disregard first of the two C0 temp = [x for x in self.serial_port.read(6)] if temp: uart_buffer += temp if is_timeout(start, DfuTransportSerial.ACK_PACKET_TIMEOUT): # reset HciPacket numbering back to 0 HciPacket.sequence_number = 0 self._send_event( DfuEvent.TIMEOUT_EVENT, log_message= "Timed out waiting for acknowledgement from device.") # quit loop break # read until you get a new C0 # RESUME_WORK if len(uart_buffer) < 2: raise NordicSemiException( "No data received on serial port. Not able to proceed.") logger.debug("PC <- target: %s", [hex(i) for i in uart_buffer]) data = self.decode_esc_chars(uart_buffer) # Remove 0xC0 at start and beginning data = data[1:-1] # Extract ACK number from header return (data[0] >> 3) & 0x07
def sleep_until_ready_to_send(): """ Waits until a notification is received from peer device Will timeout after 10 seconds :return: """ if NUM_OF_PACKETS_BETWEEN_NOTIF: timeout = 10 start_time = datetime.now() while not self.ready_to_send: timed_out = datetime.now() - start_time > timedelta( 0, timeout) if timed_out: log_message = "Timeout while waiting for notification from device." self._send_event(DfuEvent.TIMEOUT_EVENT, log_message=log_message) raise NordicSemiException(log_message) time.sleep(0.1)
def slip_decode_esc_chars(data): """Decode esc characters in a SLIP package. Replaces 0xDBDC with 0xCO and 0xDBDD with 0xDB. :return: str decoded data :type str data: data to decode """ result = [] while len(data): char = data.pop(0) if char == 0xDB: char2 = data.pop(0) if char2 == 0xDC: result.append(0xC0) elif char2 == 0xDD: result.append(0xDB) else: raise NordicSemiException('Char 0xDB NOT followed by 0xDC or 0xDD') else: result.append(char) return result