def setup_method(self, method): if testSerialPort: serialPort = serial.Serial(port=testSerialPort, baudrate=57600, timeout=0) else: serialPort = [] self.nodeParams = NodeParams(configFile=configFilePath) self.nodeParams.commStartTime = time.time() self.nodeParams.config.commConfig['transmitSlot'] = 1 self.radio = Radio( serialPort, { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 }) commProcessor = CommProcessor([TDMACmdProcessor, TestCmdProcessor], self.nodeParams) msgParser = SLIPMsgParser( {'parseMsgMax': self.nodeParams.config.parseMsgMax}) self.tdmaComm = TDMAComm(commProcessor, self.radio, msgParser, self.nodeParams) self.tdmaComm.nodeParams.frameStartTime = time.time()
def setup_method(self, method): # Create NodeConfig instance self.nodeConfig = NodeConfig(configFilePath) if method.__name__ != "test_init": self.nodeParams = NodeParams(config=self.nodeConfig) # Create NodeParams instance
def test_init(self): """Test NodeParams init function.""" # Test that init function loads node configuration from file print("Testing init with configFile") nodeParams = NodeParams(configFile=configFilePath) assert (nodeParams.config.__dict__ == self.nodeConfig.__dict__) # Test that init function loads node configuration from provided config nodeParams = NodeParams(config=self.nodeConfig) assert (nodeParams.config.__dict__ == self.nodeConfig.__dict__)
def setup_method(self, method): self.nodeStatus = [NodeState(i + 1) for i in range(5)] self.nodeParams = NodeParams(configFile=configFilePath) msgParser = MsgParser( {'parseMsgMax': self.nodeParams.config.parseMsgMax}, SLIPMsg(256)) radio = Radio( [], { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 }) self.comm = TDMAComm([TDMACmdProcessor], radio, msgParser, self.nodeParams)
class TestNodeParams: def setup_method(self, method): # Create NodeConfig instance self.nodeConfig = NodeConfig(configFilePath) if method.__name__ != "test_init": self.nodeParams = NodeParams( config=self.nodeConfig) # Create NodeParams instance def test_init(self): """Test NodeParams init function.""" # Test that init function loads node configuration from file print("Testing init with configFile") nodeParams = NodeParams(configFile=configFilePath) assert (nodeParams.config.__dict__ == self.nodeConfig.__dict__) # Test that init function loads node configuration from provided config nodeParams = NodeParams(config=self.nodeConfig) assert (nodeParams.config.__dict__ == self.nodeConfig.__dict__) def test_getCmdCounter(self): """Test NodeParams command counter get function.""" # Test getting random command counter counter = self.nodeParams.get_cmdCounter() assert (counter >= 1) # value within range assert (counter <= 65536) # value within range
def setup_method(self, method): # Create CommProcessor instance nodeParams = NodeParams(configFile=configFilePath) self.commProcessor = CommProcessor([PixhawkCmdProcessor], nodeParams) self.serialComm = SerialComm([], [], nodeParams.config) # Truth data self.crcLength = 2
class TestNodeCmdProcessor: def setup_method(self, method): self.nodeStatus = [NodeState(i + 1) for i in range(5)] self.nodeParams = NodeParams(configFile=configFilePath) msgParser = MsgParser( {'parseMsgMax': self.nodeParams.config.parseMsgMax}, SLIPMsg(256)) radio = Radio( [], { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 }) self.comm = SerialComm([NodeCmdProcessor], self.nodeParams, radio, msgParser) def test_processMsg(self): """Test processMsg method of NodeCmdProcessor.""" # Test processing of all NodeCmds for cmdId in cmdsToTest: cmdMsg = testCmds[cmdId].serialize() print(cmdId) assert (self.comm.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) == True) if cmdId == NodeCmds['NoOp']: pass elif cmdId == NodeCmds['ParamUpdate']: assert (self.nodeParams.config.parseMsgMax == unpack( '=H', testCmds[cmdId].cmdData['paramValue'])[0]) elif cmdId == NodeCmds['ConfigUpdate']: assert (self.nodeParams.newConfig != None ) # new config staged for updating cmdResponse = None for entry in self.nodeParams.cmdResponse: if (entry['cmdId'] == NodeCmds['ConfigUpdate']): cmdResponse = entry break assert (cmdResponse != None) assert (cmdResponse['cmdResponse'] == 1) def test_malformedCmd(self): # Test command with improper message contents badMsg = packHeader( createHeader([ CmdDict[NodeCmds['GCSCmd']].header, [NodeCmds['GCSCmd'], 0, self.nodeParams.get_cmdCounter()] ])) # header only assert (self.comm.processMsg(badMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) == False)
def setup_method(self, method): from mesh.generic.xbeeRadio import XbeeRadio self.nodeParams = NodeParams(configFile=configFilePath) self.xbeeRadio = XbeeRadio( [], { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 }, "P8_12")
def setup_method(self, method): self.nodeStatus = [NodeState(i + 1) for i in range(5)] self.nodeParams = NodeParams(configFile=configFilePath) radio = Radio( [], { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 }) self.comm = SerialComm([GndCmdProcessor], self.nodeParams, radio, [])
def setup_method(self, method): self.nodeParams = NodeParams(configFile=configFilePath) self.nodeParams.config.commConfig['transmitSlot'] = 1 self.radio = Radio(None, {'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000}) msgParser = MsgParser({'parseMsgMax': self.nodeParams.config.parseMsgMax}, HDLCMsg(256)) self.tdmaComm = TDMAComm([TDMACmdProcessor], self.radio, msgParser, self.nodeParams) # Test article self.meshController = MeshController(self.nodeParams, self.tdmaComm)
def setup_method(self, method): self.serialPort = serial.Serial(port=testSerialPort, baudrate=57600, timeout=0) self.nodeParams = NodeParams(configFile=configFilePath) self.li1Radio = Li1Radio( self.serialPort, { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 })
def setup_method(self, method): self.nodeParams = NodeParams(configFile=configFilePath) self.serialPort = serial.Serial(port=testSerialPort, baudrate=57600, timeout=0) self.radio = Radio( self.serialPort, { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 }) self.serialComm = SerialComm([NodeCmdProcessor], self.nodeParams, self.radio, [])
def setup_method(self, method): self.nodeParams = NodeParams(configFile=configFilePath) self.serialPort = serial.Serial(port=testSerialPort, baudrate=57600, timeout=0) self.radio = Radio( self.serialPort, { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 }) msgParser = SLIPMsgParser( {'parseMsgMax': self.nodeParams.config.parseMsgMax}) self.comm = SerialComm([], self.nodeParams, self.radio, msgParser)
def setup_method(self, method): if testSerialPort: serialPort = serial.Serial(port=testSerialPort, baudrate=57600, timeout=0) else: serialPort = [] self.nodeParams = NodeParams(configFile=configFilePath) self.nodeParams.config.commConfig['transmitSlot'] = 1 self.radio = Radio(serialPort, {'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000}) msgParser = MsgParser({'parseMsgMax': self.nodeParams.config.parseMsgMax}, HDLCMsg(256)) self.tdmaComm = TDMAComm([TDMACmdProcessor], self.radio, msgParser, self.nodeParams) # Flush radio self.radio.serial.read(100)
def setup_method(self, method): self.nodeParams = NodeParams(configFile=configFilePath) self.serialPort = serial.Serial(port=testSerialPort, baudrate=57600, timeout=0) commProcessor = CommProcessor([PixhawkCmdProcessor], self.nodeParams) radio = Radio( self.serialPort, { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 }) msgParser = SLIPMsgParser( {'parseMsgMax': self.nodeParams.config.parseMsgMax}) self.nodeComm = NodeComm(commProcessor, radio, msgParser, self.nodeParams) pass
def setup_method(self, method): self.nodeParams = NodeParams(configFile=configFilePath) # Setup comms self.serialConfig = { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': self.nodeParams.config.rxBufferSize } self.serialPort = serial.Serial(port=testSerialPort, baudrate=57600, timeout=0) radio = Radio(self.serialPort, self.serialConfig) nodeComm = SerialComm([], radio, []) #self.FCSerialPort = serial.Serial(port=testSerialPort, baudrate=57600, timeout=0) #radio = Radio(self.FCSerialPort, serialConfig) FCComm = SerialComm([], radio, []) # Create executive self.nodeExecutive = NodeExecutive(self.nodeParams, None, [nodeComm], FCComm, [])
class TestTDMACmdProcessor: def setup_method(self, method): self.nodeStatus = [NodeState(i + 1) for i in range(5)] self.nodeParams = NodeParams(configFile=configFilePath) msgParser = MsgParser( {'parseMsgMax': self.nodeParams.config.parseMsgMax}, SLIPMsg(256)) radio = Radio( [], { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 }) self.comm = TDMAComm([TDMACmdProcessor], radio, msgParser, self.nodeParams) def test_validateBlockTxRequest(self): """Test validateBlockTxRequest method of TDMACmdProcessor.""" # Test request rejected if start time passed contents = { 'startTime': time.time() - 1.0, 'length': self.nodeParams.config.commConfig['maxTxBlockSize'] } assert (validateBlockTxRequest(contents, [], self.nodeParams) == False) # Test request rejected if block too long contents = { 'startTime': time.time() + 1.0, 'length': self.nodeParams.config.commConfig['maxTxBlockSize'] + 1 } assert (validateBlockTxRequest(contents, [], self.nodeParams) == False) # Test for request acceptance contents = { 'startTime': time.time() + 1.0, 'length': self.nodeParams.config.commConfig['maxTxBlockSize'] } assert (validateBlockTxRequest(contents, [], self.nodeParams) == True) def test_processMsg(self): """Test processMsg method of TDMACmdProcessor.""" # Test processing of all TDMACmds for cmdId in cmdsToTest: self.comm.networkMsgQueue = [ ] # clear command queue to check for additions after command processing assert (self.comm.processMsg(testCmds[cmdId].serialize(), args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) == True) if cmdId == TDMACmds['TimeOffset']: sourceId = testCmds[cmdId].header['header']['sourceId'] assert (self.nodeStatus[sourceId - 1].timeOffset == testCmds[cmdId].cmdData['nodeStatus'].timeOffset ) # verify time offset parsed correctly elif cmdId == TDMACmds['MeshStatus']: assert (self.comm.commStartTime == testCmds[cmdId].cmdData['commStartTimeSec'] ) # comm start time stored elif cmdId == TDMACmds['LinkStatus']: msgNodeId = testCmds[cmdId].cmdData['nodeId'] for i in range(0, self.nodeParams.config.maxNumNodes): assert (self.nodeParams.linkStatus[msgNodeId - 1][i] == testCmds[cmdId].cmdData['linkStatus'][msgNodeId - 1][i]) elif cmdId == TDMACmds['ConfigUpdate']: assert (self.nodeParams.newConfig != None ) # new config staged for updating assert (len(self.comm.networkMsgQueue) > 0) elif cmdId == TDMACmds['NetworkRestart']: assert (len(self.comm.networkMsgQueue) > 0) # Resend and test that commStartTime is not updated once it has previously been set cmdId = TDMACmds['MeshStatus'] self.comm.commStartTime = testCmds[cmdId].cmdData[ 'commStartTimeSec'] - 1 assert (self.comm.processMsg(testCmds[cmdId].serialize(), args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) == True) assert (self.comm.commStartTime != testCmds[cmdId].cmdData['commStartTimeSec'] ) # comm start time should not have been updated 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 __init__(self, configFile, meshNum, runFlag): super().__init__(name="CommProcess") # Node control run flag self.nodeControlRunFlag = runFlag # Configuration self.nodeParams = NodeParams(configFile=configFile) # Node/Comm interface interfaceConfig = { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': self.nodeParams.config.rxBufferSize, 'ipAddr': self.nodeParams.config.interface['nodeCommIntIP'], 'readPort': self.nodeParams.config.interface['commRdPort'], 'writePort': self.nodeParams.config.interface['commWrPort'] } #self.interface = SerialComm([], UDPRadio(interfaceConfig), SLIPMsgParser({'parseMsgMax': self.nodeParams.config.parseMsgMax})) self.interface = SerialComm( [], self.nodeParams, UDPRadio(interfaceConfig), MsgParser({'parseMsgMax': self.nodeParams.config.parseMsgMax}, SLIPMsg(256))) # UDP connection to node control process # Interprocess data package (Google protocol buffer interface to node control process) self.dataPackage = NodeThreadMsg() self.cmdTxLog = {} self.lastNodeCmdTime = [] ## Create comm object # Serial connection ser = serial.Serial(port=self.nodeParams.config.meshDevices[meshNum], baudrate=self.nodeParams.config.meshBaudrate, timeout=0) # Radio radioConfig = { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': self.nodeParams.config.rxBufferSize } if (self.nodeParams.config.commConfig['fpga'] == True): from mesh.generic.fpgaRadio import FPGARadio radio = FPGARadio(ser, radioConfig) else: if self.nodeParams.config.radios[meshNum] == "Xbee": radio = XbeeRadio(ser, radioConfig, "P8_12") elif self.nodeParams.config.radios[meshNum] == "Li-1": radio = Li1Radio(ser, radioConfig) # Message parser parserConfig = {'parseMsgMax': self.nodeParams.config.parseMsgMax} if self.nodeParams.config.msgParsers[meshNum] == "HDLC": msgParser = MsgParser(parserConfig, HDLCMsg(256)) elif self.nodeParams.config.msgParsers[meshNum] == "standard": msgParser = MsgParser(parserConfig) # Create comm if (self.nodeParams.config.commConfig['fpga'] == True): from mesh.generic.tdmaComm_fpga import TDMAComm_FPGA as TDMAComm else: from mesh.generic.tdmaComm import TDMAComm self.comm = TDMAComm([], radio, msgParser, self.nodeParams) # Node control run time bounds if (self.nodeParams.config.commConfig['fpga'] == False ): # only needed for software-controlled comm if self.comm.transmitSlot == 1: # For first node, run any time after transmit slot self.maxNodeControlTime = self.comm.frameLength - self.comm.slotLength self.minNodeControlTime = self.comm.slotLength else: # For other nodes, avoid running near transmit slot self.minNodeControlTime = ( self.comm.transmitSlot - 2 ) * self.comm.slotLength # don't run within 1 slot of transmit self.maxNodeControlTime = self.comm.transmitSlot * self.comm.slotLength
import time import struct from collections import namedtuple from mesh.generic.tdmaState import TDMAStatus from mesh.generic.cmdDict import CmdDict from mesh.generic.nodeConfig import ParamId from mesh.generic.cmds import NodeCmds, TDMACmds, GndCmds from mesh.generic.commandMsg import CommandMsg from mesh.generic.command import Command from mesh.generic.nodeHeader import createHeader from mesh.generic.nodeParams import NodeParams from mesh.generic.nodeState import NodeState, LinkStatus from unittests.testConfig import configFilePath nodeParams = NodeParams(configFile=configFilePath) # 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()])
def __init__(self, configFile, runFlag): super().__init__(name="NodeControlProcess", ) # Run flag self.runFlag = runFlag # Configuration nodeParams = NodeParams(configFile=configFile) # Flight computer serial port FCSer = serial.Serial(port=nodeParams.config.FCCommDevice, baudrate=nodeParams.config.FCBaudrate, timeout=0) # Create radios radios = [] radioConfig = { 'uartNumBytesToRead': nodeParams.config.uartNumBytesToRead, 'rxBufferSize': nodeParams.config.rxBufferSize, 'ipAddr': nodeParams.config.interface['nodeCommIntIP'], 'readPort': nodeParams.config.interface['commWrPort'], 'writePort': nodeParams.config.interface['commRdPort'] } for i in range(nodeParams.config.numMeshNetworks): radios.append( UDPRadio(radioConfig)) # connection to communication processes FCRadio = Radio(FCSer, radioConfig) # Create message parsers msgParsers = [] parserConfig = {'parseMsgMax': nodeParams.config.parseMsgMax} for i in range(nodeParams.config.numMeshNetworks): if nodeParams.config.msgParsers[i] == "SLIP": msgParsers.append(SLIPMsgParser(parserConfig)) elif nodeParams.config.msgParsers[i] == "standard": msgParsers.append(MsgParser(parserConfig)) FCMsgParser = SLIPMsgParser(parserConfig) # Open logfiles currentTime = str(time.time()) FCLogFilename = 'fc_' + currentTime + '.log' self.FCLogFile = open(FCLogFilename, 'w') nodeCommLogFilename = 'node_' + currentTime + '.log' self.nodeCommLogFile = open(nodeCommLogFilename, 'w') # Failsafe LED interval failsafeLEDTime = 1.0 # seconds failsafeLEDOnTime = -1.0 failsafeLEDOn = False # Initialize node and flight computer communication variables nodeComm = [[]] * nodeParams.config.numMeshNetworks FCComm = [] # Instantiate specific node software self.nodeController = [] self.nodeExecutive = [] for case in switch(nodeParams.config.platform ): # Platform specific initializations if case("SpecificNode"): pass else: # generic node from mesh.generic.nodeComm import NodeComm from mesh.generic.nodeController import NodeController from mesh.generic.nodeExecutive import NodeExecutive print("Initializing generic node") # Initialize communication variables for i in range(nodeParams.config.numMeshNetworks): nodeComm[i] = NodeComm([], radios[i], msgParsers[i], nodeParams) FCComm = NodeComm([], FCRadio, FCMsgParser, nodeParams) # Node controller self.nodeController = NodeController(nodeParams, self.nodeCommLogFile) # Node executive self.nodeExecutive = NodeExecutive(nodeParams, self.nodeController, nodeComm, FCComm, self.FCLogFile)
class TestNodeParams: def setup_method(self, method): # Create NodeConfig instance self.nodeConfig = NodeConfig(configFilePath) if method.__name__ != "test_init": self.nodeParams = NodeParams( config=self.nodeConfig) # Create NodeParams instance def test_init(self): """Test NodeParams init function.""" # Test that init function loads node configuration from file print("Testing init with configFile") nodeParams = NodeParams(configFile=configFilePath) assert (nodeParams.config.__dict__ == self.nodeConfig.__dict__) # Test that init function loads node configuration from provided config nodeParams = NodeParams(config=self.nodeConfig) assert (nodeParams.config.__dict__ == self.nodeConfig.__dict__) def test_getCmdCounter(self): """Test NodeParams command counter get function.""" # Test getting random command counter counter = self.nodeParams.get_cmdCounter() assert (counter >= 1) # value within range assert (counter <= 65536) # value within range # Test getting time-based command counter (NOTE: time-based counter commented out) #self.nodeParams.commStartTime = time.time() #time.sleep(0.5) #counter = self.nodeParams.get_cmdCounter() #assert(counter >= 0.5 * 1000) #assert(counter <= 0.6 * 1000) def test_checkNodeLinks(self): nodeId = self.nodeParams.config.nodeId - 1 # Test for direct link self.nodeParams.nodeStatus[2].present = True self.nodeParams.nodeStatus[2].lastMsgRcvdTime = time.time( ) - 0.90 * self.nodeParams.config.commConfig['linkTimeout'] self.nodeParams.checkNodeLinks() assert (self.nodeParams.linkStatus[nodeId][2] == LinkStatus.GoodLink) # Test for indirect link self.nodeParams.nodeStatus[2].present = False self.nodeParams.nodeStatus[2].updating = True self.nodeParams.checkNodeLinks() assert ( self.nodeParams.linkStatus[nodeId][2] == LinkStatus.IndirectLink) # Test for no link self.nodeParams.nodeStatus[2].present = False self.nodeParams.nodeStatus[2].updating = False self.nodeParams.checkNodeLinks() assert (self.nodeParams.linkStatus[nodeId][2] == LinkStatus.NoLink) def test_updateStatus(self): """Test updateStatus method of NodeParams.""" # Test without confirmed config self.nodeParams.updateStatus() assert (self.nodeParams.nodeStatus[self.nodeParams.config.nodeId - 1].status == 0) # Test with confirmed config self.nodeParams.configConfirmed = True self.nodeParams.updateStatus() assert (self.nodeParams.nodeStatus[self.nodeParams.config.nodeId - 1].status == 64) def test_loadConfig(self): """Test loadConfig method of NodeParams.""" # Create new config for update newConfig = NodeConfig(configFilePath) newConfigHash = newConfig.calculateHash() with open(configFilePath, "r") as jsonFile: configData = json.load(jsonFile) newConfig_pb = NodeConfig.toProtoBuf(configData).SerializeToString() # Test update method badHash = hashlib.sha1() assert (self.nodeParams.loadConfig(newConfig_pb, badHash) == False ) # test rejection with bad hash assert (self.nodeParams.newConfig == None) assert (self.nodeParams.loadConfig(newConfig_pb, newConfigHash) == True ) # test acceptance assert (self.nodeParams.newConfig != None) def test_updateConfig(self): """Test updateConfig method of NodeParams.""" # Load valid new config newConfig = NodeConfig(configFilePath) newConfigHash = newConfig.calculateHash() with open(configFilePath, "r") as jsonFile: configData = json.load(jsonFile) newConfig_pb = NodeConfig.toProtoBuf(configData).SerializeToString() self.nodeParams.loadConfig(newConfig_pb, newConfigHash) # Test successful loading self.nodeParams.config.FCBaudrate = newConfig.FCBaudrate / 2.0 # change a parameter to verify loading of new config assert (self.nodeParams.config.FCBaudrate != newConfig.FCBaudrate) assert (self.nodeParams.updateConfig() == True) assert (self.nodeParams.config.FCBaudrate == newConfig.FCBaudrate) assert (self.nodeParams.newConfig == None) # Expect no load when config missing assert (self.nodeParams.updateConfig() == False)
def setup_method(self, method): self.nodeParams = NodeParams(configFile=configFilePath) self.radio = UDPRadio({'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000, 'ipAddr': "127.0.0.1", 'readPort': 5000, 'writePort': 5000})
def setup_method(self, method): nodeParams = NodeParams(configFile=configFilePath) self.nodeController = NodeController(nodeParams)
import serial import os, time, sys from natsort import natsorted from multiprocessing import Value from mesh.generic.nodeParams import NodeParams from commProcess import CommProcess from nodeControlProcess import NodeControlProcess # Execute communication and node control as separate processes if __name__ == '__main__': # Node control shared run flag runFlag = Value('B', 1) # Load network node configuration configFile = 'nodeConfig.json' nodeParams = NodeParams(configFile=configFile) # Create node communication processes (one process per network) commProcesses = [None] * nodeParams.config.numMeshNetworks for i in range(nodeParams.config.numMeshNetworks): commProcesses[i] = CommProcess(configFile, i, runFlag) commProcesses[i].daemon = True # Create node control process nodeControlProcess = NodeControlProcess(configFile, runFlag) nodeControlProcess.daemon = True # run node control as a daemon # Start processes for process in commProcesses: process.start()
class TestNodeParams: def setup_method(self, method): # Create NodeConfig instance self.nodeConfig = NodeConfig(configFilePath) if method.__name__ != "test_init": self.nodeParams = NodeParams(config=self.nodeConfig) # Create NodeParams instance def test_init(self): """Test NodeParams init function.""" # Test that init function loads node configuration from file print("Testing init with configFile") nodeParams = NodeParams(configFile=configFilePath) assert(nodeParams.config.__dict__ == self.nodeConfig.__dict__) # Test that init function loads node configuration from provided config nodeParams = NodeParams(config=self.nodeConfig) assert(nodeParams.config.__dict__ == self.nodeConfig.__dict__) def test_getCmdCounter(self): """Test NodeParams command counter get function.""" # Test getting random command counter counter = self.nodeParams.get_cmdCounter() assert(counter >= 1) # value within range assert(counter <= 65536) # value within range # Test getting time-based command counter (NOTE: time-based counter commented out) #self.nodeParams.commStartTime = time.time() #time.sleep(0.5) #counter = self.nodeParams.get_cmdCounter() #assert(counter >= 0.5 * 1000) #assert(counter <= 0.6 * 1000) def test_checkNodeLinks(self): nodeId = self.nodeParams.config.nodeId - 1 # Test for direct link self.nodeParams.nodeStatus[2].present = True self.nodeParams.nodeStatus[2].lastMsgRcvdTime = time.time() - 0.90 * self.nodeParams.config.commConfig['linkTimeout'] self.nodeParams.checkNodeLinks() assert(self.nodeParams.linkStatus[nodeId][2] == LinkStatus.GoodLink) # Test for indirect link self.nodeParams.nodeStatus[2].present = False self.nodeParams.nodeStatus[2].updating = True self.nodeParams.checkNodeLinks() assert(self.nodeParams.linkStatus[nodeId][2] == LinkStatus.IndirectLink) # Test for no link self.nodeParams.nodeStatus[2].present = False self.nodeParams.nodeStatus[2].updating = False self.nodeParams.checkNodeLinks() assert(self.nodeParams.linkStatus[nodeId][2] == LinkStatus.NoLink) def test_updateStatus(self): """Test updateStatus method of NodeParams.""" # Test without confirmed config self.nodeParams.updateStatus() assert(self.nodeParams.nodeStatus[self.nodeParams.config.nodeId-1].status == 0) # Test with confirmed config self.nodeParams.configConfirmed = True self.nodeParams.updateStatus() assert(self.nodeParams.nodeStatus[self.nodeParams.config.nodeId-1].status == 64)
def setup_method(self, method): self.nodeParams = NodeParams(configFile=configFilePath) self.commProcessor = CommProcessor([], self.nodeParams) msgParser = SLIPMsgParser( {'parseMsgMax': self.nodeParams.config.parseMsgMax}) self.comm = TDMAComm([], [], msgParser, self.nodeParams)
class TestTDMABlockTx: def setup_method(self, method): if testSerialPort: serialPort = serial.Serial(port=testSerialPort, baudrate=57600, timeout=0) else: serialPort = [] self.nodeParams = NodeParams(configFile=configFilePath) self.nodeParams.commStartTime = time.time() self.nodeParams.config.commConfig['transmitSlot'] = 1 self.radio = Radio( serialPort, { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 }) commProcessor = CommProcessor([TDMACmdProcessor, TestCmdProcessor], self.nodeParams) msgParser = SLIPMsgParser( {'parseMsgMax': self.nodeParams.config.parseMsgMax}) self.tdmaComm = TDMAComm(commProcessor, self.radio, msgParser, self.nodeParams) self.tdmaComm.nodeParams.frameStartTime = time.time() def test_populateBlockResponseList(self): """Test populateBlockResponseList method of TDMAComm.""" # Set node presence flags presentNodes = [1, 2, 3] for node in presentNodes: self.nodeParams.nodeStatus[node - 1].present = True self.tdmaComm.populateBlockResponseList() for node in presentNodes: assert (node in self.tdmaComm.blockTxStatus['blockResponseList']) def test_checkBlockResponse(self): """Test checkBlockResponse method of TDMAComm.""" # Set block response list self.tdmaComm.blockTxStatus['blockResponseList'] = { 1: None, 2: None, 3: None } # False response test self.tdmaComm.blockTxStatus['blockResponseList'][2] = False assert (self.tdmaComm.checkBlockResponse() == False) # Waiting for responses test self.tdmaComm.blockTxStatus['blockResponseList'][2] = True assert (self.tdmaComm.checkBlockResponse() == None) # True responses test for node in self.tdmaComm.blockTxStatus['blockResponseList']: self.tdmaComm.blockTxStatus['blockResponseList'][node] = True assert (self.tdmaComm.checkBlockResponse() == True) def test_sendDataBlock(self): """Test sendDataBlock method of TDMAComm.""" # Manually set frame start time self.tdmaComm.frameStartTime = time.time() dataBlock = b'1234567890' * 50 self.tdmaComm.sendDataBlock(dataBlock) # Check data stored and block tx request sent assert (self.tdmaComm.dataBlock == dataBlock) # data block stored header, msgContents = deserialize( self.tdmaComm.radio.txBuffer[1:-3], TDMACmds['BlockTxRequest'] ) # parse only raw message portions of output assert (msgContents['blockReqID'] == self.tdmaComm.blockTxStatus['blockReqID']) assert (msgContents['startTime'] == self.tdmaComm.blockTxStatus['startTime']) assert (msgContents['length'] == self.tdmaComm.blockTxStatus['length']) def test_monitorBlockTx(self): """Test monitorBlockTx method of TDMAComm.""" # Manually set frame start time self.tdmaComm.frameStartTime = time.time() ## Test block pending behavior # Check for block request response checks self.setupBlockRequest('tx') for node in self.tdmaComm.blockTxStatus['blockResponseList']: self.tdmaComm.blockTxStatus['blockResponseList'][node] = True self.tdmaComm.monitorBlockTx() assert (self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.confirmed) # Check for request timeout self.setupBlockRequest('tx') self.tdmaComm.frameStartTime += 0.5 * self.nodeParams.config.commConfig[ 'blockTxRequestTimeout'] * self.nodeParams.config.commConfig[ 'frameLength'] self.tdmaComm.monitorBlockTx() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.pending) self.tdmaComm.frameStartTime += 0.5 * self.nodeParams.config.commConfig[ 'blockTxRequestTimeout'] * self.nodeParams.config.commConfig[ 'frameLength'] + 0.1 self.tdmaComm.monitorBlockTx() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.false) # Check for cancel when not confirmed self.setupBlockRequest('rx') self.tdmaComm.frameStartTime = self.tdmaComm.blockTxStatus[ 'requestTime'] self.tdmaComm.frameStartTime += 0.5 * ( self.tdmaComm.blockTxStatus['startTime'] - self.tdmaComm.blockTxStatus['requestTime']) self.tdmaComm.monitorBlockTx() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.pending) self.tdmaComm.frameStartTime += 0.5 * ( self.tdmaComm.blockTxStatus['startTime'] - self.tdmaComm.blockTxStatus['requestTime']) self.tdmaComm.monitorBlockTx() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.false) ## Test block confirmed behavior # Check for change to active block tx status self.setupBlockRequest('rx') self.tdmaComm.blockTxStatus['status'] = TDMABlockTxStatus.confirmed self.tdmaComm.frameStartTime = self.tdmaComm.blockTxStatus[ 'requestTime'] self.tdmaComm.frameStartTime += 0.5 * ( self.tdmaComm.blockTxStatus['startTime'] - self.tdmaComm.blockTxStatus['requestTime']) self.tdmaComm.monitorBlockTx() assert (self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.confirmed) self.tdmaComm.frameStartTime += 0.5 * ( self.tdmaComm.blockTxStatus['startTime'] - self.tdmaComm.blockTxStatus['requestTime']) self.tdmaComm.monitorBlockTx() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.active) # Check block tx status message sent self.tdmaComm.radio.txBuffer = bytearray() self.setupBlockRequest() self.tdmaComm.blockTxStatus['status'] = TDMABlockTxStatus.confirmed self.tdmaComm.frameStartTime = self.tdmaComm.blockTxStatus[ 'requestTime'] self.tdmaComm.monitorBlockTx() print(self.tdmaComm.radio.txBuffer) header, msgContents = deserialize(self.tdmaComm.radio.txBuffer, TDMACmds['BlockTxStatus']) assert (msgContents['blockReqID'] == self.tdmaComm.blockTxStatus['blockReqID']) assert (msgContents['startTime'] == self.tdmaComm.blockTxStatus['startTime']) assert (msgContents['length'] == self.tdmaComm.blockTxStatus['length']) ## Test block active behavior # Check for block end from time self.setupBlockTxActive() self.tdmaComm.monitorBlockTx() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.active) self.tdmaComm.frameStartTime += self.tdmaComm.blockTxStatus[ 'length'] * self.nodeParams.config.commConfig['frameLength'] self.tdmaComm.monitorBlockTx() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.false) # Check for block end from complete flag set self.setupBlockTxActive() self.tdmaComm.monitorBlockTx() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.active) self.tdmaComm.blockTxStatus['blockTxComplete'] = True self.tdmaComm.monitorBlockTx() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.false) # Check for block end from status set to nominal self.setupBlockTxActive() self.tdmaComm.monitorBlockTx() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.active) self.nodeParams.tdmaStatus = TDMAStatus.nominal self.tdmaComm.monitorBlockTx() assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.false) def test_sendBlock(self): """Test sendBlock method of TDMAComm.""" dataBlock = b'1234567890' * 50 # Check for blockTxComplete set if no data block assert (self.tdmaComm.blockTxStatus['blockTxComplete'] == False) self.tdmaComm.sendBlock() assert (self.tdmaComm.blockTxStatus['blockTxComplete'] == True) ## Test that block is sent in appropriately sized chunks self.tdmaComm.blockTxStatus[ 'blockTxComplete'] = False # reset block tx complete flag self.nodeParams.config.commConfig['maxBlockTransferSize'] = int( len(dataBlock) / 2) + 1 # half of block + 1 self.tdmaComm.dataBlock = dataBlock self.tdmaComm.sendBlock() time.sleep(0.1) # Check that max block transfer sized chunk sent assert (self.tdmaComm.dataBlockPos == self.nodeParams.config.commConfig['maxBlockTransferSize']) self.tdmaComm.radio.readBytes(True) assert (self.tdmaComm.radio.bytesInRxBuffer == self.nodeParams.config.commConfig['maxBlockTransferSize']) assert (self.tdmaComm.blockTxStatus['blockTxComplete'] == False) # Check that rest of block sent self.tdmaComm.radio.clearRxBuffer() self.tdmaComm.sendBlock() time.sleep(0.1) assert (self.tdmaComm.dataBlockPos == 0) self.tdmaComm.radio.readBytes(True) assert ( self.tdmaComm.radio.bytesInRxBuffer == int(len(dataBlock) / 2) + 1 ) # half of block + END byte assert (self.tdmaComm.blockTxStatus['blockTxComplete'] == True) #def test_dumpBlockData(self): # """Test dumpBlockData method of TDMAComm.""" # self.tdmaComm.receivedBlockData = b'1234567890'*10 # self.tdmaComm.dumpBlockData('./') # assert(len(self.tdmaComm.receivedBlockData) == 0) 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) 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 test_blockTxEndTime(self): """Test block transmit ended due to block length reached.""" # Force init self.tdmaComm.meshInited = True # Start block transmit self.initiateBlockTransmit() self.tdmaComm.blockTxStatus['status'] = TDMABlockTxStatus.confirmed self.tdmaComm.frameStartTime = self.tdmaComm.blockTxStatus['startTime'] self.tdmaComm.execute(self.tdmaComm.frameStartTime) assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.active) assert (self.nodeParams.tdmaStatus == TDMAStatus.blockTx) # Advance to block end and check that block terminated self.tdmaComm.frameStartTime += self.nodeParams.config.commConfig[ 'frameLength'] * self.tdmaComm.blockTxStatus['length'] self.tdmaComm.execute(self.nodeParams.frameStartTime) assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.false) assert (self.nodeParams.tdmaStatus == TDMAStatus.nominal) 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_nodePresenceUpdate(self): """Test that node presence does not timeout during block transmits.""" self.nodeParams.frameStartTime = time.time() self.tdmaComm.blockTxStatus['status'] = TDMABlockTxStatus.active self.tdmaComm.blockTxStatus[ 'txNode'] = self.nodeParams.config.nodeId + 1 self.tdmaComm.blockTxStatus['length'] = 10 self.tdmaComm.blockTxStatus[ 'startTime'] = self.nodeParams.frameStartTime self.nodeParams.tdmaStatus = TDMAStatus.blockTx # Set present nodes self.nodeParams.nodeStatus[1].present = True self.nodeParams.nodeStatus[2].present = True # Propagate time and check that node update time is updated self.tdmaComm.execute(0.0) assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.active) assert ((self.nodeParams.nodeStatus[1].lastStateUpdateTime - time.time()) <= 0.001) time.sleep(5.0) self.tdmaComm.execute(0.0) assert ( self.tdmaComm.blockTxStatus['status'] == TDMABlockTxStatus.active) assert ((self.nodeParams.nodeStatus[1].lastStateUpdateTime - time.time()) <= 0.001) def initiateBlockTransmit(self): """Initiate block transmit process.""" 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.tdmaComm.sendDataBlock(dataBlock) def setupBlockTxActive(self): self.setupBlockRequest('tx') self.tdmaComm.blockTxStatus['status'] = TDMABlockTxStatus.active self.nodeParams.tdmaStatus = TDMAStatus.blockTx self.tdmaComm.frameStartTime = self.tdmaComm.blockTxStatus['startTime'] def setupBlockRequest(self, role='tx'): self.tdmaComm.resetBlockTxStatus() currentTime = time.time() self.tdmaComm.blockTxStatus['blockReqID'] = 5 self.tdmaComm.blockTxStatus['startTime'] = int( currentTime + self.nodeParams.config.commConfig['minBlockTxDelay'] * self.nodeParams.config.commConfig['frameLength']) self.tdmaComm.blockTxStatus['length'] = 5 # Set block response list self.tdmaComm.blockTxStatus['blockResponseList'] = { 1: None, 2: None, 3: None } if role == 'tx': # This node transmitting self.tdmaComm.blockTxStatus[ 'txNode'] = self.nodeParams.config.nodeId else: self.tdmaComm.blockTxStatus[ 'txNode'] = self.nodeParams.config.nodeId + 1 self.tdmaComm.blockTxStatus['status'] = TDMABlockTxStatus.pending self.tdmaComm.blockTxStatus['requestTime'] = currentTime
class TestTDMACmdProcessor: def setup_method(self, method): self.nodeStatus = [NodeState(i + 1) for i in range(5)] self.nodeParams = NodeParams(configFile=configFilePath) self.commProcessor = CommProcessor([TDMACmdProcessor], self.nodeParams) msgParser = SLIPMsgParser( {'parseMsgMax': self.nodeParams.config.parseMsgMax}) radio = Radio( [], { 'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000 }) self.comm = TDMAComm(self.commProcessor, radio, msgParser, self.nodeParams) def test_validateBlockTxRequest(self): """Test validateBlockTxRequest method of TDMACmdProcessor.""" # Test request rejected if start time passed contents = { 'startTime': time.time() - 1.0, 'length': self.nodeParams.config.commConfig['maxTxBlockSize'] } assert (validateBlockTxRequest(contents, [], self.nodeParams) == False) # Test request rejected if block too long contents = { 'startTime': time.time() + 1.0, 'length': self.nodeParams.config.commConfig['maxTxBlockSize'] + 1 } assert (validateBlockTxRequest(contents, [], self.nodeParams) == False) # Test for request acceptance contents = { 'startTime': time.time() + 1.0, 'length': self.nodeParams.config.commConfig['maxTxBlockSize'] } assert (validateBlockTxRequest(contents, [], self.nodeParams) == True) def test_processMsg(self): """Test processMsg method of TDMACmdProcessor.""" # Test processing of all TDMACmds for cmdId in cmdsToTest: cmdMsg = packHeader(testCmds[cmdId].header) + testCmds[cmdId].body self.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) if cmdId == TDMACmds['TimeOffset']: sourceId = testCmds[cmdId].header['header']['sourceId'] assert ( self.nodeStatus[sourceId - 1].timeOffset == testCmds[cmdId].body[0] / 100.0) elif cmdId == TDMACmds['TimeOffsetSummary']: for i in range(len(testCmds[cmdId].cmdData['nodeStatus'])): assert (self.nodeStatus[i].timeOffset == testCmds[cmdId]. cmdData['nodeStatus'][i].timeOffset) elif cmdId == TDMACmds['MeshStatus']: assert (self.nodeParams.commStartTime == testCmds[cmdId].cmdData['commStartTimeSec']) # Resend and test that commStartTime is not updated once it has previously been set cmdId = TDMACmds['MeshStatus'] self.nodeParams.commStartTime = testCmds[cmdId].cmdData[ 'commStartTimeSec'] - 1 cmdMsg = packHeader(testCmds[cmdId].header) + testCmds[cmdId].body self.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) assert (self.nodeParams.commStartTime != testCmds[cmdId].cmdData['commStartTimeSec']) def test_blockTxCmdsProcessing(self): """Test processing of block transmit related commands.""" self.nodeParams.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 self.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) 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()) self.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) 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 self.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) 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 self.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) 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 self.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) 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()) self.commProcessor.processMsg(cmdMsg, args={ 'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock }) assert (self.comm.blockTxStatus['blockResponseList'][1] == False)