Example #1
0
 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
Example #2
0
    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
Example #3
0
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')
Example #4
0
 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)
Example #5
0
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
Example #6
0
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
Example #7
0
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())
Example #8
0
	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)
Example #9
0
    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)
Example #10
0
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