def receive_raw(self): """ Receives a response and returns the raw values """ length_byte = self.connection.read(1) length = struct.unpack("<B", length_byte)[0] packet = self.connection.read(length) # Check the CRC checksum crc16 = Crc("crc-16-mcrf4xx") crc16.update(length_byte + packet[:-2]) packet_crc = struct.unpack("<H", packet[-2:])[0] if crc16.crcValue != packet_crc: raise RuntimeError("Bad CRC checksum on response: %s != %s" % (crc16.crcValue, packet_crc)) # Unpack main values address, command, status = struct.unpack("<BBB", packet[:3]) data = packet[3:-2] # Check for errors if status == STATUS.ERROR_COMMAND_EXECUTE: raise CommandExecutionError() if status == STATUS.ERROR_POOR_COMMS: raise PoorCommunicationError() if status == STATUS.ERROR_NO_TAG: raise NoTagError() if status == STATUS.ERROR_COMMAND_LENGTH: raise CommandLengthWrong() if status == STATUS.ERROR_TAG_INTERNAL: raise InternalTagError(struct.unpack("<B", data)[0]) if status == STATUS.ERROR_ILLEGAL_COMMAND: raise IllegalCommand() if status == STATUS.ERROR_PARAMETER: raise ParameterError() # Return raw data return address, command, status, data
def __init__(self, config_path, config_option): self.is_configured = False self.is_connected = False self.connected_to = None self._ser = [] self._mode = [] self._port = None self._baud = [] self._timeout = [] self._vpi_mask = [] self.id = [] self._autoconnect = [] self._in_buffer = [] self._out_buffer = [] self._wait_for_ver = [] self._wait_for_data = [] self.crc = Crc('crc-8') # ###### INCOMPLETE ###### # self.configure(config_path, config_option) if self._autoconnect: if TransceiverModes[self._mode] is TransceiverModes.MASTER: pass elif TransceiverModes[self._mode] is TransceiverModes.SLAVE: pass
def calculate_authid(tid: int, uid: int): """ Calculate anonymous authID from nickname and thread id. :param uid: Anonymous User ID :param tid: Thread ID :return: Anonymous authID """ rand = str(b2a_hex(urandom(4)))[2:10] crc16 = Crc('crc-16') crc16.update((str(uid) + ":" + str(tid) + rand).encode('utf-8')) return b64encode(crc16.hexdigest().encode('utf-8')).decode('utf-8')
def send_raw(self, address, command, data): """ Sends a command to the device. """ # Packet header packet = struct.pack("<BBB", len(data) + 4, address, command) # Packet data packet += data # CRC crc16 = Crc("crc-16-mcrf4xx") crc16.update(packet) packet += struct.pack("<H", crc16.crcValue) # print(["%02x" % x for x in packet]) self.connection.write(packet)
def dump_freq(info, crc, name): crc16 = Crc('crc-16') crc16.update(info) if (crc16.crcValue != crc): print "%s: CRC mismatch" % name else: (band, deemph, spacing, chan, vol) = unpack('<BBBHB8x', info) try: freq = calc_freq(band, spacing, chan) print "%s: Freq %.2f MHz" % (name, freq) except: print "%s: Cannot decode frequency" % name print " Band: %02x" % band print " Deemphasis: %02x" % deemph print " Spacing: %02x" % spacing print " Channel: %d" % chan print " Volume: %02x" % vol
def dump_freq(info, crc): crc16 = Crc('crc-16') crc16.update(info) if (crc16.crcValue != crc): print "%s: CRC mismatch" % name else: (band, deemph, spacing, chan, vol) = unpack('<BBBHB8x', info) print " Band: %02x = %s" % (band, bandstr[band]) print " Deemphasis: %02x = %s" % (deemph, dempstr[deemph]) print " Spacing: %02x = %s" % (spacing,spacestr[spacing]) print " Channel: %.3d" % chan print " Volume: %02d" % vol try: freq = calc_freq(band, spacing, chan) print " Freqency=%03.02f Mhz (calculated)" % freq except: print "%s: Cannot decode frequency" % name
def set_speed(speed, acceleration, deceleration=None): """Set the speed of the vial spinner Args: speed (int): The permille to spin the vial at (-1000 to 1000) acceleration: The acceleration in units/s^2 deceleration: The deceleration in units/s^2 Default acceleration """ if deceleration is None: deceleration = acceleration if not (-1000 <= speed <= 1000): raise ValueError( f'{speed} is outside the permitted range (-1000 to 1000)') speed = speed.to_bytes(2, byteorder='little', signed=True) acceleration = acceleration.to_bytes(2, byteorder='little') deceleration = deceleration.to_bytes(2, byteorder='little') packet = speed + acceleration + deceleration crc16 = Crc('crc-ccitt-false') crc16.update(packet) packet += crc16.crcValue.to_bytes(2, byteorder='little') ser = serial.Serial() ser.baudrate = 115200 ser.port = port ser.timeout = 0.1 ser.dtr = None with ser as com: com.write(b'!' + packet) line = com.read(1) print(line.decode())
print "Illegal band and/or spacing" sys.exit(1) if modf(chan)[0] != 0.0: print "Illegal freq/spacing combo" sys.exit(2) chan = int(chan) # First create the data without the checksum, note that we specify # little-endianness for multi-byte values. t = pack('<BBBHB8x', band, demphasis, spacing, chan, volume) # Calculate and append a crc-16 checksum crc16 = Crc('crc-16') crc16.update(t) t = t + pack('<H', crc16.crcValue) # # Simply create a hex file with the concatenation of two tuning structures (t) # and optionally one manufacturing structure, then write the result. # eeprom = t + t if manuf: eeprom = eeprom + manuf_record(sn, ts, campaign) hexfile = IntelHex() hexfile.puts(0, eeprom)
class SerialTransceiver(): """Class for transmitting or receiving serial data with verification. Tranmitted serial communication adhere to the following protocol: [ byte0 ] [ byte1 ] [M-bytes] [N-bytes] [end byte] [M_BYTES_IN_COMMAND] [N_BYTES_IN_DATA] [COMMAND] [ DATA ] [ CRC8 ] """ RESERVED_CODES = { 'ID': '?', 'ERROR': '!', 'VERIFIED': '#', 'NOT_VERIFIED': '~', 'CONNECT': '+', 'DISCONNECT': '-', } def __init__(self, config_path, config_option): self.is_configured = False self.is_connected = False self.connected_to = None self._ser = [] self._mode = [] self._port = None self._baud = [] self._timeout = [] self._vpi_mask = [] self.id = [] self._autoconnect = [] self._in_buffer = [] self._out_buffer = [] self._wait_for_ver = [] self._wait_for_data = [] self.crc = Crc('crc-8') # ###### INCOMPLETE ###### # self.configure(config_path, config_option) if self._autoconnect: if TransceiverModes[self._mode] is TransceiverModes.MASTER: pass elif TransceiverModes[self._mode] is TransceiverModes.SLAVE: pass def configure(self, config_path, config_option): """Validate configuration file and extract values for keys.""" config, options = validateConfig(config_path, RequiredConfigFields) if config_option in options: cfg = config[config_option] mode = cfg['OPERATION_MODE'] if mode in TransceiverModes: self._mode = mode LOG.debug('Transceiver operation mode: %s', self._mode) self._port = cfg['PORT'] LOG.debug('Transceiver port: %s', self._port) self._baud = int(cfg['BAUD']) LOG.debug('Transceiver baud rate: %s', self._baud) self._timeout = int(cfg['TIMEOUT']) LOG.debug('Transceiver timeout: %d', self._timeout) search_ids = cfg.getboolean('SEARCH_PID_VID_ID') LOG.debug('Transceiver search for IDs: %s', search_ids) if search_ids: self._target_vid = [] self._target_pid = [] self._target_id = [] if 'TARGET_VID' in cfg: self._target_vid = (cfg['TARGET_VID']).split(',') LOG.debug('Transceiver target VIDs: %s', self._target_vid) if 'TARGET_PID' in cfg: self._target_pid = (cfg['TARGET_PID']).spit(',') LOG.debug('Transceiver target PIDs: %s', self._target_pid) if 'TARGET_ID' in cfg: self._target_id = (cfg['TARGET_ID']).split(',') LOG.debug('Transceiver target IDs: %s', self._target_id) self._vpi_mask = ((1 << 2) * (self._target_vid != []) + (1 << 1) * (self._target_pid != []) + (1 << 0) * (self._target_id != [])) self.id = cfg['SELF_ID'] self._autoconnect = cfg.getboolean('AUTOCONNECT') LOG.debug('Transceiver autoconnect: %s', self._autoconnect) self.is_configured = True else: LOG.warning('Transceiver operation mode `%s` not found.', mode) else: LOG.warning('Configuration option `%s` not found..', config_option) def waitForConnection(self, baud=None): """Block program until serial connection is established.""" temp_ports = self._openPorts(baud) while not self.is_connected: for port in temp_ports: self._findConnectionAttempt() if self.is_connected: self._ser = port self._port = port.name def connect(self, port=None, baud=None): """Connect to specified device or search for compatible devices.""" if self.is_configured and not self.is_connected: port = self._port baud = self._baud if port == 'None' or None: ports = self.findTrxs() port = ports[0] if port is not None: try: self._ser = serial.Serial(port, baud, timeout=self._timeout) self._tx(self.RESERVED_CODES['CONNECT'], self.id) msg, _ = self._listen() if msg[0] is self.RESERVED_CODES['VERIFIED']: LOG.info('Transceiver connected. Port: %s | Baud: %d', port, baud) self._port = port self._baud = baud self.is_connected = True else: del self._ser self._ser = [] except serial.serialutil.SerialException as ex: LOG.warning('Cannot connect - SerialException: %s', ex) else: LOG.debug('Transceiver cannot connect. Port: %s | Baud: %d', port, baud) def disconnect(self): """Close the serial port and unset connected flag.""" self._tx(self.RESERVED_CODES['DISCONNECT']) msg, _ = self._listen() if msg[0] is self.RESERVED_CODES['VERIFIED']: self.is_connected = False del self._ser self._ser = [] def findTrxs(self, baud=None) -> list: """Search ports for a compatible serial transceiver. If a compatible serial is identified through the use of keywords, the port is appended to a list and the baud rate is saved as the baud rate of the caller. If no baud rate is provided, the baud rate parameter of the caller will be used if previously set. """ device_port = [] if baud is None and self._baud != []: baud = self._baud if baud: available_ports = serial.tools.list_ports.comports() for port in available_ports: vpi_check = 0 vid = port.vid pid = port.pid if 0b100 & self._vpi_mask: if vid in self._target_vid: vpi_check = vpi_check | 0b100 if 0b010 & self._vpi_mask: if pid in self._target_pid: vpi_check = vpi_check | 0b010 if (self._vpi_mask & 0b110) == vpi_check: with serial.Serial(port.device, baud, timeout=1) as self._ser: if 0b001 & self._vpi_mask: other_id = self._checkID() if other_id in self._target_id: device_port.append(port.device) self._baud = baud LOG.info( 'Transceiver identified. ID: %s | Port: %s | Baud: %d', other_id, port, baud) else: LOG.info( 'Transceiver rejected. ID: %s | Port: %s | Baud: %d', other_id, port, baud) else: device_port.append(port.device) self._baud = baud LOG.info( 'Transceiver identified. Port: %s | Baud: %d', port, baud) else: LOG.debug( 'Transceiver not identified. Port: %s | Baud: %d', port, baud) else: LOG.warning('Baud rate has not been set.') return device_port def receive(self): """Grab from incoming buffer.""" rx_info = [] if self._in_buffer: rx_info = self._in_buffer.pop(0) return rx_info def transmit(self, command, data=None, wait_for_data=False): """Place on outgoing buffer.""" self._out_buffer.append([command, data, wait_for_data]) def _checkID(self): id_connected_device = [] self.transmit(self.RESERVED_CODES['ID'], self.id, wait_for_data=True) id_response = self._masterCommunication() if id_response[0] is self.RESERVED_CODES['ID']: id_connected_device = id_response[1] return id_connected_device def _findConnectionAttempt(self): """Listen for keyword, transmit keyword, listen for verification.""" command, data, _ = self._rx() if command is self.RESERVED_CODES['ID']: LOG.debug('Identification request from: %s', data) self._tx(self.RESERVED_CODES['ID'], self.id) command, _, _ = self._rx(wait_for_timeout=True) if command is self.RESERVED_CODES['CONNECT']: self.connected_to = data self.is_connected = True def _listen(self): """Master device listens for responses to commands.""" msg = [] command, data, error = self._rx(wait_for_timeout=True) if command and not error: msg = [command, data] LOG.debug('Message received: %s', tuple(msg)) return msg, error def _masterCommunication(self): response = [] if self._out_buffer and not self._wait_for_data: self._talk() msg, error = self._listen() if error: self._reportUnverified() if msg: ver = self._verifyTx(msg[0]) if ver: self._out_buffer.pop(0) if self._wait_for_data: response, error = self._listen() if error: self._reportUnverified() else: self._out_buffer.append(response) return response def _openPorts(self, baud=None): """Open all ports for listening.""" temp_ports = [] if baud is None: baud = self._baud else: self._baud = baud if baud: available_ports = serial.tools.list_ports.comports() for port in available_ports: temp_ports.append(serial.Serial(port.device, baud, timeout=1)) else: LOG.warning('Baud rate has not been set.') return temp_ports def _operation(self): """Coordinate serial transceiver operation.""" if self._autoconnect and not self.is_connected: if TransceiverModes[self._mode] is TransceiverModes.MASTER: self.connect() elif TransceiverModes[self._mode] is TransceiverModes.SLAVE: self.waitForConnection() self._wait_for_data = True elif self.is_connected: # ###### INCOMPLETE ###### # if TransceiverModes[self._mode] is TransceiverModes.MASTER: response = self._masterCommunication() if not response: LOG.warning('Failed to receive response. Disconnecting.') self.disconnect() else: pass elif TransceiverModes[self._mode] is TransceiverModes.SLAVE: received_info, error = self._listen() if received_info: msg = self._in_buffer.pop() self._tx(msg[0], msg[1]) self._in_buffer.append(msg) def _reportUnverified(self): self._tx(self.RESERVED_CODES['NOT_VERIFIED']) def _rx(self, wait_for_timeout=False): """Receive data from device buffer.""" command = [] data = [] error = False attempt_read = False if wait_for_timeout or self._ser.in_waiting: attempt_read = True if attempt_read: num_bytes_command = self._ser.read(1) num_bytes_data = self._ser.read(1) command = self._ser.read(num_bytes_command) if num_bytes_data: data_byte = self._ser.read(num_bytes_data) data = int.from_bytes(data_byte, byteorder=sys.byteorder) else: data_byte = b'' data = [] msg_crc = int.from_bytes(self._ser.read(1)) msg = b''.join( [num_bytes_command, num_bytes_data, command, data_byte]) crc = self.crc.update(msg) if crc.crcValue != msg_crc: error = True return command, data, error def _talk(self): """Master device transmission.""" transmit = self._out_buffer[0] self._tx(transmit[0], transmit[1]) self._wait_for_ver = True LOG.debug('Transmitting: %s', tuple(transmit)) def _tx(self, command: str, data=None): """Place data on device buffer.""" packet = bytearray() num_bytes_command = [len(bytes(command.encode()))] cmd_list = [] for ch in command: cmd_list.append(ord(ch)) if data: d_list = [data] num_bytes_data = [len(bytes(data))] else: d_list = [] num_bytes_data = [0] message = bytes(num_bytes_command + num_bytes_data + cmd_list + d_list) self.crc.update(message) packet = b''.join([message, bytes([self.crc.crcValue])]) self._ser.write(packet) def _verifyTx(self, command): msg = self._out_buffer[0] verified = False if command is self.RESERVED_CODES['VERIFIED']: LOG.debug('Transmission verified: %s', tuple(msg)) verified = True self._wait_for_data = msg[2] self._wait_for_ver = False elif command is self.RESERVED_CODES['NOT_VERIFIED']: LOG.debug('Transmission not verified: %s', tuple(msg)) return verified