class Telemetry: """`Telemetry` is a library for simple data transfer between devices on different data protocols. This version using Serial interface. Parameters ---------- port : String Port name of the serial interface. baudrate : Integer Serial BAUDRATE. items : An array of the dicts Telemetry item. Contains: `id`, `type`, `data`, `func`, `info` keys. stopbits : Integer Number of stopbits. Attributes ---------- ser : Object Serial interface object. items : List of the dicts. Telemetry items. """ # Types of a data ONE_BYTE = 1 TWO_BYTE = 2 FOUR_BYTE = 4 ARRAY = 5 FLOAT = 6 # Start identifier START = 33000 # Sign identifiers MINUS = 33001 PLUS = 33002 def __init__(self, port, baudrate, items, stopbits=STOPBITS_TWO): self.ser = Serial(port, baudrate, stopbits=stopbits) self.items = items def close(self): """ Close Serial connection. """ self.ser.close() def _read(self, bytes=1): """Reading data unsing Serial interface. For internal use only. Parameters ---------- bytes : Integer Number of bytes the data. Returns ------- type Byte, Integer, N-bytes data. """ return int.from_bytes(self.ser._read(bytes), byteorder='big') def _read_signed(self, bytes=1): """Transforming negative data to positive. For internal use only. Parameters ---------- bytes : Integer Number of bytes the data. Returns ------- type Byte, Integer, N-bytes data. """ # Reading two-byte "sign" identifier sign = self._read(2) # Reading n-bytes data res = self._read(bytes) # If sign is "MINUS" transform received data if sign == self.MINUS: res *= -1 return res def _write(self, data): """Writing data using Serial interface. Parameters ---------- data : Whatever you want :) Transmitting data. """ self.ser._write(struct.pack('>B', data)) def receive_float(self): """Receiving float digit. Returns ------- type Float Received float digit. """ # Receiving raw four-byte data raw_data = self._read(4) # Getting sign from received raw digit sign = raw_data // (2 ** 31) & 0xFF # Getting exponenta from received raw digit exponenta = raw_data // (2 ** 23) & 0xFF # Getting mantissa from received raw digit mantissa = raw_data & 0x7FFFFF # Calculating float digit and return it a = mantissa / (2 ** 23) return ((-1) ** sign) * (1 + a) * (2 ** (exponenta - 127)) def receive_array(self): """Receiving an array. Returns ------- type Array Received an array. """ # Receiving an array length len = self._read() # Receiving an array type type = self._read() # Initialize an array data variable arr = None if type == self.FLOAT: # Receiving and returning an array data arr = [self.receive_float(type) for _ in range(len)] # Receiving and returning an array data arr = [self._read_signed(type) for _ in range(len)] # Return dict with all data information return { 'data': arr, 'type': type, 'length': len } def transmit_array(self, arr, type, len): """Transmitting an array. Parameters ---------- arr : Array Data array type : Integer An array items type (one-byte, two-byte, etc...) len : Integer An array length """ # Transmitting an array length self._write(len) # Transmitting an array type self._write(type) # Transmitting an array items for item in arr: self._write(item) def data_transmit(self, item): """Transmitting Telemetry data. Parameters ---------- item : Dict, Telemetry item that will be transmit. Contains: `type`, `id`, `data`, `info` keys. """ # Transmitting "start" identifier self._write(self.START) # Transmitting data type identifier self._write(item.get('type')) # Getting callback function from telemetry item and call it func = item.get('func') callback = func() # Check data type and use a special function if a type is "float" or "array" if item.get('type') == self.FLOAT: self._write(callback) elif item.get('type') == self.ARRAY: self.transmit_array(callback.get('data'), callback.get('type'), callback.get('len')) else: self._write(callback) def stream_data(self): """ Listening the Rx wire and transmitting data on request. """ # Receiving data identifier id = self._read(2) for item in self.items: # Find telemetry item with right identifier if item.get('id') == id: # Transmitting the data self.data_transmit(item) def get_data(self, id): """Getting telemetry data after transmitting identifier. Parameters ---------- id : Integer Data identifier. Returns ------- type Dict Telemetry item that has been received. Contains: `type`, `data`, `info` keys. """ # Sending identifier self._write(id) # Receiving start identifier start = self._read(2) if start != self.START: return None # Receiving type identifier type = self._read() # Initialize variable for array information arr_info = None # Receiving data if type == self.ARRAY: data = self.receive_array() # Making array info dict arr_info = { 'type': data.get('type'), 'length': data.get('length') } # Reinitialize array data data = data.get('data') elif type == self.FLOAT: data = self.receive_float() else: data = self._read_signed(type) # Returning dict with all received information return { 'data': data, 'type': type, 'info': arr_info }