def receive_message(self, timeout_ms=500): """ Receives a message and stops either when the message is complete or when the allotted time expires, whichever comes first. """ self._calculate_deadline(timeout_ms=timeout_ms) if self._hook_message_signature() is False: logging.info("Failed to obtain message signature " "within allotted time") return False logging.debug("Got message signature.") header = self._receive_buffer(size=self._header.buffer_length) if header == []: logging.info("Failed to obtain message header " "within allotted time") return False logging.debug("Got message header.") self._header.unpack(packed_data="".join(header)) payload_len = \ self._header.message_len - \ self._signature.buffer_length - \ self._header.buffer_length - \ self._checksum.buffer_length if payload_len is not 0: self._payload = self._receive_buffer(size=payload_len) if self._payload == []: logging.info("Failed to obtain message payload " "within allotted time") return False logging.debug("Got message payload.") for _ in self._payload: logging.debug("payload {0}".format(binascii.hexlify(_))) else: logging.debug("Got empty message without payload.") self._payload = [] checksum = self._receive_buffer(size=self._checksum.buffer_length) if checksum == []: logging.info("Failed to obtain message checksum " "within allotted time") return False logging.debug("Got message checksum.") self._checksum.unpack(packed_data="".join(checksum)) calculated_checksum = \ MappedBuffer.calculate_checksum( [self._SIGNATURE[0], self._SIGNATURE[1], self._header.buffer_checksum, MappedBuffer.calculate_checksum(self._payload)]) if self._checksum.checksum == calculated_checksum: logging.info("RX: id = {0}\t\tpayload = {1}".format( self._header.message_id, self._payload)) logging.debug("Checksum verification successful.") return True else: logging.info("Checksum verification failed:\n" + "Received = {0}\n".format(self._checksum.checksum) + "Calculated = {0}".format(calculated_checksum)) return False
def receive_message(self, timeout_ms=500): """ Receives a message and stops either when the message is complete or when the allotted time expires, whichever comes first. """ self._calculate_deadline(timeout_ms=timeout_ms) if self._hook_message_signature() is False: logging.info("Failed to obtain message signature " "within allotted time") return False logging.debug("Got message signature.") header = self._receive_buffer(size=self._header.buffer_length) if header == []: logging.info("Failed to obtain message header " "within allotted time") return False logging.debug("Got message header.") self._header.unpack(packed_data="".join(header)) payload_len = \ self._header.message_len - \ self._signature.buffer_length - \ self._header.buffer_length - \ self._checksum.buffer_length if payload_len is not 0: self._payload = self._receive_buffer(size=payload_len) if self._payload == []: logging.info("Failed to obtain message payload " "within allotted time") return False logging.debug("Got message payload.") for _ in self._payload: logging.debug("payload {0}".format(binascii.hexlify(_))) else: logging.debug("Got empty message without payload.") self._payload = [] checksum = self._receive_buffer(size=self._checksum.buffer_length) if checksum == []: logging.info("Failed to obtain message checksum " "within allotted time") return False logging.debug("Got message checksum.") self._checksum.unpack(packed_data="".join(checksum)) calculated_checksum = \ MappedBuffer.calculate_checksum( [self._SIGNATURE[0], self._SIGNATURE[1], self._header.buffer_checksum, MappedBuffer.calculate_checksum(self._payload)]) if self._checksum.checksum == calculated_checksum: logging.info("RX: id = {0}\t\tpayload = {1}". format(self._header.message_id, self._payload)) logging.debug("Checksum verification successful.") return True else: logging.info("Checksum verification failed:\n" + "Received = {0}\n".format(self._checksum.checksum) + "Calculated = {0}".format(calculated_checksum)) return False
def __init__(self): """ Abstraction of the HW layer. """ self._signature = MappedBuffer(fields=( {"first_byte": "B"}, {"second_byte": "B"}, )) self._signature.first_byte = ord(self._SIGNATURE[0]) self._signature.second_byte = ord(self._SIGNATURE[1]) self._header = MappedBuffer(fields=( {"message_len": "B"}, {"message_id": "B"}, )) self._payload = [] self._checksum = MappedBuffer(fields=( {"checksum": "B"}, )) self._deadline = None
def encode(self, data): """ Generates the byte sequence for a USB keyboard command. """ # pylint: disable=exec-used # pylint: disable=unused-argument buf = MappedBuffer(fields=({"byte_0": "B"}, {"byte_1": "B"}, {"byte_2": "B"}, {"byte_3": "B"}, {"byte_4": "B"}, {"byte_5": "B"}, {"byte_6": "B"}, {"byte_7": "B"}, )) for index in range(0, 8): exec("buf.byte_" + str(index) + " = data['buffer'][" + str(index) + "]") state = CMD_NEW_KEYBOARD_DATA return self.pack(command_id=state, data=buf.pack())
def __init__(self): """ Abstraction of the HW layer. """ self._signature = MappedBuffer(fields=( { "first_byte": "B" }, { "second_byte": "B" }, )) self._signature.first_byte = ord(self._SIGNATURE[0]) self._signature.second_byte = ord(self._SIGNATURE[1]) self._header = MappedBuffer(fields=( { "message_len": "B" }, { "message_id": "B" }, )) self._payload = [] self._checksum = MappedBuffer(fields=({"checksum": "B"}, )) self._deadline = None
def encode(self, data): """ Generates the byte sequence for a USB keyboard command. """ # pylint: disable=exec-used # pylint: disable=unused-argument buf = MappedBuffer(fields=( { "byte_0": "B" }, { "byte_1": "B" }, { "byte_2": "B" }, { "byte_3": "B" }, { "byte_4": "B" }, { "byte_5": "B" }, { "byte_6": "B" }, { "byte_7": "B" }, )) for index in range(0, 8): exec("buf.byte_" + str(index) + " = data['buffer'][" + str(index) + "]") state = CMD_NEW_KEYBOARD_DATA return self.pack(command_id=state, data=buf.pack())
def transmit_message(self, payload=""): """ Transmits a message """ self._message_id = (self._message_id + 1) % 256 self._header.message_len = \ self._signature.buffer_length + \ self._header.buffer_length + \ len(payload) + \ self._checksum.buffer_length self._header.message_id = self._message_id message = self._signature.pack() + self._header.pack() + payload self._checksum.checksum = MappedBuffer.calculate_checksum(message) message = message + self._checksum.pack() logging.info("TX {0}".format(binascii.hexlify(message))) for character in message: self._write_char(character) self._flush()
def transmit_message(self, payload=""): """ Transmits a message """ self._message_id = (self._message_id + 1) % 256 self._header.message_len = \ self._signature.buffer_length + \ self._header.buffer_length + \ len(payload) + \ self._checksum.buffer_length self._header.message_id = self._message_id message = self._signature.pack() + self._header.pack() + payload self._checksum.checksum = MappedBuffer.calculate_checksum(message) message = message + self._checksum.pack() logging.info("TX {0}".format(binascii.hexlify(message))) for character in message: #check for python version if sys.version_info[0] == 2: self._write_char(character) elif sys.version_info[0] == 3: self._write_char(chr(character).encode("Latin-1")) self._flush()
class Phys(object): """ Physical Connection Object: interacts with the Arduino device. """ # pylint: disable=abstract-class-not-used __metaclass__ = abc.ABCMeta _imports = {} _arguments = {} _message_id = 0 _SIGNATURE = ['\xaa', '\x55'] def __init__(self): """ Abstraction of the HW layer. """ self._signature = MappedBuffer(fields=( {"first_byte": "B"}, {"second_byte": "B"}, )) self._signature.first_byte = ord(self._SIGNATURE[0]) self._signature.second_byte = ord(self._SIGNATURE[1]) self._header = MappedBuffer(fields=( {"message_len": "B"}, {"message_id": "B"}, )) self._payload = [] self._checksum = MappedBuffer(fields=( {"checksum": "B"}, )) self._deadline = None def new(self): """ Prepares for transmitting a new message. """ self._payload = [] self._message_id += 1 @classmethod def prepare_arguments(cls): """ Function providing a list of arguments configurations. Each entry will be loaded into ArgumentParser.add_argument The default dictionary - cls._arguments - is empty. """ return cls._arguments.values(), cls._imports @abc.abstractmethod def _test_connection(self): """ Checks that the connection is established and functioning. """ @abc.abstractmethod def _chars_available(self): """ Returns the number of charaters that can be read. """ @abc.abstractmethod def _read_char(self): """ Read a char from the physical layer. """ @abc.abstractmethod def _write_char(self, character): """ Write a char to the physical layer. """ @abc.abstractmethod def _flush(self): """ Waits untill all the data is written. """ @abc.abstractmethod def close(self): """ Terminates the connection. """ def _calculate_deadline(self, timeout_ms): """ Defines the deadline for the completion of the current TX or RX operation. """ self._deadline = datetime.datetime.now() + \ datetime.timedelta(milliseconds=timeout_ms) def _read_char_with_timeout(self): """ As the name suggests, either a chracter is received from the Arduino, or the function will wait till the timeout expires. """ while datetime.datetime.now() < self._deadline: if self._chars_available() > 0: return self._read_char() return False def _hook_message_signature(self): """ Tries to identify the message signature, till either it finds it, or the allotted time runs out. """ while True: new_char = self._read_char_with_timeout() while new_char == self._SIGNATURE[0]: new_char = self._read_char_with_timeout() if new_char == self._SIGNATURE[1]: return True if new_char is False: return False def _receive_buffer(self, size): """ Reads and stores "size" characters. """ receive_buffer = [] while datetime.datetime.now() < self._deadline: if self._chars_available() > 0: receive_buffer.append(self._read_char()) if len(receive_buffer) == size: return receive_buffer print "Timeout" return [] def receive_message(self, timeout_ms=500): """ Receives a message and stops either when the message is complete or when the allotted time expires, whichever comes first. """ self._calculate_deadline(timeout_ms=timeout_ms) if self._hook_message_signature() is False: logging.info("Failed to obtain message signature " "within allotted time") return False logging.debug("Got message signature.") header = self._receive_buffer(size=self._header.buffer_length) if header == []: logging.info("Failed to obtain message header " "within allotted time") return False logging.debug("Got message header.") self._header.unpack(packed_data="".join(header)) payload_len = \ self._header.message_len - \ self._signature.buffer_length - \ self._header.buffer_length - \ self._checksum.buffer_length if payload_len is not 0: self._payload = self._receive_buffer(size=payload_len) if self._payload == []: logging.info("Failed to obtain message payload " "within allotted time") return False logging.debug("Got message payload.") for _ in self._payload: logging.debug("payload {0}".format(binascii.hexlify(_))) else: logging.debug("Got empty message without payload.") self._payload = [] checksum = self._receive_buffer(size=self._checksum.buffer_length) if checksum == []: logging.info("Failed to obtain message checksum " "within allotted time") return False logging.debug("Got message checksum.") self._checksum.unpack(packed_data="".join(checksum)) calculated_checksum = \ MappedBuffer.calculate_checksum( [self._SIGNATURE[0], self._SIGNATURE[1], self._header.buffer_checksum, MappedBuffer.calculate_checksum(self._payload)]) if self._checksum.checksum == calculated_checksum: logging.info("RX: id = {0}\t\tpayload = {1}". format(self._header.message_id, self._payload)) logging.debug("Checksum verification successful.") return True else: logging.info("Checksum verification failed:\n" + "Received = {0}\n".format(self._checksum.checksum) + "Calculated = {0}".format(calculated_checksum)) return False def transmit_message(self, payload=""): """ Transmits a message """ self._message_id = (self._message_id + 1) % 256 self._header.message_len = \ self._signature.buffer_length + \ self._header.buffer_length + \ len(payload) + \ self._checksum.buffer_length self._header.message_id = self._message_id message = self._signature.pack() + self._header.pack() + payload self._checksum.checksum = MappedBuffer.calculate_checksum(message) message = message + self._checksum.pack() logging.info("TX {0}".format(binascii.hexlify(message))) for character in message: self._write_char(character) self._flush() def ping(self): """ Sends an empty message to the device and waits for an ACK to arrive before the timeout. """ if self._test_connection() is False: return False self.transmit_message() return self.receive_message()
class Phys(with_metaclass(abc.ABCMeta, object)): """ Physical Connection Object: interacts with the Arduino device. """ _imports = {} _arguments = {} _message_id = 0 _SIGNATURE = ['\xaa', '\x55'] def __init__(self): """ Abstraction of the HW layer. """ self._signature = MappedBuffer(fields=( { "first_byte": "B" }, { "second_byte": "B" }, )) self._signature.first_byte = ord(self._SIGNATURE[0]) self._signature.second_byte = ord(self._SIGNATURE[1]) self._header = MappedBuffer(fields=( { "message_len": "B" }, { "message_id": "B" }, )) self._payload = [] self._checksum = MappedBuffer(fields=({"checksum": "B"}, )) self._deadline = None def new(self): """ Prepares for transmitting a new message. """ self._payload = [] self._message_id += 1 @classmethod def prepare_arguments(cls): """ Function providing a list of arguments configurations. Each entry will be loaded into ArgumentParser.add_argument The default dictionary - cls._arguments - is empty. """ return list(cls._arguments.values()), cls._imports @abc.abstractmethod def _test_connection(self): """ Checks that the connection is established and functioning. """ @abc.abstractmethod def _chars_available(self): """ Returns the number of charaters that can be read. """ @abc.abstractmethod def _read_char(self): """ Read a char from the physical layer. """ @abc.abstractmethod def _write_char(self, character): """ Write a char to the physical layer. """ @abc.abstractmethod def _flush(self): """ Waits untill all the data is written. """ @abc.abstractmethod def close(self): """ Terminates the connection. """ def _calculate_deadline(self, timeout_ms): """ Defines the deadline for the completion of the current TX or RX operation. """ self._deadline = datetime.datetime.now() + \ datetime.timedelta(milliseconds=timeout_ms) def _read_char_with_timeout(self): """ As the name suggests, either a chracter is received from the Arduino, or the function will wait till the timeout expires. """ while datetime.datetime.now() < self._deadline: if self._chars_available() > 0: return self._read_char() return False def _hook_message_signature(self): """ Tries to identify the message signature, till either it finds it, or the allotted time runs out. """ while True: new_char = self._read_char_with_timeout() while new_char == self._SIGNATURE[0]: new_char = self._read_char_with_timeout() if new_char == self._SIGNATURE[1]: return True if new_char is False: return False def _receive_buffer(self, size): """ Reads and stores "size" characters. """ receive_buffer = [] while datetime.datetime.now() < self._deadline: if self._chars_available() > 0: receive_buffer.append(self._read_char()) if len(receive_buffer) == size: return receive_buffer logging.info("phys._receive_buffer timeout") return [] def receive_message(self, timeout_ms=500): """ Receives a message and stops either when the message is complete or when the allotted time expires, whichever comes first. """ self._calculate_deadline(timeout_ms=timeout_ms) if self._hook_message_signature() is False: logging.info("Failed to obtain message signature " "within allotted time") return False logging.debug("Got message signature.") header = self._receive_buffer(size=self._header.buffer_length) if header == []: logging.info("Failed to obtain message header " "within allotted time") return False logging.debug("Got message header.") self._header.unpack(packed_data="".join(header)) payload_len = \ self._header.message_len - \ self._signature.buffer_length - \ self._header.buffer_length - \ self._checksum.buffer_length if payload_len is not 0: self._payload = self._receive_buffer(size=payload_len) if self._payload == []: logging.info("Failed to obtain message payload " "within allotted time") return False logging.debug("Got message payload.") for _ in self._payload: logging.debug("payload {0}".format(binascii.hexlify(_))) else: logging.debug("Got empty message without payload.") self._payload = [] checksum = self._receive_buffer(size=self._checksum.buffer_length) if checksum == []: logging.info("Failed to obtain message checksum " "within allotted time") return False logging.debug("Got message checksum.") self._checksum.unpack(packed_data="".join(checksum)) calculated_checksum = \ MappedBuffer.calculate_checksum( [self._SIGNATURE[0], self._SIGNATURE[1], self._header.buffer_checksum, MappedBuffer.calculate_checksum(self._payload)]) if self._checksum.checksum == calculated_checksum: logging.info("RX: id = {0}\t\tpayload = {1}".format( self._header.message_id, self._payload)) logging.debug("Checksum verification successful.") return True else: logging.info("Checksum verification failed:\n" + "Received = {0}\n".format(self._checksum.checksum) + "Calculated = {0}".format(calculated_checksum)) return False def transmit_message(self, payload=""): """ Transmits a message """ self._message_id = (self._message_id + 1) % 256 self._header.message_len = \ self._signature.buffer_length + \ self._header.buffer_length + \ len(payload) + \ self._checksum.buffer_length self._header.message_id = self._message_id message = self._signature.pack() + self._header.pack() + payload self._checksum.checksum = MappedBuffer.calculate_checksum(message) message = message + self._checksum.pack() logging.info("TX {0}".format(binascii.hexlify(message))) for character in message: #check for python version if sys.version_info[0] == 2: self._write_char(character) elif sys.version_info[0] == 3: self._write_char(chr(character).encode("Latin-1")) self._flush() def ping(self): """ Sends an empty message to the device and waits for an ACK to arrive before the timeout. """ if self._test_connection() is False: return False self.transmit_message() return self.receive_message()