def test_processMsgs(self): """Test processMsgs method of SerialComm.""" # Create message parser for testing purposes msg = SLIPMsg(self.nodeParams.config.parseMsgMax) self.serialComm.msgParser.msg = msg # Create and send test messages nodeStatus = [NodeState(node + 1) for node in range(5)] clock = FormationClock() cmdId1 = NodeCmds['NoOp'] # No op command cmdMsg1 = Command(cmdId1, None, [cmdId1, 1, 200]).serialize() cmdId2 = NodeCmds['GCSCmd'] # GCS command cmdMsg2 = Command(cmdId2, { 'destId': 1, 'mode': 2 }, [cmdId2, 1, 201]).serialize() self.serialComm.sendMsg(cmdMsg1) self.serialComm.sendMsg(cmdMsg2) time.sleep(0.1) # Test processing self.serialComm.processMsgs( args={ 'logFile': [], 'nav': [], 'nodeStatus': nodeStatus, 'clock': clock, 'comm': self.serialComm }) assert (cmdId1 in self.serialComm.cmdQueue ) # Test that correct message added to cmdQueue assert (cmdId2 in self.serialComm.cmdQueue ) # Test that correct message added to cmdQueue
def test_serialize(self): """Test serialization of command.""" command = Command(self.cmdId, self.cmdData, self.header) serMsg = command.serialize(0) assert(len(serMsg) == (calcsize(headers[CmdDict[self.cmdId].header]['format']) + calcsize(CmdDict[self.cmdId].packFormat))) # serial message the correct length
def getBlockTxPacket(self): # Check for block data #if (self.blockTxData == None): # no data to send # return None # Create mesh packet from next chunk of block data if (self.blockTx.dataLoc >= len(self.blockTx.data)): # no packets remaining return None elif (len(self.blockTx.data) > self.blockTx.dataLoc + self.nodeParams.config.commConfig['blockTxPacketSize']): newBlockTxDataLoc = self.blockTx.dataLoc + int(self.nodeParams.config.commConfig['blockTxPacketSize']) blockDataChunk = self.blockTx.data[self.blockTx.dataLoc:newBlockTxDataLoc] self.blockTx.dataLoc = newBlockTxDataLoc else: # send remainder of data block blockDataChunk = self.blockTx.data[self.blockTx.dataLoc:] self.blockTx.dataLoc = len(self.blockTx.data) # reached end of data block # Generate new packet command self.blockTx.packetNum += 1 blockDataCmd = Command(TDMACmds['BlockData'], {'blockReqId': self.blockTx.reqId, 'packetNum': self.blockTx.packetNum, 'dataLength': len(blockDataChunk), 'data': blockDataChunk}, [TDMACmds['BlockData'], self.nodeParams.config.nodeId]) blockDataSerialized = self.tdmaCmdParser.encodeMsg(blockDataCmd.serialize(self.nodeParams.clock.getTime())) blockPacket = self.createMeshPacket(self.blockTx.destId, b'', blockDataSerialized, self.nodeParams.config.nodeId, BLOCK_TX_MSG) print("Node " + str(self.nodeParams.config.nodeId) + " - Sending block transmit packet", self.blockTx.packetNum, ". Length-", len(blockPacket)) return blockPacket
def initMesh(self, currentTime=time.time()): """Initialize node mesh networks.""" # Create tdma comm messages flooredStartTime = math.floor(self.nodeParams.commStartTime) self.tdmaCmds[TDMACmds['MeshStatus']] = Command( TDMACmds['MeshStatus'], { 'commStartTimeSec': int(flooredStartTime), 'status': self.nodeParams.tdmaStatus }, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId], self.nodeParams.config.commConfig['statusTxInterval']) self.tdmaCmds[TDMACmds['LinkStatus']] = Command( TDMACmds['LinkStatus'], { 'linkStatus': self.nodeParams.linkStatus, 'nodeId': self.nodeParams.config.nodeId }, [TDMACmds['LinkStatus'], self.nodeParams.config.nodeId], self.nodeParams.config.commConfig['linksTxInterval']) if self.nodeParams.config.nodeId != 0: # stop ground node from broadcasting time offset self.tdmaCmds[TDMACmds['TimeOffset']] = Command( TDMACmds['TimeOffset'], { 'nodeStatus': self.nodeParams.nodeStatus[self.nodeParams.config.nodeId - 1] }, [TDMACmds['TimeOffset'], self.nodeParams.config.nodeId], self.nodeParams.config.commConfig['offsetTxInterval']) # Determine where in frame mesh network currently is self.syncTDMAFrame(currentTime) self.inited = True print("Node " + str(self.nodeParams.config.nodeId) + " - Initializing comm")
def sendBlock(self): if self.dataBlock: if len(self.dataBlock[self.dataBlockPos:] ) > self.nodeParams.config.commConfig[ 'maxBlockTransferSize']: # buffer portion of data block blockDataCmd = Command( TDMACmds['BlockData'], { 'data': self.dataBlock[self.dataBlockPos:self.dataBlockPos + self.nodeParams.config. commConfig['maxBlockTransferSize']] }, [TDMACmds['BlockData'], self.nodeParams.config.nodeId ]).serialize(self.nodeParams.clock.getTime()) self.dataBlockPos += self.nodeParams.config.commConfig[ 'maxBlockTransferSize'] else: # send entire data block blockDataCmd = Command( TDMACmds['BlockData'], { 'data': self.dataBlock[self.dataBlockPos:] }, [TDMACmds['BlockData'], self.nodeParams.config.nodeId ]).serialize(self.nodeParams.clock.getTime()) self.clearDataBlock() # clear stored data block self.blockTxStatus[ 'blockTxComplete'] = True # end block transfer # Send block data self.radio.bufferTxMsg(blockDataCmd) self.radio.bufferTxMsg(SLIP_END_TDMA) self.radio.sendBuffer( self.nodeParams.config.commConfig['maxBlockTransferSize']) else: # end block transfer - no data to send self.blockTxStatus['blockTxComplete'] = True
def test_processMeshMsgs(self): """Test processMeshMsgs method of TDMAComm.""" commStartTime = int(time.time()) cmd = Command(TDMACmds['MeshStatus'], {'commStartTimeSec': commStartTime, 'status': TDMAStatus.nominal}, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId]) encodedCmd = self.tdmaComm.tdmaCmdParser.encodeMsg(cmd.serialize()) # Verify pre-test conditions assert(self.tdmaComm.commStartTime == None) self.tdmaComm.processMeshMsgs(encodedCmd) assert(self.tdmaComm.commStartTime == commStartTime)
def test_init(self): """Test creation of Command instance.""" # Test creation without header command = Command(self.cmdId, self.cmdData) assert(command.cmdId == self.cmdId) assert(command.cmdData == self.cmdData) # Test creation with header command = Command(self.cmdId, self.cmdData, self.header) assert(isinstance(command.header, dict) == True) # header created as dict assert(len(command.header['header']) == len(self.header)) # header has same number of entries as provided header data
def test_packHeader(self): """Test packHeader method of Command class.""" command = Command(self.cmdId, self.cmdData, self.header) # Test with header header = command.packHeader() assert (header == packHeader(command.header)) # Test without header command.header = [] header = command.packHeader() assert (len(header) == 0)
def test_packBody(self): """Test packBody method of Command class.""" command = Command(self.cmdId, self.cmdData) # Test with serialize method body = command.packBody() assert (len(body) == calcsize(CmdDict[self.cmdId].packFormat)) assert (body == CmdDict[self.cmdId].serialize(command.cmdData, 0)) # Test without serialize method command.serializeMethod = [] body = command.packBody() assert (len(body) == 0)
def test_syncTDMAFrame(self): """Test syncTDMAFrame method of TDMAComm.""" # Setup test conditions testTime = 5.0 self.tdmaComm.rxBufferReadPos = 10 self.tdmaComm.commStartTime = testTime - 0.5*self.tdmaComm.frameLength self.tdmaComm.tdmaCmds[TDMACmds['MeshStatus']] = Command(TDMACmds['MeshStatus'], {'commStartTimeSec': 0.0, 'status': TDMAStatus.blockTx}, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId]) self.tdmaComm.tdmaStatus = TDMAStatus.nominal assert(self.tdmaComm.nodeParams.nodeStatus[self.tdmaComm.nodeParams.config.nodeId-1].timeOffset == 127) # offset at default value # Call method under test self.tdmaComm.syncTDMAFrame(testTime) # Check frame time variables assert(self.tdmaComm.frameTime == 0.5*self.tdmaComm.frameLength) assert(self.tdmaComm.frameStartTime == testTime - self.tdmaComm.frameTime) # Check that TDMA status updated in outgoing MeshStatus message assert(self.tdmaComm.tdmaCmds[TDMACmds['MeshStatus']].cmdData['status'] == TDMAStatus.nominal) # Check that rx buffer position reset assert(self.tdmaComm.rxBufferReadPos == 0) # Verify time offset check assert(self.tdmaComm.nodeParams.nodeStatus[self.tdmaComm.nodeParams.config.nodeId-1].timeOffset != 127) # offset updated
def test_processMsg(self): """Test processMsg method of SerialComm.""" # Create message and test processing nodeStatus = [NodeState(node + 1) for node in range(5)] clock = FormationClock() cmdId = NodeCmds['NoOp'] cmdMsg = Command(cmdId, None, [cmdId, 1, 200]).serialize() assert (self.serialComm.processMsg(cmdMsg, args={ 'logFile': [], 'nav': [], 'nodeStatus': nodeStatus, 'clock': clock, 'comm': self.serialComm }) == True) assert (cmdId in self.serialComm.cmdQueue ) # Test that correct message added to cmdQueue # Confirm proper return when no message processed successfully assert (self.serialComm.processMsg(b'12345', args={ 'logFile': [], 'nav': [], 'nodeStatus': nodeStatus, 'clock': clock, 'comm': self.serialComm }) == False)
def test_rejectedTDMABlockTx(self): """Test rejecting block transmit request.""" # Force init self.tdmaComm.meshInited = True # Start block transmit self.initiateBlockTransmit() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.pending) # "Send" negative response from other node time.sleep(0.01) cmdMsg = Command( TDMACmds['BlockTxRequestResponse'], { 'blockReqID': self.tdmaComm.blockTxStatus['blockReqID'], "accept": False }, [ TDMACmds['BlockTxRequestResponse'], 2, self.nodeParams.get_cmdCounter() ]).serialize(self.nodeParams.clock.getTime()) self.tdmaComm.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeParams.nodeStatus, 'comm': self.tdmaComm, 'clock': self.nodeParams.clock }) self.tdmaComm.frameStartTime += self.nodeParams.config.commConfig[ 'frameLength'] self.tdmaComm.execute(self.tdmaComm.frameStartTime) assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.false ) # request cancelled
def updateBlockTxStatus(self): # Monitor for block transmit end if (self.blockTx.complete or self.nodeParams.clock.getTime() >= self.blockTx.endTime): # block transmit ended if (self.blockTx.srcId == self.nodeParams.config.nodeId): # sender end block tx # Send block transmit end message self.tdmaCmds[TDMACmds['BlockTxRequest']] = Command(TDMACmds['BlockTxRequest'], {'blockReqId': self.blockTx.reqId, 'destId': self.blockTx.destId, 'startTime': self.blockTx.startTime, 'length': self.blockTx.length, 'status': 0}, [TDMACmds['BlockTxRequest'], self.nodeParams.config.nodeId, self.nodeParams.get_cmdCounter()]) # End block transmit self.endBlockTx()
def sendDataBlock(self, dataBlock): """Begins block transfer process.""" # Calculate block tx parameters length = int( ceil( len(dataBlock) / self.nodeParams.config.commConfig['maxBlockTransferSize'])) if length > self.nodeParams.config.commConfig['maxTxBlockSize']: # Too much data to transmit return False startTime = int(self.frameStartTime + self.nodeParams.config.commConfig['frameLength'] * self.nodeParams.config.commConfig['minBlockTxDelay']) # Store data block self.dataBlock = dataBlock # Populate response list self.populateBlockResponseList() # Send block tx request blockReqID = random.randint(1, 255) # just a random "unique" number blockTxCmd = Command(TDMACmds['BlockTxRequest'], { 'blockReqID': blockReqID, 'startTime': startTime, 'length': length }, [ TDMACmds['BlockTxRequest'], self.nodeParams.config.nodeId, self.nodeParams.get_cmdCounter() ]) self.bufferTxMsg(blockTxCmd.serialize(self.nodeParams.clock.getTime())) # Update blockTxStatus self.blockTxStatus['blockReqID'] = blockReqID self.blockTxStatus['startTime'] = startTime self.blockTxStatus['length'] = length self.blockTxStatus['requestTime'] = self.frameStartTime self.blockTxStatus['txNode'] = self.nodeParams.config.nodeId self.blockTxStatus['status'] = TDMABlockTxStatus.pending return True
def test_sendTDMACmds(self): """Test sendTDMACmds method of TDMAComm.""" self.tdmaComm.commStartTime = time.time(); flooredStartTime = math.floor(self.tdmaComm.commStartTime) self.tdmaComm.tdmaCmds.update({TDMACmds['MeshStatus']: Command(TDMACmds['MeshStatus'], {'commStartTimeSec': flooredStartTime, 'status': self.tdmaComm.tdmaStatus}, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId], 0.500)}) # Check command serialized and returned tdmaCmdBytes = self.tdmaComm.sendTDMACmds() assert(len(tdmaCmdBytes) > 0) # Wait for resend time.sleep(0.1) assert(len(self.tdmaComm.sendTDMACmds()) == 0) # should not return anything time.sleep(0.4) assert(len(self.tdmaComm.sendTDMACmds()) > 0) # should return bytes # Confirm non-periodic commands are returned and then removed self.tdmaComm.tdmaCmds = {TDMACmds['MeshStatus']: Command(TDMACmds['MeshStatus'], {'commStartTimeSec': flooredStartTime, 'status': self.tdmaComm.tdmaStatus}, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId])} assert(len(self.tdmaComm.sendTDMACmds()) > 0) assert(len(self.tdmaComm.tdmaCmds) == 0)
def initMesh(self, currentTime=time.time()): self.tdmaCmds[TDMACmds['LinkStatus']] = Command( TDMACmds['LinkStatus'], { 'linkStatus': self.nodeParams.linkStatus, 'nodeId': self.nodeParams.config.nodeId }, [TDMACmds['LinkStatus'], self.nodeParams.config.nodeId], self.nodeParams.config.commConfig['linksTxInterval']) if self.nodeParams.config.nodeId != 0: # stop ground node from broadcasting time offset self.tdmaCmds[TDMACmds['TimeOffset']] = Command( TDMACmds['TimeOffset'], { 'nodeStatus': self.nodeParams.nodeStatus[self.nodeParams.config.nodeId - 1] }, [TDMACmds['TimeOffset'], self.nodeParams.config.nodeId], self.nodeParams.config.commConfig['offsetTxInterval']) self.inited = True print("Node " + str(self.nodeParams.config.nodeId) + " - Initializing comm")
def initMesh(self, currentTime=time.time()): """Initialize node mesh networks.""" # Create tdma comm messages flooredStartTime = math.floor(self.commStartTime) self.tdmaCmds[TDMACmds['MeshStatus']] = Command(TDMACmds['MeshStatus'], {'commStartTimeSec': int(flooredStartTime), 'status': self.tdmaStatus, 'configHash': self.nodeParams.config.calculateHash()}, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId], self.nodeParams.config.commConfig['statusTxInterval']) self.tdmaCmds[TDMACmds['LinkStatus']] = Command(TDMACmds['LinkStatus'], {'linkStatus': self.nodeParams.linkStatus, 'nodeId': self.nodeParams.config.nodeId}, [TDMACmds['LinkStatus'], self.nodeParams.config.nodeId], self.nodeParams.config.commConfig['linksTxInterval']) if self.nodeParams.config.nodeId != 0: # stop ground node from broadcasting time offset self.tdmaCmds[TDMACmds['TimeOffset']] = Command(TDMACmds['TimeOffset'], {'nodeStatus': self.nodeParams.nodeStatus[self.nodeParams.config.nodeId-1]}, [TDMACmds['TimeOffset'], self.nodeParams.config.nodeId], self.nodeParams.config.commConfig['offsetTxInterval']) # Current network configuration message self.initialConfigTxTime = self.commStartTime + self.nodeParams.config.nodeId * self.nodeParams.config.commConfig['configTxInterval'] configHash = self.nodeParams.config.calculateHash() config_pb = NodeConfig.toProtoBuf(self.nodeParams.config.rawConfig).SerializeToString() self.tdmaCmds[TDMACmds['CurrentConfig']] = Command(TDMACmds['CurrentConfig'], {'config': config_pb, 'configLength': len(config_pb), 'configHash': configHash, 'hashLength': self.nodeParams.config.hashSize}, [TDMACmds['CurrentConfig'], self.nodeParams.config.nodeId], self.maxNumSlots * self.nodeParams.config.commConfig['configTxInterval']) # Determine where in frame mesh network currently is self.syncTDMAFrame(currentTime) self.inited = True print("Node " + str(self.nodeParams.config.nodeId) + " - Initializing comm")
def test_packageMeshPacket(self): """Test packageMeshPacket method of TDMAComm.""" packetHeaderLen = 8 # Test no send of empty message msgBytes = b'' destId = 5 assert(len(self.tdmaComm.packageMeshPacket(destId, msgBytes)) == 0) # Confirm packet structure msgBytes = b'1234567890' packet = self.tdmaComm.packageMeshPacket(destId, msgBytes) assert(len(packet) == packetHeaderLen + len(msgBytes)) packetHeader = struct.unpack('<BBHHH', packet[0:packetHeaderLen]) assert(packetHeader[0] == self.tdmaComm.nodeParams.config.nodeId) assert(packetHeader[1] == destId) assert(packetHeader[2] == 0) # no admin bytes assert(packetHeader[3] == len(msgBytes)) # Test sending of periodic TDMA commands (broadcast message only) cmd = Command(TDMACmds['MeshStatus'], {'commStartTimeSec': int(time.time()), 'status': TDMAStatus.nominal}, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId]) encodedCmd = self.tdmaComm.tdmaCmdParser.encodeMsg(cmd.serialize()) self.tdmaComm.tdmaCmds = dict() self.tdmaComm.tdmaCmds[TDMACmds['MeshStatus']] = cmd destId = 0 # broadcast message packet = self.tdmaComm.packageMeshPacket(destId, msgBytes) assert(len(packet) == packetHeaderLen + len(encodedCmd) + len(msgBytes)) assert(packet[packetHeaderLen:packetHeaderLen+len(encodedCmd)] == encodedCmd) assert(packet[packetHeaderLen+len(encodedCmd):] == msgBytes) # Confirm admin bytes still sent with zero length message bytes msgBytes = b'' self.tdmaComm.tdmaCmds[TDMACmds['MeshStatus']] = cmd packet = self.tdmaComm.packageMeshPacket(destId, msgBytes) assert(len(packet) == packetHeaderLen + len(encodedCmd)) assert(packet[packetHeaderLen:packetHeaderLen+len(encodedCmd)] == encodedCmd)
def test_checkForInit(self): """Test checkForInit method of TDMAComm.""" # Confirm radio is off assert(self.radio.mode == RadioMode.off) # Test without message self.tdmaComm.checkForInit() assert(self.radio.mode == RadioMode.receive) assert(self.tdmaComm.commStartTime == None) # Test with MeshStatus message startTime = int(time.time()) self.tdmaComm.tdmaCmds[TDMACmds['MeshStatus']] = Command(TDMACmds['MeshStatus'], {'commStartTimeSec': startTime, 'status': TDMAStatus.nominal}, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId], 0) self.tdmaComm.bufferTxMsg(self.tdmaComm.packageMeshPacket(0, b'')) #self.tdmaComm.bufferTxMsg(cmd.serialize()) self.tdmaComm.sendBuffer() time.sleep(0.1) self.tdmaComm.checkForInit() assert(self.tdmaComm.commStartTime == startTime)
def test_processSendBlockDataCmd(self): """Test processing of SendBlockData command from GCS.""" self.tdmaComm.frameStartTime = 0.0 # set a frame start time since main execution is bypassed # Create TestCmds['SendBlockData'] command cmdMsg = Command(TestCmds['SendDataBlock'], { 'destId': self.nodeParams.config.nodeId }, [TestCmds['SendDataBlock'], 0, self.nodeParams.get_cmdCounter()]).serialize( self.nodeParams.clock.getTime()) # Process command and check result self.tdmaComm.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeParams.nodeStatus, 'comm': self.tdmaComm }) assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.pending) assert (self.tdmaComm.dataBlock == b'1234567890' * 100)
def test_initComm(self): """Test initComm method of TDMAComm.""" testTime = time.time() # Confirm starting conditions assert(self.radio.mode == RadioMode.off) assert(self.tdmaComm.initStartTime == None) # Init comm and check radio is now in receive self.tdmaComm.initComm(testTime) assert(self.tdmaComm.initStartTime == testTime) self.tdmaComm.initComm(testTime + 0.01) assert(self.radio.mode == RadioMode.receive) # Send MeshStatus message and confirm that commStartTime is updated commStartTime = int(testTime) self.tdmaComm.tdmaCmds[TDMACmds['MeshStatus']] = Command(TDMACmds['MeshStatus'], {'commStartTimeSec': commStartTime, 'status': TDMAStatus.nominal}, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId], 0) assert(self.tdmaComm.commStartTime != commStartTime) # check that comm start times do not match #print(cmd.serialize()) #self.tdmaComm.bufferTxMsg(cmd.serialize()) self.tdmaComm.bufferTxMsg(self.tdmaComm.packageMeshPacket(0, b'')) self.tdmaComm.sendBuffer() time.sleep(0.1) self.tdmaComm.initComm(testTime) assert(self.tdmaComm.commStartTime == commStartTime) # check that comm start times now match
def sendDataBlock(self, destId, blockBytes): """This function receives a large data block to be sent over the mesh network for Block Transfer.""" if (self.blockTxReqPending or self.blockTxAccepted): # block tx already pending return False # Store data block and request block data transfer blockTxStartTime = int( self.nodeParams.clock.getTime() + self.nodeParams.config.commConfig['pollTimeout']) blockTxLength = math.ceil( len(blockBytes) / self.nodeParams.config.commConfig['blockTxPacketSize'] ) # length in number of packets if (blockTxLength > self.nodeParams.config.commConfig['blockTxMaxLength'] ): # data block is too large return False self.blockTxData = blockBytes self.comm.tdmaCmds[TDMACmds['BlockTxRequest']] = Command( TDMACmds['BlockTxRequest'], { 'blockReqId': self.getBlockRequestId(), 'destId': destId, 'startTime': blockTxStartTime, 'length': blockTxLength, 'status': 1 }, [ TDMACmds['BlockTxRequest'], self.nodeParams.config.nodeId, self.nodeParams.get_cmdCounter() ]) self.blockTxReqPending = True return True
def processMsg(self, cmdId, msg, args): nodeStatus = args['nodeStatus'] comm = args['comm'] clock = args['clock'] cmdStatus = False if len(msg) > 0: # Parse command header header = deserialize(msg, cmdId, 'header') if (processHeader(self, header, msg, nodeStatus, clock, comm) == False): # stale command return False # Parse message contents if cmdId not in [TDMACmds['BlockData'], TDMACmds['LinkStatus']]: try: msgContents = deserialize(msg, cmdId, 'body') if msgContents == None: return False except Exception as e: print("Exception occurred while deserializing message:", e) return False # Process message by command id for case in switch(cmdId): if case(TDMACmds['TimeOffset']): if nodeStatus and len(nodeStatus) >= header['sourceId']: nodeStatus[header['sourceId']-1].timeOffset = msgContents['timeOffset']/100.0 cmdStatus = True break if case(TDMACmds['MeshStatus']): if not comm.commStartTime: # accept value if one not already present comm.commStartTime = msgContents['commStartTimeSec'] # store comm start time cmdStatus = True break if case(TDMACmds['LinkStatus']): # Status of links to other nodes msgSize = self.nodeParams.config.maxNumNodes headerSize = calcsize(headers[CmdDict[cmdId].header]['format']) linkData = unpack('=' + msgSize*CmdDict['LinkStatusContents'].packFormat, msg[headerSize:]) # Determine sending node array index node = header['sourceId'] - 1 # Place received data into appropriate link status subarray for i in range(msgSize): self.nodeParams.linkStatus[node][i] = linkData[i] cmdStatus = True break if case(TDMACmds['BlockTxRequest']): # Request for a block of transmit time blockTxResponse = False if comm.blockTxStatus['status'] == TDMABlockTxStatus.false: # no current block tx active # Check block transmit constraints if validateBlockTxRequest(msgContents, header, self.nodeParams): # Store pending request parameters comm.blockTxStatus['blockReqID'] = msgContents['blockReqID'] comm.blockTxStatus['status'] = TDMABlockTxStatus.pending # set to pending status and wait for start comm.blockTxStatus['startTime'] = msgContents['startTime'] # store time of request comm.blockTxStatus['txNode'] = header['sourceId'] # store requesting node's ID comm.blockTxStatus['length'] = msgContents['length'] # transmit block length blockTxResponse = True # set response to request elif comm.blockTxStatus['status'] == TDMABlockTxStatus.pending: if comm.blockTxStatus['blockReqID'] == msgContents['blockReqId'] and header['sourceId'] == comm.blockTxStatus['txNode']: # repeat positive response blockTxResponse = True # Send response responseCmd = Command(TDMACmds['BlockTxRequestResponse'], {'blockReqID': msgContents['blockReqID'], 'accept': blockTxResponse}, [TDMACmds['BlockTxRequestResponse'], self.nodeParams.config.nodeId, self.nodeParams.get_cmdCounter()]) comm.radio.bufferTxMsg(responseCmd.serialize(self.nodeParams.clock.getTime())) break if case(TDMACmds['BlockTxConfirmed']): # Transmit block confirmation if comm.blockTxStatus['status'] == TDMABlockTxStatus.pending: # pending block transmit if comm.blockTxStatus['blockReqID'] == msgContents['blockReqID'] and comm.blockTxStatus['txNode'] == header['sourceId']: # confirmation received correct node with correct block ID comm.blockTxStatus['status'] = TDMABlockTxStatus.confirmed break if case(TDMACmds['BlockTxRequestResponse']): if comm.blockTxStatus['status'] == TDMABlockTxStatus.pending and comm.blockTxStatus['txNode'] == self.nodeParams.config.nodeId: # Block Tx previously requested by this node if header['sourceId'] in comm.blockTxStatus['blockResponseList']: # this node in response list comm.blockTxStatus['blockResponseList'][header['sourceId']] = msgContents['accept'] break if case(TDMACmds['BlockTxStatus']): updateStatus = False if comm.blockTxStatus['status'] == TDMABlockTxStatus.false: # receiving node not aware of block transmit updateStatus = True elif comm.blockTxStatus['status'] == TDMABlockTxStatus.pending: if msgContents['blockReqID'] == comm.blockTxStatus['blockReqID']: # may have missed confirm message updateStatus = True if updateStatus: # Update block transmit status comm.blockTxStatus['blockReqID'] = msgContents['blockReqID'] comm.blockTxStatus['status'] = TDMABlockTxStatus.confirmed # jump to confirmed status comm.blockTxStatus['startTime'] = msgContents['startTime'] # store time of request comm.blockTxStatus['txNode'] = header['sourceId'] # store requesting node's ID comm.blockTxStatus['length'] = msgContents['length'] # transmit block length break if case(TDMACmds['BlockData']): # raw block data headerSize = calcsize(headers[CmdDict[cmdId].header]['format']) blockData = msg[headerSize:] print("Block data received:", blockData) return cmdStatus
def test_blockTxCmdsProcessing(self): """Test processing of block transmit related commands.""" return # skip this test self.comm.commStartTime = self.nodeParams.clock.getTime() - 1.0 blockReqID = random.randint(1, 255) # just a random "unique" number startTime = int(self.nodeParams.clock.getTime() + 10.0) length = self.nodeParams.config.commConfig['maxTxBlockSize'] txNode = 1 ## TDMACmds['BlockTxRequest'] cmdMsg = Command(TDMACmds['BlockTxRequest'], { 'blockReqID': blockReqID, 'startTime': startTime, 'length': length }, [ TDMACmds['BlockTxRequest'], txNode, self.nodeParams.get_cmdCounter() ]).serialize(self.nodeParams.clock.getTime()) # Process and check results assert (self.comm.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) == True) assert (len(self.comm.radio.txBuffer) == calcsize( CmdDict[TDMACmds['BlockTxRequestResponse']].packFormat) + calcsize(headers['NodeHeader']['format'])) # response sent assert (self.comm.blockTxStatus['blockReqID'] == blockReqID) assert (self.comm.blockTxStatus['status'] == TDMABlockTxStatus.pending) assert (self.comm.blockTxStatus['txNode'] == txNode) assert (self.comm.blockTxStatus['startTime'] == startTime) assert (self.comm.blockTxStatus['length'] == length) ## TDMACmds['BlockTxConfirmed'] time.sleep(0.01) cmdMsg = Command(TDMACmds['BlockTxConfirmed'], { 'blockReqID': blockReqID }, [ TDMACmds['BlockTxConfirmed'], txNode, self.nodeParams.get_cmdCounter() ]).serialize(self.nodeParams.clock.getTime()) assert (self.comm.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) == True) assert ( self.comm.blockTxStatus['status'] == TDMABlockTxStatus.confirmed ) # status updated to confirmed ## TDMACmds['BlockTxStatus'] self.comm.resetBlockTxStatus() time.sleep(0.01) cmdMsg = Command(TDMACmds['BlockTxStatus'], { 'blockReqID': blockReqID, 'startTime': startTime, 'length': length }, [ TDMACmds['BlockTxStatus'], txNode, self.nodeParams.get_cmdCounter() ]).serialize(self.nodeParams.clock.getTime()) # Check status updated assert (self.comm.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) == True) assert (len(self.comm.radio.txBuffer) == calcsize( CmdDict[TDMACmds['BlockTxRequestResponse']].packFormat) + calcsize(headers['NodeHeader']['format'])) # response sent assert (self.comm.blockTxStatus['blockReqID'] == blockReqID) assert ( self.comm.blockTxStatus['status'] == TDMABlockTxStatus.confirmed) assert (self.comm.blockTxStatus['txNode'] == txNode) assert (self.comm.blockTxStatus['startTime'] == startTime) assert (self.comm.blockTxStatus['length'] == length) # Check status updated to confirmed if only pending time.sleep(0.01) cmdMsg = Command(TDMACmds['BlockTxStatus'], { 'blockReqID': blockReqID, 'startTime': startTime, 'length': length }, [ TDMACmds['BlockTxStatus'], txNode, self.nodeParams.get_cmdCounter() ]).serialize(self.nodeParams.clock.getTime()) # update command counter self.comm.blockTxStatus['status'] = TDMABlockTxStatus.pending assert (self.comm.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) == True) assert ( self.comm.blockTxStatus['status'] == TDMABlockTxStatus.confirmed) ## TDMACmds['BlockTxRequestResponse'] time.sleep(0.01) self.comm.resetBlockTxStatus() self.comm.blockTxStatus[ 'txNode'] = self.nodeParams.config.nodeId # this node requested block transfer self.comm.blockTxStatus['status'] = TDMABlockTxStatus.pending cmdMsg = Command(TDMACmds['BlockTxRequestResponse'], { 'blockReqID': blockReqID, "accept": True }, [ TDMACmds['BlockTxRequestResponse'], 1, self.nodeParams.get_cmdCounter() ]).serialize(self.nodeParams.clock.getTime()) print(self.nodeParams.config.nodeId) self.nodeParams.nodeStatus[ 0].present = True # mark another node as present self.comm.populateBlockResponseList() # create block response list # Test acceptance marked assert (self.comm.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) == True) assert (self.comm.blockTxStatus['blockResponseList'][1] == True) # Test rejection marked time.sleep(0.01) cmdMsg = Command(TDMACmds['BlockTxRequestResponse'], { 'blockReqID': blockReqID, "accept": False }, [ TDMACmds['BlockTxRequestResponse'], 1, self.nodeParams.get_cmdCounter() ]).serialize(self.nodeParams.clock.getTime()) assert (self.comm.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) == True) assert (self.comm.blockTxStatus['blockResponseList'][1] == False)
def test_processMsgs(self): """Test processMsgs method of TDMAComm.""" commStartTime = int(time.time()) cmd = Command(TDMACmds['MeshStatus'], {'commStartTimeSec': commStartTime, 'status': TDMAStatus.nominal}, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId]) encodedCmd = self.tdmaComm.tdmaCmdParser.encodeMsg(cmd.serialize()) self.tdmaComm.tdmaCmds = dict() self.tdmaComm.tdmaCmds[TDMACmds['MeshStatus']] = cmd payloadBytes = b'1234567890' # Verify pre-test conditions assert(len(self.tdmaComm.cmdRelayBuffer) == 0) assert(self.tdmaComm.commStartTime == None) # Send test packet packet = self.tdmaComm.packageMeshPacket(0, payloadBytes) self.tdmaComm.bufferTxMsg(packet) self.tdmaComm.sendBuffer() time.sleep(0.1) # Confirm payload bytes buffered for host assert(len(self.tdmaComm.hostBuffer) == 0) self.tdmaComm.readMsgs() self.tdmaComm.processMsgs() assert(len(self.tdmaComm.hostBuffer) > 0) assert(self.tdmaComm.hostBuffer == payloadBytes) # Confirm mesh admin message processed assert(self.tdmaComm.commStartTime == commStartTime) ## Test proper relaying cmdRelayBufferLen = len(self.tdmaComm.cmdRelayBuffer) assert(cmdRelayBufferLen > 0) # new broadcast command should be relayed self.tdmaComm.bufferTxMsg(packet) self.tdmaComm.sendBuffer() time.sleep(0.1) self.tdmaComm.readMsgs() self.tdmaComm.processMsgs() assert(len(self.tdmaComm.cmdRelayBuffer) == cmdRelayBufferLen) # stale command should be tossed # Send msg with destination that should be relayed self.tdmaComm.maxNumSlots = 7 self.tdmaComm.meshPaths = [[]*7]*7 self.tdmaComm.nodeParams.linkStatus = [[0, 1, 1, 0, 0, 0, 0], [1, 0, 0, 1, 0 ,0, 0], [1, 0, 0, 1, 0, 0, 0], [0, 1, 1, 0, 1, 1, 0], [0, 0, 0, 1, 0, 0, 1], [0, 0, 0, 1, 0, 0, 1], [0, 0, 0, 0, 1, 1, 0]] self.tdmaComm.updateShortestPaths() self.tdmaComm.cmdRelayBuffer = bytearray() destId = 3 self.tdmaComm.nodeParams.config.nodeId = 2 packet = self.tdmaComm.packageMeshPacket(destId, payloadBytes) self.tdmaComm.bufferTxMsg(packet) self.tdmaComm.sendBuffer() time.sleep(0.1) self.tdmaComm.readMsgs() self.tdmaComm.nodeParams.config.nodeId = 1 self.tdmaComm.processMsgs() assert(len(self.tdmaComm.cmdRelayBuffer) > 0) # Send msg with destination that should not be relayed self.tdmaComm.cmdRelayBuffer = bytearray() destId = 4 self.tdmaComm.nodeParams.config.nodeId = 2 packet = self.tdmaComm.packageMeshPacket(destId, payloadBytes) self.tdmaComm.bufferTxMsg(packet) self.tdmaComm.sendBuffer() time.sleep(0.1) self.tdmaComm.readMsgs() self.tdmaComm.nodeParams.config.nodeId = 1 self.tdmaComm.processMsgs() assert(len(self.tdmaComm.cmdRelayBuffer) == 0)
def test_sendMsg(self): """Test sendMsg method of TDMAComm.""" # Test send only when conditions met self.tdmaComm.enabled = False self.tdmaComm.tdmaMode = TDMAMode.receive self.tdmaComm.transmitComplete = False assert(len(self.tdmaComm.radio.txBuffer) == 0) self.tdmaComm.radio.bufferTxMsg(b'12345') assert(len(self.tdmaComm.radio.txBuffer) > 0) self.tdmaComm.sendMsg() assert(len(self.tdmaComm.radio.txBuffer) > 0) # message not sent assert(self.tdmaComm.transmitComplete == False) self.tdmaComm.enabled = True self.tdmaComm.sendMsg() assert(len(self.tdmaComm.radio.txBuffer) > 0) # message still not sent self.tdmaComm.tdmaMode = TDMAMode.transmit self.tdmaComm.sendMsg() assert(len(self.tdmaComm.radio.txBuffer) == 0) # message sent # Test transmission of periodic commands #serBytes = self.tdmaComm.radio.getRxBytes() # clear incoming bytes #assert(len(self.tdmaComm.cmdBuffer) == 0) #assert(len(self.tdmaComm.cmdRelayBuffer) == 0) #cmd = Command(TDMACmds['MeshStatus'], {'commStartTimeSec': int(time.time()), 'status': TDMAStatus.nominal}, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId]) #self.tdmaComm.tdmaCmds[TDMACmds['MeshStatus']] = cmd #self.tdmaComm.sendMsg() #time.sleep(0.1) #self.tdmaComm.readBytes() #serBytes = self.tdmaComm.radio.getRxBytes() #assert(len(serBytes) > 0) #assert(serBytes[-1:] == HDLC_END_TDMA) # check for end of message indicator # Test command relay buffer testMsg = b'1234567890' self.tdmaComm.radio.clearRxBuffer() self.tdmaComm.cmdRelayBuffer = testMsg self.tdmaComm.sendMsg() time.sleep(0.1) self.tdmaComm.readBytes() serBytes = self.tdmaComm.radio.getRxBytes() assert(testMsg in serBytes) # Test command buffer self.tdmaComm.radio.clearRxBuffer() testCmd = {'bytes': b'12345'} self.tdmaComm.cmdBuffer['key1'] = testCmd self.tdmaComm.sendMsg() assert(len(self.tdmaComm.cmdBuffer) == 0) # command buffer flushed out time.sleep(0.1) self.tdmaComm.readBytes() assert(len(self.tdmaComm.radio.getRxBytes()) > 0) ## Test meshQueue processing # Test no output for empty queue self.tdmaComm.sendMsg() time.sleep(0.1) self.tdmaComm.readBytes() assert(len(self.tdmaComm.radio.getRxBytes()) > 0) # nothing sent when meshQueue is empty (and no periodic commands) # Test broadcast message output cmd = Command(TDMACmds['MeshStatus'], {'commStartTimeSec': int(time.time()), 'status': TDMAStatus.nominal}, [TDMACmds['MeshStatus'], self.nodeParams.config.nodeId]) self.tdmaComm.tdmaCmds[TDMACmds['MeshStatus']] = cmd encodedCmd = self.tdmaComm.tdmaCmdParser.encodeMsg(cmd.serialize()) self.tdmaComm.sendMsg() time.sleep(0.1) self.tdmaComm.readBytes() assert(len(self.tdmaComm.radio.getRxBytes()) > 0) # message sent when periodic commands pending self.tdmaComm.parseMsgs() assert(len(self.tdmaComm.msgParser.parsedMsgs) == 1) packetHeader = struct.unpack('<BBHHH', self.tdmaComm.msgParser.parsedMsgs[0][0:8]) assert(packetHeader[1] == 0) # broadcast message assert(encodedCmd in self.tdmaComm.msgParser.parsedMsgs[0]) # tdmaCmds included in message # Test destination specific output self.nodeParams.config.commConfig['recvAllMsgs'] = True # receive all messages, regardless of dest msg1 = b'1234567890' msg1Dest = 3 msg2 = b'0987654321' msg2Dest = 5 self.tdmaComm.meshQueueIn[msg1Dest] = msg1 self.tdmaComm.meshQueueIn[msg2Dest] = msg2 self.tdmaComm.sendMsg() time.sleep(0.1) self.tdmaComm.readBytes() assert(len(self.tdmaComm.radio.getRxBytes()) > 0) self.tdmaComm.processMsgs() assert(len(self.tdmaComm.hostBuffer) > 0) assert(msg1 in self.tdmaComm.hostBuffer) assert(msg2 in self.tdmaComm.hostBuffer) # Test without receiving messages for other nodes self.tdmaComm.hostBuffer = bytearray() self.nodeParams.config.commConfig['recvAllMsgs'] = False msg1Dest = self.nodeParams.config.nodeId self.tdmaComm.meshQueueIn[msg1Dest] = msg1 self.tdmaComm.meshQueueIn[msg2Dest] = msg2 self.tdmaComm.sendMsg() time.sleep(0.1) self.tdmaComm.readBytes() assert(len(self.tdmaComm.radio.getRxBytes()) > 0) self.tdmaComm.processMsgs() assert(len(self.tdmaComm.hostBuffer) > 0) assert(self.tdmaComm.hostBuffer == msg1)
def monitorBlockTx(self): """Monitors current status of block transmit.""" if self.blockTxStatus['status'] == TDMABlockTxStatus.false: return elif self.blockTxStatus[ 'status'] == TDMABlockTxStatus.pending: # monitor pending block request if self.blockTxStatus[ 'txNode'] == self.nodeParams.config.nodeId: # this node requested block tx # Check block request responses response = self.checkBlockResponse() if response == True: # Confirm block tx blockConfirmCmd = Command( TDMACmds['BlockTxConfirmed'], {'blockReqID': self.blockTxStatus['blockReqID']}, [ TDMACmds['BlockTxConfirmed'], self.nodeParams.config.nodeId, self.nodeParams.get_cmdCounter() ]) self.radio.bufferTxMsg( blockConfirmCmd.serialize( self.nodeParams.clock.getTime())) self.blockTxStatus['status'] = TDMABlockTxStatus.confirmed return elif response == False: # Cancel request self.resetBlockTxStatus() return # Check for request timeout if (self.frameStartTime - self.blockTxStatus['requestTime'] ) > self.nodeParams.config.commConfig[ 'blockTxRequestTimeout'] * self.nodeParams.config.commConfig[ 'frameLength']: # Request timed out - reset status self.resetBlockTxStatus() return if self.frameStartTime >= self.blockTxStatus[ 'startTime']: # no block confirmed received # Cancel pending block self.resetBlockTxStatus() return elif self.blockTxStatus['status'] == TDMABlockTxStatus.confirmed: # Check for block start if self.frameStartTime >= self.blockTxStatus[ 'startTime']: # start block self.blockTxStatus['status'] = TDMABlockTxStatus.active self.nodeParams.tdmaStatus = TDMAStatus.blockTx # Send block transmit status message if self.blockTxStatus['txNode'] == self.nodeParams.config.nodeId: blockStatusCmd = Command( TDMACmds['BlockTxStatus'], { 'blockReqID': self.blockTxStatus['blockReqID'], 'startTime': self.blockTxStatus['startTime'], 'length': self.blockTxStatus['length'] }, [ TDMACmds['BlockTxStatus'], self.nodeParams.config.nodeId, self.nodeParams.get_cmdCounter() ]) self.radio.bufferTxMsg( blockStatusCmd.serialize(self.nodeParams.clock.getTime())) elif self.blockTxStatus[ 'status'] == TDMABlockTxStatus.active: # block transmit in progress # Check for end of block transmit if self.blockTxStatus['blockTxComplete'] or ( self.frameStartTime - self.blockTxStatus['startTime'] ) >= self.blockTxStatus['length'] * self.nodeParams.config.commConfig[ 'frameLength'] or self.nodeParams.tdmaStatus == TDMAStatus.nominal: # Block transmit ended - reset status self.resetBlockTxStatus()
def checkPolling(self): # Update poll status for poll in self.networkPolls: # Respond to poll if (poll.voteSent == False): # respond to poll cmdResponse = None if (poll.cmdId == TDMACmds['ConfigUpdate']): if (poll.cmd['valid'] == True): poll.votes[self.nodeParams.config.nodeId - 1] = NetworkVote.Yes cmdResponse = True else: # invalid config poll.votes[self.nodeParams.config.nodeId - 1] = NetworkVote.No cmdResponse = False elif (poll.cmdId == TDMACmds['NetworkRestart']): poll.votes[self.nodeParams.config.nodeId - 1] = NetworkVote.Yes cmdResponse = True elif (poll.cmdId == TDMACmds['BlockTxRequest']): if (self.blockTxAccepted or self.comm.blockTxInProgress): # reject new request poll.votes[self.nodeParams.config.nodeId - 1] = NetworkVote.No cmdResponse = False else: # accept request poll.votes[self.nodeParams.config.nodeId - 1] = NetworkVote.Yes cmdResponse = True else: # rejected unrecognized command ids poll.votes[self.nodeParams.config.nodeId - 1] = NetworkVote.No cmdResponse = False # Send poll response print("Node " + str(self.nodeParams.config.nodeId) + ": Sending command response") self.comm.tdmaCmds[NodeCmds['CmdResponse']] = Command( NodeCmds['CmdResponse'], { 'cmdId': poll.cmdId, 'cmdCounter': poll.cmdCounter, 'cmdResponse': cmdResponse }, [NodeCmds['CmdResponse'], self.nodeParams.config.nodeId]) poll.voteSent = True # Process any pending command responses if (poll.cmdCounter in self.nodeParams.cmdResponse): for key in self.nodeParams.cmdResponse[poll.cmdCounter]: if (self.nodeParams.cmdResponse[poll.cmdCounter][key] == 1 ): poll.votes[key - 1] = NetworkVote.Yes elif (self.nodeParams.cmdResponse[poll.cmdCounter][key] == 0): poll.votes[key - 1] = NetworkVote.No del self.nodeParams.cmdResponse[poll.cmdCounter] # Check for poll decision yesVotes = 0 for node in range(0, self.nodeParams.config.maxNumNodes): if (node + 1 in poll.exclusions): poll.votes[node] = NetworkVote.Excluded elif (self.nodeParams.nodeStatus[node].updating == False ): # node not updating poll.votes[node] = NetworkVote.Excluded poll.exclusions.append(node + 1) # add node to exclusion list elif (poll.votes[node] == NetworkVote.No): # node voted no poll.decision = VoteDecision.No print( "Node " + str(self.nodeParams.config.nodeId) + ": Vote failed - ", poll.cmdId, poll.cmdCounter) elif (poll.votes[node] == NetworkVote.Yes): # node voted yes yesVotes += 1 if (yesVotes == (self.nodeParams.config.maxNumNodes - len(poll.exclusions)) ): # all present and not excluded notes have concurred poll.decision = VoteDecision.Yes print( "Node " + str(self.nodeParams.config.nodeId) + ": Vote succeeded - ", poll.cmdId, poll.cmdCounter) # Update poll status updatedPolls = [] for poll in self.networkPolls: if (poll.decision == VoteDecision.Undecided): # Check expiration on undecided polls if (self.nodeParams.clock.getTime() <= (poll.startTime + self.nodeParams.config.commConfig['pollTimeout']) ): # poll has not yet expired updatedPolls.append(poll) else: print("Node " + str(self.nodeParams.config.nodeId) + ": Clearing poll") else: # take action on completed poll self.executeNetworkAction(poll) self.networkPolls = updatedPolls
def test_nominalTDMABlockTx(self): """Test TDMA block transfer sequence.""" # Force init self.tdmaComm.meshInited = True dataBlock = b'1234567890' * 50 self.nodeParams.config.commConfig['maxBlockTransferSize'] = int( len(dataBlock) / 2) + 1 self.tdmaComm.frameStartTime = time.time() # Set present nodes self.nodeParams.nodeStatus[0].present = True self.nodeParams.nodeStatus[1].present = True # Request sending of data block self.initiateBlockTransmit() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.pending) ## Execute TDMA comm and monitor block transfer process # Check for status change to pending self.tdmaComm.frameStartTime += self.nodeParams.config.commConfig[ 'frameLength'] self.tdmaComm.execute(self.tdmaComm.frameStartTime) assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.pending) # "Send" positive request response from one node cmdMsg = Command( TDMACmds['BlockTxRequestResponse'], { 'blockReqID': self.tdmaComm.blockTxStatus['blockReqID'], "accept": True }, [ TDMACmds['BlockTxRequestResponse'], 1, self.nodeParams.get_cmdCounter() ]).serialize(self.nodeParams.clock.getTime()) self.tdmaComm.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeParams.nodeStatus, 'comm': self.tdmaComm, 'clock': self.nodeParams.clock }) print(self.tdmaComm.blockTxStatus['blockResponseList']) assert (self.tdmaComm.blockTxStatus['blockResponseList'][1] == True ) # response list updated self.tdmaComm.frameStartTime += self.nodeParams.config.commConfig[ 'frameLength'] self.tdmaComm.execute(self.tdmaComm.frameStartTime) assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.pending) # Send remaining positive responses and check for update to confirmed status time.sleep(0.1) cmdMsg = Command( TDMACmds['BlockTxRequestResponse'], { 'blockReqID': self.tdmaComm.blockTxStatus['blockReqID'], "accept": True }, [ TDMACmds['BlockTxRequestResponse'], 2, self.nodeParams.get_cmdCounter() ]).serialize(self.nodeParams.clock.getTime()) self.tdmaComm.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeParams.nodeStatus, 'comm': self.tdmaComm, 'clock': self.nodeParams.clock }) self.tdmaComm.frameStartTime += self.nodeParams.config.commConfig[ 'frameLength'] self.tdmaComm.execute(self.tdmaComm.frameStartTime) assert (self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.confirmed) # Advance to block start time self.tdmaComm.radio.txBuffer = bytearray() # clear tx buffer self.tdmaComm.frameStartTime = self.tdmaComm.blockTxStatus['startTime'] self.tdmaComm.execute(self.tdmaComm.frameStartTime) time.sleep(0.1) self.tdmaComm.radio.readBytes(True) assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.active ) # block started assert (self.nodeParams.tdmaStatus == TDMAStatus.blockTx ) # tdma status updated assert (self.tdmaComm.radio.bytesInRxBuffer >= self.nodeParams.config.commConfig['maxBlockTransferSize']) assert (self.tdmaComm.blockTxStatus['blockTxComplete'] == False) # Continue sending and check for block tx complete flag self.tdmaComm.frameStartTime += self.nodeParams.config.commConfig[ 'frameLength'] self.tdmaComm.execute(self.tdmaComm.frameStartTime) assert (self.tdmaComm.blockTxStatus['blockTxComplete'] == True) # Check for transition back to nominal TDMA self.tdmaComm.frameStartTime += self.nodeParams.config.commConfig[ 'frameLength'] self.tdmaComm.execute(self.tdmaComm.frameStartTime) assert (self.nodeParams.tdmaStatus == TDMAStatus.nominal) assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.false)
# TestCmd type TestCmd = namedtuple('TestCmd', ['cmdData', 'body', 'header']) # Node configuration nodeId = 1 cmdCounter = 11 # Test commands dictionary testCmds = dict() ### NodeCmds # NodeCmds['NoOp'] cmdId = NodeCmds['NoOp'] cmdData = {} cmd = Command(cmdId, cmdData, [cmdId, nodeId, nodeParams.get_cmdCounter()]) testCmds.update({cmdId: cmd}) # NodeCmds['GCSCmd'] cmdId = NodeCmds['GCSCmd'] cmdData = {'destId': 0, 'mode': 1} cmd = Command(cmdId, cmdData, [cmdId, 0, nodeParams.get_cmdCounter()]) testCmds.update({cmdId: cmd}) # NodeCmds['ConfigRequest'] cmdId = NodeCmds['ConfigRequest'] cmdData = {'configHash': nodeParams.config.calculateHash()} cmd = Command(cmdId, cmdData, [cmdId, 0, nodeParams.get_cmdCounter()]) testCmds.update({cmdId: cmd}) # NodeCmds['ParamUpdate']