class SLIPMsgParser(MsgParser): """This class is responsible for taking raw serial bytes and searching them for valid SLIP messages. Attributes: crc: CRC calculator. msg: Parsed SLIP message with SLIP bytes extracted. parsedMsg: Valid serial message stored in this variable upon confirmation of valid CRC. """ def __init__(self, config): MsgParser.__init__(self, config) self.crc = crcmod.mkCrcFun(0x107, initCrc=0, xorOut=0, rev=False) # CRC-8 self.crcLength = 1 self.msg = SLIPMsg(256) def parseSerialMsg(self, msgBytes, msgStart): """Searches raw serial data for SLIP messages and then validates message integrity by comparing a computed CRC to the CRC found in the message. Valid messages are then stored for processing. Args: msgBytes: Raw serial data to be parsed. msgStart: Start location to begin looking for serial message in msgBytes data array. """ if len(msgBytes) > 0: # Process serial message self.msg.decodeMsg(msgBytes, msgStart) if self.msg.msgFound == True: # Message start found if self.msg.msgEnd != -1: # entire msg found # Check msg CRC crc = self.crc(self.msg.msg[:-self.crcLength]) if self.msg.msg[-self.crcLength:] == packData( crc, self.crcLength): # CRC matches - valid message #print("CRC matches") self.parsedMsgs.append(self.msg.msg[:-self.crcLength]) return self.msg.msgEnd else: # partial msg found pass else: # No message found pass return len( msgBytes) # all bytes parsed so return length of input message else: return 0 def encodeMsg(self, msgBytes): if msgBytes: # Add CRC crc = self.crc(msgBytes) msgBytes = msgBytes + packData(crc, self.crcLength) self.msg.encodeMsg(msgBytes) return self.msg.slip return msgBytes
def test_bufferTxMsg(self): """Test bufferTxMsg method of SerialComm.""" # Create message parser for testing purposes msg = SLIPMsg(self.nodeParams.config.parseMsgMax) self.serialComm.msgParser.msg = msg # Test that encoded message buffered msgBytes = b'ZYXWVU' assert (len(self.serialComm.radio.txBuffer) == 0 ) # confirm empty tx buffer self.serialComm.bufferTxMsg(msgBytes) encoder = SLIPMsg(256) encoder.encodeMsg(msgBytes) truthMsg = encoder.encoded assert (self.serialComm.radio.txBuffer == truthMsg ) # confirm encoded message placed in tx buffer
class TestSLIPMsg: def setup_method(self, method): self.slipMsg = SLIPMsg(256) self.truthCRC = packData(self.slipMsg.crc(testMsg), self.slipMsg.crcLength) pass def test_encodeMsg(self): """Test encodeMsg method of SLIPMsg.""" self.slipMsg.encodeMsg(testMsg) minLength = len(truthSLIPMsg + self.truthCRC) assert(len(self.slipMsg.encoded) >= minLength) # length should be at least length of encoded raw bytes plus crc (could be longer if CRC included reserved bytes) if (len(self.slipMsg.encoded) == minLength): # no reserved bytes in CRC assert(self.slipMsg.encoded == truthSLIPMsg[:-1] + self.truthCRC + truthSLIPMsg[-1:]) else: # CRC contained reserved bytes: assert(self.slipMsg.encoded[:-(self.slipMsg.crcLength+1)] == truthSLIPMsg[:-1]) # skip over CRC assert(self.slipMsg.encoded[-1] == truthSLIPMsg[-1]) def test_parseMsg(self): """Test parseMsg method of SLIPMsg.""" self.slipMsg.encodeMsg(testMsg) # encode messaging for parsing # Parse message from encoded message parsedMsg = self.slipMsg.parseMsg(self.slipMsg.encoded, 0) assert(parsedMsg == testMsg) # Parse message with surrounding bytes inputMsg = b'9876' + self.slipMsg.encoded + b'1234' parsedMsg = self.slipMsg.parseMsg(inputMsg, 0) assert(parsedMsg == testMsg) # Parse partial message self.slipMsg = SLIPMsg(256) self.slipMsg.encodeMsg(testMsg) self.slipMsg.parseMsg(self.slipMsg.encoded[:-1], 0) assert(self.slipMsg.msgEnd == -1) # message end not found parsedMsg = self.slipMsg.parseMsg(self.slipMsg.encoded[-1:], 0) # parse remaining message assert(parsedMsg == testMsg) # verify message contents assert(len(parsedMsg) == len(testMsg)) # verify message length # Test parsing partial message in middle of escape sequence self.slipMsg = SLIPMsg(256) msg = b'123' + SLIP_ESC + b'456' self.slipMsg.encodeMsg(msg) self.slipMsg.parseMsg(self.slipMsg.encoded[0:4], 0) # length prior to escape sequence msgLen = self.slipMsg.msgLength self.slipMsg.parseMsg(self.slipMsg.encoded[4:5],0) # parse SLIP_ESC assert(msgLen == self.slipMsg.msgLength) # message length should be unchanged until entire escape sequence read self.slipMsg.parseMsg(self.slipMsg.encoded[5:6], 0) # read entire escape sequence assert(self.slipMsg.msgLength == msgLen + 1) parsedMsg = self.slipMsg.parseMsg(self.slipMsg.encoded[6:], 0) # test successful parsing of remainder of message assert(parsedMsg == msg) # verify message contents assert(len(parsedMsg) == len(msg)) # verify message length
def test_parseSerialMsg(self): """Test parseSerialMessage method of SLIPMsgParser.""" # Check rejection of message with invalid CRC self.msgParser.parseSerialMsg(truthSLIPMsg, 0) assert (self.msgParser.msg.msgFound == True) # slip msg found assert (self.msgParser.msg.msgEnd != 1) # message end found assert (self.msgParser.parsedMsgs == []) # message rejected # Check acceptance of message with valid CRC crc = self.msgParser.msg.crc(testMsg) slipMsg = SLIPMsg(256) slipMsg.encodeMsg(testMsg) self.msgParser.parseSerialMsg(slipMsg.encoded, 0) assert (self.msgParser.msg.msgFound == True) # slip msg found assert (self.msgParser.msg.msgEnd != 1) # message end found assert (self.msgParser.parsedMsgs[0] == testMsg) # message accepted # Check that proper message end position is returned self.msgParser.parsedMsgs = [] paddedMsg = slipMsg.encoded + b'989898' msgEnd = self.msgParser.parseSerialMsg(paddedMsg, 0) assert (self.msgParser.parsedMsgs[0] == testMsg) assert (msgEnd == len(slipMsg.encoded) - 1)
class TestSLIPMsg: def setup_method(self, method): self.slipMsg = SLIPMsg(256) pass def test_encodeMsg(self): """Test encodeMsg method of SLIPMsg.""" self.slipMsg.encodeMsg(testMsg) assert (self.slipMsg.slip == truthSLIPMsg) pass def test_decodeMsg(self): """Test decodeMsg method of SLIPMsg. Will also test decodeMsgContents.""" # Test clearing of partial message self.slipMsg = SLIPMsg(256) self.slipMsg.msgFound = True self.slipMsg.msg = b'123' self.slipMsg.msgEnd = 5 self.slipMsg.msgLength = 10 self.slipMsg.decodeMsg(b'12345', 0) assert (self.slipMsg.msgFound == False) assert (self.slipMsg.msg == b'') assert (self.slipMsg.msgLength == 0) assert (self.slipMsg.msgEnd == -1) # Test decoding entire message contents self.slipMsg = SLIPMsg(256) self.slipMsg.encodeMsg(testMsg) assert (self.slipMsg.msgEnd == -1) self.slipMsg.decodeMsg(self.slipMsg.slip, 0) assert (self.slipMsg.msg == testMsg) # verify message contents assert (self.slipMsg.msgLength == len(testMsg) ) # verify message length assert (self.slipMsg.msgEnd == len(truthSLIPMsg) - 1 ) # verify message end location # Test decoding partial message self.slipMsg = SLIPMsg(256) self.slipMsg.encodeMsg(testMsg) self.slipMsg.decodeMsg(self.slipMsg.slip[:-1], 0) assert (self.slipMsg.msgEnd == -1) # message end not found self.slipMsg.decodeMsg(self.slipMsg.slip[-1:], 0) # parse remaining message assert (self.slipMsg.msg == testMsg) # verify message contents assert (self.slipMsg.msgLength == len(testMsg) ) # verify message length # Test decoding partial message in middle of escape sequence self.slipMsg = SLIPMsg(256) msg = b'123' + SLIP_ESC + b'456' self.slipMsg.encodeMsg(msg) self.slipMsg.decodeMsg(self.slipMsg.slip[0:4], 0) # length prior to escape sequence msgLen = self.slipMsg.msgLength self.slipMsg.decodeMsg(self.slipMsg.slip[4:5], 0) # parse SLIP_ESC assert ( msgLen == self.slipMsg.msgLength ) # message length should be unchanged until entire escape sequence read self.slipMsg.decodeMsg(self.slipMsg.slip[5:6], 0) # read entire escape sequence assert (self.slipMsg.msgLength == msgLen + 1) self.slipMsg.decodeMsg( self.slipMsg.slip[6:], 0) # test successful parsing of remainder of message assert (self.slipMsg.msg == msg) # verify message contents assert (self.slipMsg.msgLength == len(msg)) # verify message length
def test_encodeMsg(self): """Test encodeMsg method of SLIPMsgParser.""" slipMsg = SLIPMsg(256) slipMsg.encodeMsg(testMsg) encodedMsg = self.msgParser.encodeMsg(testMsg) assert (encodedMsg == slipMsg.encoded)