import functools import operator from .escaper import escaper from .escaper import unescaper from .eprint import eprint __author__ = "jhart99" __license__ = "MIT" def compute_check(msg): """ Compute the check value for a message AUCTUS messages use a check byte which is simply the XOR of all the values of the message. """ if len(msg) == 0: return int(0).to_bytes(1, 'little') return functools.reduce(operator.xor, msg).to_bytes(1, 'little') def rda_debug_frame(flow, cmd, message): """ Format a raw message into a frame AUCTUS frames are of the form AD 00 XX FF ...message... YY where XX is the length of the message and YY is the check byte Additionally certain bytes in the message are escaped. """ header = int(0xad).to_bytes(1, 'big') msg = flow + cmd + message msglen = len(msg).to_bytes(2, 'big') check = compute_check(msg) return escaper(header + msglen + msg + check) def read_word(addr, seq = 1): """ make a frame to read a word at a memory address this function creates a frame to read the memory from the device suitable for serial transmission. """ flow = bytes([0xff]) command = bytes([0x02]) if isinstance(addr, int): addr = addr.to_bytes(4, 'little') msg = addr + seq.to_bytes(1, 'big') return rda_debug_frame(flow, command, msg) def write_register_int8(addr, msg): """ write to a byte to an internal register this function creates a frame to do some device magic and these frames are used in the preamble and finalizer commands. """ flow = bytes([0xff]) command = bytes([0x84]) msg = addr.to_bytes(4, 'little') + msg.to_bytes(1, 'little') return rda_debug_frame(flow, command, msg) def read_register_int8(addr, seq=1): """ make a frame containing a knock command this function creates a frame that I assume wakes up the device for further commands. """ flow = bytes([0xff]) command = bytes([0x04]) msg = addr.to_bytes(4, 'little') + seq.to_bytes(1, 'big') return rda_debug_frame(flow, command, msg) def write_block(addr, msg): """ make a frame containing a write command this function creates a frame to do write a multiple byte content at a specific memory address. The length need not be a word, but could be 16 bytes or more. """ flow = bytes([0xff]) command = bytes([0x83]) if isinstance(addr, int): addr = addr.to_bytes(4, 'little') msg = addr + msg return rda_debug_frame(flow, command, msg) class RdaFrame: """ Received Frame class This class decodes possible received Frames. """ ack = False check_fail = False seq = 0 length = 0 content = bytes([]) def __init__(self, msg): msg = unescaper(msg) if len(msg) <= 4: if(msg == b'\x11\x13'): self.ack = True else: # impossibly short frame something is wrong. self.check_fail = True return if (msg[-1].to_bytes(1, 'big') != compute_check(msg[3:-1])): self.check_fail = True return self.seq = msg[4] self.length = msg[2] self.content = msg[5:-1] def __repr__(self): return 'packet length {} seq {} content {} ack {} check {}'.format(self.length, self.seq, self.content, self.ack, self.check_fail)