├── .gitignore ├── LICENSE ├── README.md ├── cpp ├── Makefile ├── comm │ ├── .xbeeRadio.cpp.swp │ ├── .xbeeRadio.cpp.swx │ ├── SLIPMsg.cpp │ ├── SLIPMsg.hpp │ ├── SLIPMsgParser.cpp │ ├── SLIPMsgParser.hpp │ ├── checksum.cpp │ ├── checksum.hpp │ ├── cmdHeader.cpp │ ├── cmdHeader.hpp │ ├── commBuffer.hpp │ ├── commControl.cpp │ ├── commControl.hpp │ ├── command.cpp │ ├── command.hpp │ ├── commandSupport.hpp │ ├── commandUtils.cpp │ ├── commandUtils.hpp │ ├── commands.cpp │ ├── commands.hpp │ ├── crc.hpp │ ├── crc_16.cpp │ ├── crc_16.hpp │ ├── crc_8.cpp │ ├── crc_8.hpp │ ├── defines.hpp │ ├── exceptions.hpp │ ├── formationClock.cpp │ ├── formationClock.hpp │ ├── fpgaRadio.cpp │ ├── fpgaRadio.hpp │ ├── li1Radio.cpp │ ├── li1Radio.hpp │ ├── message.hpp │ ├── msgParser.cpp │ ├── msgParser.hpp │ ├── msgProcessor.hpp │ ├── nodeCmds.cpp │ ├── nodeCmds.hpp │ ├── nodeMsgProcessor.cpp │ ├── nodeMsgProcessor.hpp │ ├── radio.cpp │ ├── radio.hpp │ ├── serialComm.cpp │ ├── serialComm.hpp │ ├── serialRadio.cpp │ ├── serialRadio.hpp │ ├── tdmaCmds.cpp │ ├── tdmaCmds.hpp │ ├── tdmaComm.cpp │ ├── tdmaComm.hpp │ ├── tdmaComm_fpga.cpp │ ├── tdmaComm_fpga.hpp │ ├── tdmaMsgProcessor.cpp │ ├── tdmaMsgProcessor.hpp │ ├── tdmaTime.hpp │ ├── testMsgProcessor.cpp │ ├── testMsgProcessor.hpp │ ├── udpRadio.cpp │ ├── udpRadio.hpp │ ├── utilities.cpp │ ├── utilities.hpp │ ├── xbeeRadio.cpp │ └── xbeeRadio.hpp ├── commControl.cpp ├── lib │ ├── GPIOWrapper │ │ ├── GPIOWrapper.cpp │ │ ├── GPIOWrapper.hpp │ │ ├── GPIOWrapper_BBB.cpp │ │ ├── GPIOWrapper_PI.cpp │ │ └── Makefile │ └── rapidjson │ │ ├── JSON_Document.cpp │ │ ├── JSON_Document.d │ │ ├── JSON_Document.hpp │ │ ├── JSON_Value.cpp │ │ ├── JSON_Value.d │ │ ├── JSON_Value.hpp │ │ ├── JSON_Values.cpp │ │ ├── JSON_Values.d │ │ ├── JSON_Values.hpp │ │ ├── JSON_Wrapper.cpp │ │ ├── JSON_Wrapper.d │ │ ├── JSON_Wrapper.hpp │ │ ├── Makefile │ │ ├── allocators.h │ │ ├── document.h │ │ ├── encodedstream.h │ │ ├── encodings.h │ │ ├── error │ │ ├── en.h │ │ └── error.h │ │ ├── filereadstream.h │ │ ├── filewritestream.h │ │ ├── internal │ │ ├── biginteger.h │ │ ├── diyfp.h │ │ ├── dtoa.h │ │ ├── ieee754.h │ │ ├── itoa.h │ │ ├── meta.h │ │ ├── pow10.h │ │ ├── stack.h │ │ ├── strfunc.h │ │ └── strtod.h │ │ ├── memorybuffer.h │ │ ├── memorystream.h │ │ ├── msinttypes │ │ ├── inttypes.h │ │ └── stdint.h │ │ ├── prettywriter.h │ │ ├── rapidjson.h │ │ ├── reader.h │ │ ├── rules.mk │ │ ├── stringbuffer.h │ │ └── writer.h ├── node │ ├── nodeCmds.cpp │ ├── nodeCmds.hpp │ ├── nodeConfig.cpp │ ├── nodeConfig.hpp │ ├── nodeConfigSupport.hpp │ ├── nodeControl.cpp │ ├── nodeControl.hpp │ ├── nodeController.cpp │ ├── nodeController.hpp │ ├── nodeExecutive.cpp │ ├── nodeExecutive.hpp │ ├── nodeInterface.cpp │ ├── nodeInterface.hpp │ ├── nodeInterface.pb.cpp │ ├── nodeInterface.pb.h │ ├── nodeParams.cpp │ ├── nodeParams.hpp │ ├── nodeState.cpp │ └── nodeState.hpp ├── nodeConfig.json ├── nodeConfig_bad.json ├── nodeConfig_noNodeId.json ├── readme.md ├── rules.mk ├── runTest.cpp ├── runTest.py └── tests │ ├── SLIPMsgParser_UT.cpp │ ├── SLIPMsgParser_UT.hpp │ ├── SLIPMsg_UT.cpp │ ├── SLIPMsg_UT.hpp │ ├── checksum_UT.cpp │ ├── checksum_UT.hpp │ ├── cmdHeader_UT.cpp │ ├── cmdHeader_UT.hpp │ ├── commBuffer_UT.cpp │ ├── commBuffer_UT.hpp │ ├── commProcessor_UT.cpp │ ├── commProcessor_UT.hpp │ ├── commandUtils_UT.cpp │ ├── commandUtils_UT.hpp │ ├── command_UT.cpp │ ├── command_UT.hpp │ ├── crc_UT.cpp │ ├── crc_UT.hpp │ ├── formationClock_UT.cpp │ ├── formationClock_UT.hpp │ ├── li1Radio_UT.cpp │ ├── li1Radio_UT.hpp │ ├── msgParser_UT.cpp │ ├── msgParser_UT.hpp │ ├── nodeCmds_UT.cpp │ ├── nodeCmds_UT.hpp │ ├── nodeConfig_UT.cpp │ ├── nodeConfig_UT.hpp │ ├── nodeMsgProcessor_UT.cpp │ ├── nodeMsgProcessor_UT.hpp │ ├── nodeParams_UT.cpp │ ├── nodeParams_UT.hpp │ ├── radio_UT.cpp │ ├── radio_UT.hpp │ ├── serialComm_UT.cpp │ ├── serialComm_UT.hpp │ ├── serialRadio_UT.cpp │ ├── serialRadio_UT.hpp │ ├── tdmaCmds_UT.cpp │ ├── tdmaCmds_UT.hpp │ ├── tdmaComm_UT.cpp │ ├── tdmaComm_UT.hpp │ ├── tdmaMsgProcessor_UT.cpp │ ├── tdmaMsgProcessor_UT.hpp │ ├── utilities_UT.cpp │ ├── utilities_UT.hpp │ ├── xbeeRadio_UT.cpp │ └── xbeeRadio_UT.hpp ├── doc ├── Makefile ├── README ├── build │ ├── doctrees │ │ ├── api.doctree │ │ ├── config.doctree │ │ ├── cpp.doctree │ │ ├── design.doctree │ │ ├── environment.pickle │ │ ├── hardware.doctree │ │ ├── hostInterface.doctree │ │ ├── index.doctree │ │ ├── mesh.doctree │ │ ├── mesh.generic.doctree │ │ ├── mesh.interface.doctree │ │ ├── python.doctree │ │ ├── setup.doctree │ │ ├── software.doctree │ │ ├── unittests.doctree │ │ └── vhdl.doctree │ └── html │ │ ├── .buildinfo │ │ ├── _images │ │ ├── blockTx_sequence.png │ │ ├── hardware_1stgen.png │ │ ├── hardware_2ndgen_astrodev.png │ │ ├── hardware_2ndgen_xbee.png │ │ ├── hardware_currentgen.png │ │ ├── tdma_frame.png │ │ └── topology.png │ │ ├── _sources │ │ ├── api.rst.txt │ │ ├── config.rst.txt │ │ ├── cpp.rst.txt │ │ ├── design.rst.txt │ │ ├── hardware.rst.txt │ │ ├── hostInterface.rst.txt │ │ ├── index.rst.txt │ │ ├── mesh.generic.rst.txt │ │ ├── mesh.interface.rst.txt │ │ ├── mesh.rst.txt │ │ ├── python.rst.txt │ │ ├── setup.rst.txt │ │ ├── software.rst.txt │ │ ├── unittests.rst.txt │ │ └── vhdl.rst.txt │ │ ├── _static │ │ ├── ajax-loader.gif │ │ ├── alabaster.css │ │ ├── basic.css │ │ ├── comment-bright.png │ │ ├── comment-close.png │ │ ├── comment.png │ │ ├── custom.css │ │ ├── doctools.js │ │ ├── documentation_options.js │ │ ├── down-pressed.png │ │ ├── down.png │ │ ├── file.png │ │ ├── jquery-3.1.0.js │ │ ├── jquery-3.2.1.js │ │ ├── jquery-3.4.1.js │ │ ├── jquery.js │ │ ├── language_data.js │ │ ├── minus.png │ │ ├── plus.png │ │ ├── pygments.css │ │ ├── searchtools.js │ │ ├── underscore-1.3.1.js │ │ ├── underscore.js │ │ ├── up-pressed.png │ │ ├── up.png │ │ └── websupport.js │ │ ├── api.html │ │ ├── config.html │ │ ├── cpp.html │ │ ├── design.html │ │ ├── genindex.html │ │ ├── hardware.html │ │ ├── hostInterface.html │ │ ├── index.html │ │ ├── mesh.generic.html │ │ ├── mesh.html │ │ ├── mesh.interface.html │ │ ├── objects.inv │ │ ├── py-modindex.html │ │ ├── python.html │ │ ├── search.html │ │ ├── searchindex.js │ │ ├── setup.html │ │ ├── software.html │ │ ├── unittests.html │ │ └── vhdl.html ├── hardware_1stgen.png ├── hardware_2ndgen_astrodev.png ├── hardware_2ndgen_xbee.png ├── hardware_currentgen.png ├── source │ ├── conf.py │ ├── config.rst │ ├── cpp.rst │ ├── design.rst │ ├── hardware.rst │ ├── index.rst │ ├── mesh.generic.rst │ ├── mesh.interface.rst │ ├── mesh.rst │ ├── python.rst │ ├── software.rst │ ├── unittests.rst │ └── vhdl.rst ├── tdma_frame.png └── topology.png ├── interface ├── nodeConfig.proto ├── nodeInterface.pb.cc ├── nodeInterface.pb.h └── nodeInterface.proto ├── python ├── commProcess.py ├── demoController.py ├── execute.py ├── globalCfg.py ├── mesh │ ├── __init__.py │ ├── generic │ │ ├── __init__.py │ │ ├── blockTx.py │ │ ├── checksum.py │ │ ├── cmdDict.py │ │ ├── cmdProcessor.py │ │ ├── cmdStatus.py │ │ ├── cmds.py │ │ ├── commPorts.py │ │ ├── command.py │ │ ├── commandMsg.py │ │ ├── commandType.py │ │ ├── constants.py │ │ ├── customExceptions.py │ │ ├── deserialize.py │ │ ├── dijkstra.py │ │ ├── formationClock.py │ │ ├── fpgaRadio.py │ │ ├── gndCmdDict.py │ │ ├── gndCmdProcessor.py │ │ ├── gpio.py │ │ ├── hdlcMsg.py │ │ ├── hdlcMsgParser.py │ │ ├── li1Radio.py │ │ ├── li1RadioCmds.py │ │ ├── meshController.py │ │ ├── msgParser.py │ │ ├── multiProcess.py │ │ ├── navigation.py │ │ ├── nodeCmdProcessor.py │ │ ├── nodeConfig.py │ │ ├── nodeConfig_pb2.py │ │ ├── nodeController.py │ │ ├── nodeExecutive.py │ │ ├── nodeHeader.py │ │ ├── nodeParams.py │ │ ├── nodeState.py │ │ ├── nodeTools.py │ │ ├── pipeConn.py │ │ ├── radio.py │ │ ├── serialComm.py │ │ ├── slipMsg.py │ │ ├── slipMsgParser.py │ │ ├── slipMsgParser_li1.py │ │ ├── slipMsg_li1.py │ │ ├── tdmaCmdDict.py │ │ ├── tdmaCmdProcessor.py │ │ ├── tdmaComm.py │ │ ├── tdmaComm_fpga.py │ │ ├── tdmaState.py │ │ ├── tdmaTime.py │ │ ├── testCmdDict.py │ │ ├── testCmdProcessor.py │ │ ├── timeLib.py │ │ ├── udpRadio.py │ │ ├── utilities.py │ │ └── xbeeRadio.py │ └── interface │ │ ├── __init__.py │ │ └── nodeInterface_pb2.py ├── nodeConfig.json ├── nodeControlProcess.py ├── switch.py └── unittests │ ├── __init__.py │ ├── executeTests.py │ ├── generic │ ├── test_HDLCMsg.py │ ├── test_SLIPMsg.py │ ├── test_cmdProcessor.py │ ├── test_command.py │ ├── test_commandMsg.py │ ├── test_deserialize.py │ ├── test_dijkstra.py │ ├── test_formationClock.py │ ├── test_gndCmdProcessor.py │ ├── test_hdlcMsgParser.py │ ├── test_li1Radio.py │ ├── test_meshController.py │ ├── test_msgParser.py │ ├── test_navigation.py │ ├── test_nodeCmdProcessor.py │ ├── test_nodeConfig.py │ ├── test_nodeController.py │ ├── test_nodeExecutive.py │ ├── test_nodeHeader.py │ ├── test_nodeParams.py │ ├── test_radio.py │ ├── test_serialComm.py │ ├── test_slipMsgParser.py │ ├── test_tdmaCmdProcessor.py │ ├── test_tdmaComm.py │ ├── test_tdmaTime.py │ ├── test_udpRadio.py │ └── test_xbeeRadio.py │ ├── nodeConfig.json │ ├── nodeConfig_bad.json │ ├── nodeConfig_noNodeId.json │ ├── pixhawkNodeController.log │ ├── testCmds.py │ ├── testConfig.py │ ├── testHelpers.py │ └── test_blank.py └── vhdl ├── clockTime.vhd ├── commandTypes.vhd ├── compDec.vhd ├── crc16.vhd ├── customClock.vhd ├── dataParser.vhd ├── dataProcessor.vhd ├── dualRankSync.vhd ├── dualRankSyncBus.vhd ├── memController.vhd ├── memInterface.vhd ├── meshFPGA.vhd ├── meshPack.vhd ├── radio.vhd ├── rstDualRankSync.vhd ├── slip.vhd ├── tdma.vhd ├── tdmaCtrl.vhd ├── uart.vhd ├── uartFifo.vhd ├── uartRx.vhd ├── uartTx.vhd └── userInterface.vhd /.gitignore: -------------------------------------------------------------------------------- 1 | *.d 2 | *.o 3 | __pycache__/ 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # meshNetwork 2 | 3 | The Mesh Network Communication System is a peer-to-peer communication network architecture that enables communication between network nodes of various types. The initial primary goal of the system was to enable communication between small formations of cubesats or other small satellites, but the basic mesh architecture is applicable to data exchange between network assets of any type. The system has been flight tested on formations of small unmanned aerial systems (sUAS) and shown to provide low latency data throughput for dynamic flight environments. 4 | 5 | ### Documentation 6 | 7 | The full documentation is in the doc/build/html directory. 8 | 9 | ### License 10 | 11 | The Mesh Network software is released under the NASA Open Source Agreement Version 1.3 [license](LICENSE). 12 | 13 | 14 | ### Python dependencies 15 | pyserial 16 | crcmod 17 | -------------------------------------------------------------------------------- /cpp/comm/.xbeeRadio.cpp.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/cpp/comm/.xbeeRadio.cpp.swp -------------------------------------------------------------------------------- /cpp/comm/.xbeeRadio.cpp.swx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/cpp/comm/.xbeeRadio.cpp.swx -------------------------------------------------------------------------------- /cpp/comm/SLIPMsgParser.cpp: -------------------------------------------------------------------------------- 1 | #include "comm/SLIPMsgParser.hpp" 2 | #include "crc.hpp" 3 | #include "utilities.hpp" 4 | #include 5 | 6 | using std::vector; 7 | 8 | namespace comm { 9 | 10 | SLIPMsgParser::SLIPMsgParser(unsigned int parseMsgMaxIn, unsigned int SLIPMaxLength) : 11 | MsgParser(parseMsgMaxIn), 12 | slipMsg(SLIPMsg(SLIPMaxLength)) 13 | { 14 | }; 15 | 16 | unsigned int SLIPMsgParser::parseSerialMsg(const vector & msgBytes, unsigned int msgStart) { 17 | if (msgBytes.size() < 0) { // no message bytes 18 | return 0; 19 | } 20 | 21 | if (slipMsg.decodeSLIPMsg(msgBytes, msgStart) == true && slipMsg.msg.size() >= sizeof(crc8_t)) { // minimum size should be crc length 22 | // Compare CRC 23 | vector msgOnly = vector(slipMsg.msg.begin(), slipMsg.msg.end()-sizeof(crc8_t)); 24 | crc8_t crc = crc8_create(msgOnly); 25 | crc8_t msgCrc; 26 | util::serialBytesToVariable(slipMsg.msg, slipMsg.msg.size()-sizeof(msgCrc), &msgCrc); 27 | if (crc == msgCrc) { 28 | // Add message to parsed messages 29 | parsedMsgs.push_back(msgOnly); 30 | } 31 | return slipMsg.msgEnd; 32 | } 33 | return msgBytes.size(); // no message found - return length of parsed bytes 34 | } 35 | 36 | vector SLIPMsgParser::encodeMsg(vector msgBytes) { 37 | if (msgBytes.size() > 0) { 38 | // Add CRC 39 | crc8_t crc = crc8_create(msgBytes); 40 | util::variableToSerialBytes(msgBytes, crc); 41 | //msgBytes.push_back((uint8_t)((crc & 0xFF00) >> 8)); 42 | //msgBytes.push_back((uint8_t)((crc & 0x00FF))); 43 | return slipMsg.encodeSLIPMsg(msgBytes); 44 | 45 | } 46 | 47 | return vector(); // no message 48 | 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /cpp/comm/SLIPMsgParser.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_SLIP_MSG_PARSER_HPP 2 | #define COMM_SLIP_MSG_PARSER_HPP 3 | 4 | #include "comm/defines.hpp" 5 | #include "msgParser.hpp" 6 | #include "SLIPMsg.hpp" 7 | #include 8 | 9 | namespace comm { 10 | 11 | class SLIPMsgParser : public MsgParser { 12 | 13 | public: 14 | /** 15 | * SLIPMsg instance. 16 | */ 17 | SLIPMsg slipMsg; 18 | 19 | /** 20 | * Default constructor. 21 | */ 22 | SLIPMsgParser() : slipMsg(SLIPMsg(256)) {}; 23 | 24 | /** 25 | * Constructor. 26 | * @param parseMsgMaxIn Message parsing limit 27 | * @param SLIPMaxLength Maximum length of SLIP message 28 | */ 29 | SLIPMsgParser(unsigned int parseMsgMaxIn, unsigned int SLIPMaxLength); 30 | 31 | /** 32 | * This function searches raw byte for a message. 33 | * @param msgBytes The raw bytes of a message. 34 | * @param msgStart Index to begin search. 35 | * @return Length of parsed message. 36 | */ 37 | virtual unsigned int parseSerialMsg(const std::vector & msgBytes, unsigned int msgStart); 38 | 39 | /** 40 | * This function encodes raw input bytes into a message for serial transmission. 41 | * @param msgBytes Bytes to be encoded. 42 | */ 43 | virtual std::vector encodeMsg(std::vector msgBytes); 44 | 45 | }; 46 | } 47 | #endif // COMM_SLIP_MSG_PARSER_HPP 48 | -------------------------------------------------------------------------------- /cpp/comm/checksum.cpp: -------------------------------------------------------------------------------- 1 | #include "comm/checksum.hpp" 2 | 3 | namespace comm { 4 | 5 | // Calculate 8-bit Fletcher checksum for message bytes 6 | std::vector calculate8bitFletcherChecksum(std::vector msgBytes) { 7 | 8 | std::vector checksum; 9 | uint8_t ck_A = 0; 10 | uint8_t ck_B = 0; 11 | 12 | for (unsigned int i = 0; i < msgBytes.size(); i++) { 13 | ck_A += msgBytes[i]; 14 | ck_B += ck_A; 15 | } 16 | 17 | // Output checksum 18 | checksum.push_back(ck_A); 19 | checksum.push_back(ck_B); 20 | return checksum; 21 | } 22 | 23 | // Compare two checksum values 24 | bool compareChecksum(std::vector msgBytes, std::vector & checksumBytes) { 25 | std::vector checksum = calculate8bitFletcherChecksum(msgBytes); 26 | 27 | if (checksum[0] == checksumBytes[0] && checksum[1] == checksumBytes[1]) { 28 | return true; // checksum matches 29 | } 30 | else { // checksums don't match 31 | return false; 32 | } 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /cpp/comm/checksum.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_CHECKSUM_HPP 2 | #define COMM_CHECKSUM_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace comm { 8 | 9 | std::vector calculate8bitFletcherChecksum(std::vector msgBytes); 10 | bool compareChecksum(std::vector msgBytes, std::vector & checksumBytes); 11 | } 12 | #endif // COMM_CHECKSUM_HPP 13 | 14 | -------------------------------------------------------------------------------- /cpp/comm/commandSupport.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef COMM_CMD_SUPPORT_HPP 3 | #define COMM_CMD_SUPPORT_HPP 4 | 5 | namespace comm { 6 | 7 | // Defined header types 8 | // Defined header types 9 | enum HeaderType { 10 | NODE_HEADER = 0, 11 | MINIMAL_HEADER = 1, 12 | SOURCE_HEADER = 2, 13 | NO_HEADER = 3, 14 | HEADER_UNKNOWN = 4 15 | }; 16 | 17 | } 18 | 19 | #endif // COMM_CMD_SUPPORT_HPP 20 | -------------------------------------------------------------------------------- /cpp/comm/commandUtils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_COMMAND_UTILS_HPP 2 | #define COMM_COMMAND_UTILS_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include "comm/command.hpp" 8 | #include "comm/cmdHeader.hpp" 9 | #include "comm/msgProcessor.hpp" 10 | 11 | namespace comm { 12 | 13 | /** 14 | * Deserialize received command bytes. 15 | * @param msg Raw message bytes. 16 | * @param cmdId Command ID of message. 17 | */ 18 | std::unique_ptr deserialize(std::vector & msg, uint8_t cmdId); 19 | 20 | /** 21 | * Check command counter of incoming message to see if it is new and if it should be relayed. 22 | * @param cmd Received command. 23 | * @param msg Raw message bytes. 24 | * @param relayBuffer Message bytes vector to place commands to be relayed. 25 | * @return Returns true if command added to relay buffer. 26 | */ 27 | bool checkCmdCounter(Command & cmd, std::vector & msg, std::vector * relayBuffer); 28 | 29 | //CmdHeader parseHeader(std::vector & msg, uint8_t cmdId); 30 | 31 | 32 | /** 33 | * Updates status of message reception from nodes. 34 | * @param header Command header. 35 | */ 36 | void updateNodeMsgRcvdStatus(CmdHeader & header); 37 | 38 | /** 39 | * Process received command header. 40 | * @param cmd Received command. 41 | * @param msg Raw message bytes. 42 | * @param args Message processing arguments. 43 | * @return Returns true if command header processed successfully. 44 | */ 45 | bool processHeader(Command & cmd, std::vector & msg, MsgProcessorArgs & args); 46 | 47 | } 48 | 49 | #endif // COMM_COMMAND_UTILS_HPP 50 | -------------------------------------------------------------------------------- /cpp/comm/commands.cpp: -------------------------------------------------------------------------------- 1 | #include "comm/commands.hpp" 2 | #include "comm/tdmaCmds.hpp" 3 | 4 | using std::unordered_map; 5 | using std::string; 6 | using std::vector; 7 | 8 | namespace comm { 9 | // Global command dictionary 10 | std::unordered_map Cmds::cmdDict; 11 | // Commands to relay 12 | std::vector Cmds::cmdsToRelay = {TDMACmds::BlockTxRequest, TDMACmds::BlockTxRequestResponse, TDMACmds::BlockTxConfirmed, TDMACmds::BlockTxStatus}; 13 | 14 | 15 | void Cmds::updateCmdDict(std::unordered_map & newDict) { 16 | Cmds::cmdDict.insert(newDict.begin(), newDict.end()); 17 | } 18 | 19 | void Cmds::updateRelayCmds(std::vector & relayCmds) { 20 | Cmds::cmdsToRelay.insert(Cmds::cmdsToRelay.end(), relayCmds.begin(), relayCmds.end()); 21 | } 22 | 23 | 24 | /*vector Cmds::getCmds(map & cmds) { 25 | vector out; 26 | 27 | for (map::iterator it = cmds.begin(); it != cmds.end(); it++) { 28 | out.push_back(it->second); 29 | } 30 | 31 | return out; 32 | }*/ 33 | } 34 | -------------------------------------------------------------------------------- /cpp/comm/commands.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_COMMANDS_HPP 2 | #define COMM_COMMANDS_HPP 3 | 4 | #include "comm/commandSupport.hpp" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace comm { 11 | 12 | class Cmds { 13 | public: 14 | 15 | /* 16 | * Command ID to header type mapping. 17 | */ 18 | static std::unordered_map cmdDict; 19 | 20 | static std::vector cmdsToRelay; 21 | /* 22 | * Utility function to load command ID dictionaries. 23 | */ 24 | static void updateCmdDict(std::unordered_map & newDict); 25 | 26 | /* 27 | * Function to update list of commands to relayed 28 | */ 29 | static void updateRelayCmds(std::vector & relayCmds); 30 | 31 | /* 32 | * Returns vector of all values in a command ID map. 33 | */ 34 | //static std::vector getCmds(std::map & cmds); 35 | 36 | }; 37 | 38 | // struct CmdMessage { 39 | // }; 40 | 41 | } 42 | 43 | #endif // COMM_COMMANDS_HPP 44 | -------------------------------------------------------------------------------- /cpp/comm/crc.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CRC_H 3 | #define CRC_H 4 | 5 | #include "comm/crc_8.hpp" 6 | #include "comm/crc_16.hpp" 7 | 8 | #endif /* CRC_H */ 9 | -------------------------------------------------------------------------------- /cpp/comm/crc_16.cpp: -------------------------------------------------------------------------------- 1 | #include "comm/crc_16.hpp" 2 | #include 3 | 4 | using std::vector; 5 | 6 | namespace comm { 7 | 8 | /** 9 | * Reflect all bits of a \a data word of \a data_len bytes. 10 | * 11 | * \param data The data word to be reflected. 12 | * \param data_len The width of \a data expressed in number of bits. 13 | * \return The reflected data. 14 | *****************************************************************************/ 15 | crc16_t crc16_reflect(crc16_t data, size_t data_len) 16 | { 17 | unsigned int i; 18 | crc16_t ret; 19 | 20 | ret = data & 0x01; 21 | for (i = 1; i < data_len; i++) { 22 | data >>= 1; 23 | ret = (ret << 1) | (data & 0x01); 24 | } 25 | return ret; 26 | } 27 | 28 | 29 | /** 30 | * Update the crc value with new data. 31 | * 32 | * \param crc The current crc value. 33 | * \param data Pointer to a buffer of \a data_len bytes. 34 | * \param data_len Number of bytes in the \a data buffer. 35 | * \return The updated crc value. 36 | *****************************************************************************/ 37 | crc16_t crc16_update(crc16_t crc, vector & data) 38 | { 39 | unsigned int tbl_idx; 40 | 41 | for (unsigned int i = 0; i < data.size(); i++) { 42 | tbl_idx = (crc ^ data[i]) & 0xff; 43 | crc = (crc16_table[tbl_idx] ^ (crc >> 8)) & 0xffff; 44 | } 45 | return crc & 0xffff; 46 | } 47 | 48 | crc16_t crc16_create(vector & data) { 49 | crc16_t crc; 50 | crc = crc16_init(); 51 | crc = crc16_update(crc, data); 52 | crc = crc16_finalize(crc); 53 | 54 | return crc; 55 | } 56 | /* 57 | crc16_t bytesToCrc(vector & bytes, unsigned int pos) { 58 | return (uint16_t)(bytes[pos] | (bytes[pos+1] << 8)); 59 | } 60 | 61 | vector crcToBytes(crc16_t crc) { 62 | vector crcBytes; 63 | crcToBytes(crcBytes, crc); 64 | return crcBytes; 65 | } 66 | 67 | void crcToBytes(vector & output, crc16_t crc) { 68 | output.push_back((uint8_t)(crc & 0x00FF)); 69 | output.push_back((uint8_t)(crc >> 8)); 70 | 71 | }*/ 72 | 73 | } 74 | 75 | 76 | -------------------------------------------------------------------------------- /cpp/comm/defines.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_DEFINES_HPP 2 | #define COMM_DEFINES_HPP 3 | 4 | #include 5 | 6 | #define SLIP_MAX_LENGTH 256 7 | #define DEG_TO_RAD M_PI/180.0 8 | #define HAS_GPIO 0 9 | #define IS_BEAGLEBONE 0 10 | #define IS_PI 0 11 | #define NTP_ENABLED 0 12 | 13 | #endif /* COMM_DEFINES_HPP */ 14 | -------------------------------------------------------------------------------- /cpp/comm/exceptions.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_EXCEPTIONS_HPP 2 | #define COMM_EXCEPTIONS_HPP 3 | 4 | #include 5 | 6 | class InvalidInputsException : public std::exception 7 | { 8 | virtual const char * what() const throw() { 9 | return "Invalid constructor inputs supplied"; 10 | } 11 | }; 12 | #endif // COMM_EXCEPTIONS_HPP 13 | -------------------------------------------------------------------------------- /cpp/comm/formationClock.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_FORMATION_CLOCK_HPP 2 | #define COMM_FORMATION_CLOCK_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace comm { 8 | 9 | class FormationClock { 10 | 11 | public: 12 | 13 | /** 14 | * Invalid clock offset value; 15 | */ 16 | static double invalidOffset; 17 | 18 | 19 | /** 20 | * This function resets the TDMA timer. 21 | */ 22 | static void resetTDMATimer(); 23 | 24 | /** 25 | * Constructor. 26 | * @param referenced Referenced clock flag. 27 | * @param referenceTime Time to initialize reference clock. 28 | * @param ppsPin GPIO pin to use for PPS. 29 | */ 30 | FormationClock(bool referenced = false, double referenceTime = 0.0, std::string ppsPin = ""); 31 | 32 | /** 33 | * This functions returns the current clock time. 34 | * @return Current clock time. 35 | */ 36 | double getTime(); 37 | 38 | /** 39 | * This function gets the current value of the TDMA timer. 40 | * @return Current TDMA timer value. 41 | */ 42 | double getTDMATimer(); 43 | 44 | /** 45 | * This function returns the current clock offset. 46 | * @return Returns the current clock offset. 47 | */ 48 | double getOffset(); 49 | 50 | /** 51 | * This function sets up time sync pulse monitoring for TDMA comm scheme. 52 | */ 53 | void monitorSyncPulse(); 54 | 55 | private: 56 | /** 57 | * Time that tdma timer was started. 58 | */ 59 | static double tdmaTimerStart; 60 | 61 | /** 62 | * Mutex for accessing tdmaTimerStart variable. 63 | */ 64 | static std::mutex timer_mutex; 65 | 66 | /** 67 | * Flag of whether clock is referenced from some provided time or just provides system clock time. 68 | */ 69 | bool referenced; 70 | 71 | /** 72 | * Reference time for referenced clocks. 73 | */ 74 | double referenceTime; 75 | 76 | /** 77 | * PPS pin number. 78 | */ 79 | unsigned int ppsPin; 80 | 81 | }; 82 | 83 | } 84 | 85 | #endif // COMM_FORMATION_CLOCK_HPP 86 | -------------------------------------------------------------------------------- /cpp/comm/fpgaRadio.cpp: -------------------------------------------------------------------------------- 1 | #include "comm/fpgaRadio.hpp" 2 | #include "crc_16.hpp" 3 | #include "SLIPMsg.hpp" 4 | #include "utilities.hpp" 5 | 6 | using std::vector; 7 | namespace comm { 8 | 9 | FPGARadio::FPGARadio(serial::Serial * serialIn, RadioConfig & configIn) : 10 | Radio(serialIn, configIn) 11 | { 12 | }; 13 | 14 | unsigned int FPGARadio::sendMsg(vector & msgBytes) { 15 | // Create message crc 16 | crc16_t crc = crc16_create(msgBytes); 17 | 18 | // Add FPGA message header and crc to outgoing message 19 | vector outMsg; 20 | outMsg.push_back(SLIP_END); 21 | outMsg.push_back(FPGA_MSG_START); 22 | uint16_t msgLength = msgBytes.size(); 23 | std::vector lengthBytes = util::packBytes(&msgLength, 2); 24 | outMsg.insert(outMsg.end(), lengthBytes.begin(), lengthBytes.end()); 25 | outMsg.insert(outMsg.end(), msgBytes.begin(), msgBytes.end()); 26 | util::variableToSerialBytes(outMsg, crc); 27 | 28 | return Radio::sendMsg(outMsg); 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /cpp/comm/fpgaRadio.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_FPGA_RADIO_HPP 2 | #define COMM_FPGA_RADIO_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "comm/radio.hpp" 9 | #include "comm/defines.hpp" 10 | #include 11 | 12 | namespace comm { 13 | static const uint8_t FPGA_MSG_START = 250; 14 | 15 | class FPGARadio : public Radio { 16 | 17 | public: 18 | /** 19 | * Default constructor. 20 | */ 21 | FPGARadio() {}; 22 | 23 | /** 24 | * Constructor. 25 | * @param serialIn Serial instance to be used by radio. 26 | * @param configIn Radio configuration. 27 | */ 28 | FPGARadio(serial::Serial * serialIn, RadioConfig & configIn); 29 | 30 | /** 31 | * This function sends bytes over the serial connetion. 32 | * @param msgBytes Bytes to send. 33 | * @return Returns number of messages sent. 34 | */ 35 | virtual unsigned int sendMsg(std::vector & msgBytes); 36 | 37 | }; 38 | } 39 | #endif // COMM_FPGA_RADIO_HPP 40 | -------------------------------------------------------------------------------- /cpp/comm/message.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_MESSAGE_HPP 2 | #define COMM_MESSAGE_HPP 3 | 4 | namespace comm { 5 | 6 | class Message { 7 | public: 8 | virtual ~Message() {}; 9 | }; 10 | 11 | } 12 | #endif // COMM_MESSAGE_HPP 13 | -------------------------------------------------------------------------------- /cpp/comm/msgParser.cpp: -------------------------------------------------------------------------------- 1 | #include "comm/msgParser.hpp" 2 | #include 3 | 4 | using std::vector; 5 | 6 | namespace comm { 7 | 8 | MsgParser::MsgParser(unsigned int parseMsgMaxIn) : 9 | parseMsgMax(parseMsgMaxIn) 10 | {}; 11 | 12 | unsigned int MsgParser::parseSerialMsg(const vector & msgBytes, unsigned int msgStart) { 13 | if (msgBytes.size() > 0) { 14 | parsedMsgs.push_back(std::vector(msgBytes.begin() + msgStart, msgBytes.end())); 15 | return msgBytes.size(); 16 | } 17 | 18 | return 0; 19 | } 20 | 21 | void MsgParser::parseMsgs(const vector & msgBytes) { 22 | unsigned int msgEnd = 0; 23 | for (unsigned int i = 0; i < parseMsgMax; i++) { 24 | if (msgEnd < msgBytes.size()) { 25 | msgEnd = parseSerialMsg(msgBytes, msgEnd); 26 | } 27 | else { 28 | break; 29 | } 30 | } 31 | } 32 | 33 | vector MsgParser::encodeMsg(vector msgBytes) { 34 | // Base class just returns inputted bytes 35 | return vector(msgBytes.begin(), msgBytes.end()); 36 | } 37 | 38 | bool MsgParser::getMsg(std::vector & msg, unsigned int pos) { 39 | if (pos >= parsedMsgs.size()) { // position greater than number of parsed messages 40 | return false; 41 | } 42 | 43 | // Return and delete requested element 44 | msg = parsedMsgs[pos]; 45 | parsedMsgs.erase(parsedMsgs.begin() + pos); 46 | return true; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /cpp/comm/msgParser.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_MSG_PARSER_HPP 2 | #define COMM_MSG_PARSER_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "comm/defines.hpp" 10 | #include 11 | 12 | namespace comm { 13 | 14 | class MsgParser { 15 | 16 | public: 17 | /** 18 | * Container for parsed messages. 19 | */ 20 | std::deque< std::vector > parsedMsgs; 21 | 22 | /** 23 | * Maximum number of messages to attempt to parse. 24 | */ 25 | unsigned int parseMsgMax; 26 | 27 | /** 28 | * Default constructor. 29 | */ 30 | MsgParser() : parseMsgMax(1) {}; 31 | 32 | /** 33 | * Constructor. 34 | * @param parseMsgMaxIn Message parsing limit 35 | */ 36 | MsgParser(unsigned int parseMsgMaxIn); 37 | 38 | /** 39 | * This function searches raw byte for a message. 40 | * @param msgBytes The raw bytes of a message. 41 | * @param msgStart Index to begin search. 42 | * @return Length of parsed message. 43 | */ 44 | virtual unsigned int parseSerialMsg(const std::vector & msgBytes, unsigned int msgStart); 45 | 46 | /** 47 | * This function searches inputted bytes and attempts to find messages. 48 | * @param msgBytes Raw received bytes. 49 | */ 50 | void parseMsgs(const std::vector & msgBytes); 51 | 52 | /** 53 | * This function encodes raw input bytes into a message for serial transmission. 54 | * @param msgBytes Bytes to be encoded. 55 | */ 56 | virtual std::vector encodeMsg(std::vector msgBytes); 57 | 58 | /** 59 | * This function returns and removes a message from the parsedMsgs vector. 60 | * @param msg Vector to store message to be returned. 61 | * @param pos Index of message to return. 62 | * @return Returns true if message was successfully retrieved. 63 | */ 64 | bool getMsg(std::vector & msg, unsigned int pos = 0); 65 | 66 | }; 67 | } 68 | #endif // COMM_MSG_PARSER_HPP 69 | -------------------------------------------------------------------------------- /cpp/comm/nodeMsgProcessor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_NODE_MSG_PROCESSOR_HPP 2 | #define COMM_NODE_MSG_PROCESSOR_HPP 3 | 4 | #include "comm/msgProcessor.hpp" 5 | #include 6 | #include 7 | 8 | namespace comm { 9 | 10 | class NodeMsgProcessor : public MsgProcessor { 11 | 12 | public: 13 | NodeMsgProcessor(); 14 | 15 | /** 16 | * Processes received node command messages. 17 | * @param cmdId Command ID of received command bytes. 18 | * @param msg Raw command message bytes. 19 | * @param args Arguments to be used to process command. 20 | */ 21 | virtual bool processMsg(uint8_t cmdId, std::vector & msg, MsgProcessorArgs & args); 22 | 23 | }; 24 | } 25 | #endif // COMM_NODE_MSG_PROCESSOR_HPP 26 | -------------------------------------------------------------------------------- /cpp/comm/serialRadio.cpp: -------------------------------------------------------------------------------- 1 | #include "comm/serialRadio.hpp" 2 | 3 | using std::vector; 4 | namespace comm { 5 | 6 | SerialRadio::SerialRadio(serial::Serial * serialIn, RadioConfig & configIn) : 7 | Radio(configIn), 8 | serial(serialIn) 9 | { 10 | }; 11 | 12 | int SerialRadio::readBytes(bool bufferFlag, int bytesToRead) { 13 | // Attempt to read serial bytes 14 | vector newBytes; 15 | serial->read(newBytes, bytesToRead); 16 | 17 | // Process received bytes 18 | if (newBytes.size() > 0) { 19 | return processRxBytes(newBytes, bufferFlag); 20 | } 21 | 22 | return 0; 23 | } 24 | 25 | unsigned int SerialRadio::sendMsg(vector & msgBytes) { 26 | if (msgBytes.size() > 0) { 27 | serial->write(createMsg(msgBytes)); 28 | } 29 | 30 | return 1; // number of messages sent 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /cpp/comm/serialRadio.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_SERIAL_RADIO_HPP 2 | #define COMM_SERIAL_RADIO_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "comm/radio.hpp" 9 | #include "comm/defines.hpp" 10 | #include 11 | 12 | namespace comm { 13 | 14 | class SerialRadio : public Radio { 15 | 16 | public: 17 | /** 18 | * Serial instance. 19 | */ 20 | serial::Serial * serial; 21 | 22 | /** 23 | * Default constructor. 24 | */ 25 | SerialRadio() {}; 26 | 27 | /** 28 | * Constructor. 29 | * @param serialIn Serial instance to be used by radio. 30 | * @param configIn Radio configuration. 31 | */ 32 | SerialRadio(serial::Serial * serialIn, RadioConfig & configIn); 33 | 34 | /** 35 | * This function clears the receive buffer. 36 | * @param bufferFlag Whether or not to buffer new bytes or replace existing. 37 | * @param bytesToRead Number of bytes to attempt to read. 38 | * @return Returns number of new bytes buffered. 39 | */ 40 | virtual int readBytes(bool bufferFlag, int bytesToRead = 65536); 41 | 42 | /** 43 | * This function sends bytes over the serial connetion. 44 | * @param msgBytes Bytes to send. 45 | * @return Returns number of messages sent. 46 | */ 47 | virtual unsigned int sendMsg(std::vector & msgBytes); 48 | 49 | }; 50 | } 51 | #endif // COMM_SERIAL_RADIO_HPP 52 | -------------------------------------------------------------------------------- /cpp/comm/tdmaComm_fpga.cpp: -------------------------------------------------------------------------------- 1 | #include "comm/tdmaComm_fpga.hpp" 2 | #include "node/nodeParams.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "utilities.hpp" 8 | #include "comm/tdmaCmds.hpp" 9 | 10 | using node::NodeParams; 11 | using std::unique_ptr; 12 | 13 | namespace comm { 14 | 15 | TDMAComm_FPGA::TDMAComm_FPGA(std::vector msgProcessorsIn, Radio * radioIn, MsgParser * msgParserIn) : 16 | TDMAComm(msgProcessorsIn, radioIn, msgParserIn), 17 | transmitInterval(1.0/NodeParams::config.commConfig.desiredDataRate), 18 | lastTransmitTime(-1.0) 19 | { 20 | } 21 | 22 | void TDMAComm_FPGA::executeTDMAComm(double currentTime) { 23 | // Read any new bytes 24 | readMsg(); 25 | 26 | // Send current message data 27 | if (util::getTime() - lastTransmitTime > transmitInterval) { 28 | lastTransmitTime = util::getTime(); 29 | tdmaMode = TDMA_TRANSMIT; 30 | sendMsg(); 31 | } 32 | else { // wait for next transmit time 33 | tdmaMode = TDMA_RECEIVE; 34 | } 35 | } 36 | 37 | void TDMAComm_FPGA::init(double currentTime) { 38 | initMesh(currentTime); 39 | } 40 | 41 | void TDMAComm_FPGA::initMesh(double currentTime) { 42 | // Create TDMA comm messages 43 | tdmaCmds[TDMACmds::LinkStatus] = unique_ptr(new TDMA_LinkStatus(NodeParams::linkStatus[NodeParams::config.nodeId-1], CmdHeader(TDMACmds::LinkStatus, NodeParams::config.nodeId), NodeParams::config.commConfig.linksTxInterval)); 44 | 45 | //if (NodeParams::config.nodeId != 0) { // do not do for ground node 46 | tdmaCmds[TDMACmds::TimeOffset] = unique_ptr(new TDMA_TimeOffset(NodeParams::nodeStatus[NodeParams::config.nodeId-1].timeOffset, CmdHeader(TDMACmds::TimeOffset, NodeParams::config.nodeId), NodeParams::config.commConfig.offsetTxInterval)); 47 | //} 48 | 49 | inited = true; 50 | std::cout << "Node " << NodeParams::config.nodeId << " - Initializing comm" << std::endl; 51 | } 52 | 53 | void TDMAComm_FPGA::sleep() { 54 | // No actions for sleep 55 | } 56 | 57 | bool TDMAComm_FPGA::readMsg() { 58 | // Read from FPGA 59 | radio->readBytes(true); 60 | 61 | return true; 62 | } 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /cpp/comm/tdmaComm_fpga.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_TDMA_COMM_FPGA_HPP 2 | #define COMM_TDMA_COMM_FPGA_HPP 3 | 4 | #include "comm/tdmaComm.hpp" 5 | //#include "comm/commProcessor.hpp" 6 | #include "comm/radio.hpp" 7 | #include "comm/msgParser.hpp" 8 | 9 | namespace comm { 10 | 11 | class TDMAComm_FPGA : public TDMAComm { 12 | 13 | public: 14 | /** 15 | * Default constructor 16 | */ 17 | TDMAComm_FPGA() {}; 18 | 19 | /** 20 | * Constructor. 21 | * @param msgProcessorsIn Vector of message processors. 22 | * @param radioIn Radio to send/receive messages. 23 | * @param msgParserIn Message parser. 24 | */ 25 | TDMAComm_FPGA(std::vector msgProcessorsIn, Radio * radioIn, MsgParser * msgParserIn = NULL); 26 | 27 | /** 28 | * Executes TDMA communication logic. 29 | * @param currentTime Current clock time. 30 | */ 31 | virtual void executeTDMAComm(double currenTime); 32 | 33 | /** 34 | * Communication initialization function. 35 | * @param currentTime Current time. 36 | */ 37 | virtual void init(double currentTime); 38 | 39 | /** 40 | * Initializes mesh network. 41 | * @param currentTime Current time. 42 | */ 43 | virtual void initMesh(double currentTime); 44 | 45 | /** 46 | * Sleeps until end of TDMA frame. 47 | */ 48 | virtual void sleep(); 49 | 50 | /** 51 | * Checks for any received data. 52 | * @return End of transmission indication. 53 | */ 54 | virtual bool readMsg(); 55 | 56 | /** 57 | * TDMA transmit interval between messages to FPGA. 58 | */ 59 | double transmitInterval; 60 | 61 | /** 62 | * TDMA last transmit time to FPGA. 63 | */ 64 | double lastTransmitTime; 65 | }; 66 | 67 | } 68 | 69 | #endif // COMM_TDMA_COMM_FPGA_HPP 70 | -------------------------------------------------------------------------------- /cpp/comm/tdmaMsgProcessor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_TDMA_MSG_PROCESSOR_HPP 2 | #define COMM_TDMA_MSG_PROCESSOR_HPP 3 | 4 | #include "comm/msgProcessor.hpp" 5 | #include 6 | #include 7 | 8 | namespace comm { 9 | 10 | class TDMAMsgProcessor : public MsgProcessor { 11 | 12 | public: 13 | /** 14 | * Default constructor. 15 | */ 16 | TDMAMsgProcessor(); 17 | 18 | /** 19 | * Processes received TDMA command messages. 20 | * @param cmdId Command ID of message. 21 | * @param msg Command message bytes. 22 | * @param args Message processor arguments. 23 | */ 24 | virtual bool processMsg(uint8_t cmdId, std::vector & msg, MsgProcessorArgs & args); 25 | 26 | }; 27 | } 28 | #endif // COMM_TDMA_MSG_PROCESSOR_HPP 29 | -------------------------------------------------------------------------------- /cpp/comm/tdmaTime.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_TDMA_TIME_HPP 2 | #define COMM_TDMA_TIME_HPP 3 | 4 | 5 | 6 | #endif // COMM_TDMA_TIME_HPP 7 | -------------------------------------------------------------------------------- /cpp/comm/testMsgProcessor.cpp: -------------------------------------------------------------------------------- 1 | #include "comm/testMsgProcessor.hpp" 2 | 3 | #include 4 | #include 5 | #include "comm/tdmaCmds.hpp" 6 | #include 7 | #include 8 | using std::vector; 9 | 10 | 11 | namespace comm { 12 | 13 | 14 | TestMsgProcessor::TestMsgProcessor() 15 | { 16 | cmdIds = vector({TDMACmds::MeshStatus, TDMACmds::TimeOffset}); 17 | } 18 | 19 | bool TestMsgProcessor::processMsg(uint8_t cmdId, vector & msg, MsgProcessorArgs args) { 20 | std::cout << "In processor 1" << std::endl; 21 | return True; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /cpp/comm/testMsgProcessor.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_TEST_MSG_PROCESSOR_HPP 2 | #define COMM_TEST_MSG_PROCESSOR_HPP 3 | 4 | #include "comm/msgProcessor.hpp" 5 | #include 6 | #include 7 | 8 | namespace comm { 9 | 10 | class TestMsgProcessor : public MsgProcessor { 11 | 12 | public: 13 | TestMsgProcessor(); 14 | 15 | virtual bool processMsg(uint8_t cmdId, std::vector & msg, MsgProcessorArgs args); 16 | 17 | }; 18 | } 19 | #endif // COMM_TEST_MSG_PROCESSOR_HPP 20 | -------------------------------------------------------------------------------- /cpp/comm/udpRadio.cpp: -------------------------------------------------------------------------------- 1 | #include "comm/udpRadio.hpp" 2 | 3 | using std::vector; 4 | namespace comm { 5 | UDPRadio::UDPRadio(std::string udpInterfaceIn, std::string udpPortIn, RadioConfig & configIn) : 6 | Radio(NULL, configIn) 7 | { 8 | }; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /cpp/comm/udpRadio.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_UDPRADIO_HPP 2 | #define COMM_UDPRADIO_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "comm/radio.hpp" 9 | 10 | namespace comm { 11 | 12 | class UDPRadio : public Radio { 13 | 14 | public: 15 | 16 | /** 17 | * Constructor. 18 | * @param udpInterfaceIn UDP network interface. 19 | * @param udpPortIn UDP port. 20 | * @param configIn Radio configuration. 21 | */ 22 | UDPRadio(std::string udpInterfaceIn, std::string udpPortIn, RadioConfig & configIn); 23 | 24 | }; 25 | } 26 | #endif // COMM_UDPRADIO_HPP 27 | -------------------------------------------------------------------------------- /cpp/comm/utilities.cpp: -------------------------------------------------------------------------------- 1 | #include "utilities.hpp" 2 | 3 | namespace util { 4 | void setupSerial(serial::Serial & ser, std::string port, unsigned int baudrate, unsigned int timeout) { 5 | serial::Timeout sTimeout = serial::Timeout::simpleTimeout(timeout); 6 | ser.setPort(port); 7 | ser.setBaudrate(baudrate); 8 | ser.setTimeout(sTimeout); 9 | ser.open(); 10 | 11 | } 12 | 13 | std::vector packBytes(void * data, unsigned int dataSize) { 14 | uint8_t buf[dataSize]; 15 | memcpy(buf, data, dataSize); 16 | return std::vector(buf, buf + sizeof(buf)); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /cpp/comm/xbeeRadio.cpp: -------------------------------------------------------------------------------- 1 | #include "comm/xbeeRadio.hpp" 2 | #include "GPIOWrapper/GPIOWrapper.hpp" 3 | 4 | namespace comm { 5 | XbeeRadio::XbeeRadio(serial::Serial * serialIn, RadioConfig & configIn, int sleepPinIn) : 6 | Radio(serialIn, configIn), 7 | sleepPin(sleepPinIn) 8 | { 9 | if (sleepPinIn > -1) { // sleep pin available 10 | GPIOWrapper::setupPin((unsigned int)sleepPinIn, GPIOWrapper::OUTPUT); 11 | } 12 | } 13 | 14 | bool XbeeRadio::setOff(void) { 15 | setSleep(); 16 | mode = RADIO_OFF; 17 | return true; 18 | } 19 | 20 | bool XbeeRadio::setSleep(void) { 21 | if (sleepPin > -1) { 22 | GPIOWrapper::setValue((unsigned int)sleepPin, GPIOWrapper::HIGH); 23 | } 24 | 25 | mode = RADIO_SLEEP; 26 | 27 | return true; 28 | } 29 | 30 | bool XbeeRadio::setReceive(void) { 31 | wake(); 32 | mode = RADIO_RECEIVE; 33 | return true; 34 | } 35 | 36 | bool XbeeRadio::setTransmit(void) { 37 | wake(); 38 | mode = RADIO_TRANSMIT; 39 | return true; 40 | } 41 | 42 | void XbeeRadio::wake(void) { 43 | if (sleepPin > -1) { 44 | GPIOWrapper::setValue((unsigned int)sleepPin, GPIOWrapper::LOW); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /cpp/comm/xbeeRadio.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_XBEE_RADIO_HPP 2 | #define COMM_XBEE_RADIO_HPP 3 | 4 | #include "comm/radio.hpp" 5 | #include 6 | 7 | namespace comm { 8 | 9 | class XbeeRadio : public Radio { 10 | 11 | public: 12 | /** 13 | * Sleep GPIO pin. 14 | */ 15 | int sleepPin; 16 | 17 | /** 18 | * Default constructor. 19 | */ 20 | XbeeRadio() : Radio(), sleepPin(-1) {}; 21 | 22 | /** 23 | * Constructor. 24 | * @param serialIn Serial instance to be used by radio. 25 | * @param configIn Radio configuration. 26 | * @param sleepPin GPIO pin to toggle sleep. 27 | */ 28 | XbeeRadio(serial::Serial * serialIn, RadioConfig & configIn, int sleepPin = -1); 29 | 30 | /** 31 | * This function sets the radio mode to OFF. 32 | * @return True on successful mode change. 33 | */ 34 | virtual bool setOff(void); 35 | 36 | /** 37 | * This function sets the radio mode to SLEEP. 38 | * @return True on successful mode change. 39 | */ 40 | virtual bool setSleep(void); 41 | 42 | /** 43 | * This function sets the radio mode to RECEIVE. 44 | * @return True on successful mode change. 45 | */ 46 | virtual bool setReceive(void); 47 | 48 | /** 49 | * This function sets the radio mode to TRANSMIT. 50 | * @return True on successful mode change. 51 | */ 52 | virtual bool setTransmit(void); 53 | 54 | /** 55 | * This function wakes the radio. 56 | */ 57 | void wake(void); 58 | 59 | }; 60 | } 61 | #endif // COMM_XBEE_RADIO_HPP 62 | -------------------------------------------------------------------------------- /cpp/commControl.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "node/nodeConfig.hpp" 3 | #include "node/nodeParams.hpp" 4 | #include "comm/commControl.hpp" 5 | #include "node/nodeControl.hpp" 6 | #include "comm/udpRadio.hpp" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int main(void) { 14 | 15 | std::cout << "Executing comm control." << std::endl; 16 | 17 | // Load node parameters 18 | node::NodeConfig config("nodeConfig.json"); 19 | node::NodeParams::loadParams(config); 20 | 21 | // Node and comm interface 22 | comm::RadioConfig rConfig(200,100,100); 23 | serial::Serial ser_comm("/dev/ttyV2", 57600, serial::Timeout::simpleTimeout(10)); 24 | comm::Radio radio(&ser_comm, rConfig); 25 | //serial::Serial ser_comm(config.comm, 57600, serial::Timeout::simpleTimeout(10)); 26 | node::NodeInterface nodeInterface; 27 | 28 | // Create communication control 29 | comm::CommControl commControl(0, &radio, &nodeInterface); 30 | 31 | // Node and comm interface 32 | serial::Serial ser_commNode("/dev/ttyV1", 57600, serial::Timeout::simpleTimeout(10)); 33 | comm::Radio radioNode(&ser_commNode, rConfig); 34 | 35 | // Create log files 36 | std::ofstream fcLogFile("test.log"); 37 | std::ofstream nodeLogFile("test2.log"); 38 | std::ofstream cmdLogFile("test3.log"); 39 | 40 | // Node Control 41 | node::NodeControl nodeControl(0, &radioNode, &nodeInterface, &nodeLogFile, &fcLogFile, &cmdLogFile); 42 | 43 | // Start execution threads 44 | nodeControl.execute(); 45 | commControl.execute(); 46 | 47 | 48 | while (true) { 49 | usleep(10*1e6); 50 | } 51 | return 0; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /cpp/lib/GPIOWrapper/GPIOWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "GPIOWrapper.hpp" 2 | 3 | namespace GPIOWrapper { 4 | // Not implemented 5 | int setupPin(unsigned int pin, PINMODE mode) { return -1; }; 6 | int setMode(unsigned int pin, PINMODE mode) { return -1; }; 7 | int setValue(unsigned int pin, PINVALUE value) { return -1; }; 8 | int getValue(unsigned int pin) { return -1; }; 9 | int registerInterrupt(unsigned int pin, EDGEVALUE edge, void(*function)(void)) { return -1; }; 10 | int getPin(std::string name) { return -1; }; 11 | int setupPin(unsigned int pin) { return -1; }; 12 | int setupPin(std::string pin) { return -1; }; 13 | int setupPin(std::string pin, PINMODE mode) { return -1; }; 14 | int closePin(unsigned int pin) { return -1; }; 15 | int closePin(std::string pin) { return -1; }; 16 | int setMode(std::string pin, PINMODE mode) { return -1; }; 17 | int getMode(unsigned int pin) { return -1; }; 18 | int getMode(std::string pin) { return -1; }; 19 | int setValue(std::string pin, PINVALUE value) { return -1; }; 20 | int getValue(std::string pin) { return -1; }; 21 | int waitForEdge(unsigned int pin, EDGEVALUE edge) { return -1; }; 22 | 23 | } 24 | 25 | -------------------------------------------------------------------------------- /cpp/lib/GPIOWrapper/GPIOWrapper.hpp: -------------------------------------------------------------------------------- 1 | #ifndef GPIO_WRAPPER_HPP_ 2 | #define GPIO_WRAPPER_HPP_ 3 | 4 | #include 5 | 6 | namespace GPIOWrapper { 7 | 8 | enum PINMODE { 9 | INPUT = 0, 10 | OUTPUT = 1 11 | }; 12 | 13 | enum PINVALUE { 14 | LOW = 0, 15 | HIGH = 1 16 | }; 17 | 18 | enum EDGEVALUE { 19 | NONE = 0, 20 | RISING = 1, 21 | FALLING = 2, 22 | BOTH = 3 23 | }; 24 | 25 | int getPin(std::string name); 26 | int setupPin(unsigned int pin); 27 | int setupPin(std::string pin); 28 | int setupPin(unsigned int pin, PINMODE mode); 29 | int setupPin(std::string pin, PINMODE mode); 30 | int closePin(unsigned int pin); 31 | int closePin(std::string pin); 32 | int setMode(unsigned int pin, PINMODE mode); 33 | int setMode(std::string pin, PINMODE mode); 34 | int getMode(unsigned int pin); 35 | int getMode(std::string pin); 36 | int setValue(unsigned int pin, PINVALUE value); 37 | int setValue(std::string pin, PINVALUE value); 38 | int getValue(unsigned int pin); 39 | int getValue(std::string pin); 40 | int waitForEdge(unsigned int pin, EDGEVALUE edge); 41 | int registerInterrupt(unsigned int pin, EDGEVALUE edge, void (*function)(void)); 42 | 43 | } /* namespace GPIOWrapper */ 44 | #endif // GPIO_WRAPPER_HPP_ 45 | -------------------------------------------------------------------------------- /cpp/lib/GPIOWrapper/GPIOWrapper_PI.cpp: -------------------------------------------------------------------------------- 1 | #include "GPIOWrapper.hpp" 2 | #include 3 | 4 | namespace GPIOWrapper { 5 | int setupPin(unsigned int pin, PINMODE mode) { 6 | return setMode(pin, mode); 7 | } 8 | 9 | int setMode(unsigned int pin, PINMODE mode) { 10 | if (mode == INPUT) { 11 | pinMode(pin, INPUT); 12 | } 13 | else { 14 | pinMode(pin, OUTPUT); 15 | } 16 | 17 | return 0; 18 | } 19 | 20 | 21 | int setValue(unsigned int pin, PINVALUE value) { 22 | digitalWrite(pin, value); 23 | return 0; 24 | } 25 | 26 | int getValue(unsigned int pin) { 27 | return digitalRead(pin); 28 | } 29 | 30 | int registerInterrupt(unsigned int pin, EDGEVALUE edge, void(*function)(void)) { 31 | if (edge == NONE) { 32 | // Invalid value 33 | return -1; 34 | } 35 | else if (edge == RISING) { 36 | return wiringPiISR(pin, INT_EDGE_RISING, function); 37 | } 38 | else if (edge == FALLING) { 39 | return wiringPiISR(pin, INT_EDGE_FALLING, function); 40 | } 41 | else if (edge == BOTH) { 42 | return wiringPiISR(pin, INT_EDGE_BOTH, function); 43 | } 44 | } 45 | 46 | // Not implemented by wiringPi 47 | int getPin(std::string name) { return -1; }; 48 | int setupPin(unsigned int pin) { return -1; }; 49 | int setupPin(std::string pin) { return -1; }; 50 | int setupPin(std::string pin, PINMODE mode) { return -1; }; 51 | int closePin(unsigned int pin) { return -1; }; 52 | int closePin(std::string pin) { return -1; }; 53 | int setMode(std::string pin, PINMODE mode) { return -1; }; 54 | int getMode(unsigned int pin) { return -1; }; 55 | int getMode(std::string pin) { return -1; }; 56 | int setValue(std::string pin, PINVALUE value) { return -1; }; 57 | int getValue(std::string pin) { return -1; }; 58 | int waitForEdge(unsigned int pin, EDGEVALUE edge) { return -1; }; 59 | 60 | } 61 | 62 | -------------------------------------------------------------------------------- /cpp/lib/GPIOWrapper/Makefile: -------------------------------------------------------------------------------- 1 | BBB_SRC:=GPIOWrapper_BBB.cpp \ 2 | BeagleBoneBlack-GPIO/GPIO/GPIOManager.cpp \ 3 | BeagleBoneBlack-GPIO/GPIO/GPIOConst.cpp 4 | 5 | BBB_OBJS:=$(patsubst %.cpp, %.o, $(BBB_SRC)) 6 | BBB_OBJS:=$(BBB_OBJS:%.c=%.o) 7 | 8 | RASPI_SRC:=GPIOWrapper_PI.cpp 9 | RASPI_OBJS:=$(patsubst %.cpp, %.o, $(RASPI_SRC)) 10 | RASPI_OBJS:=$(RASPI_OBJS:%.c=%.o) 11 | 12 | default: GPIOWrapper.o 13 | ar rcs libgpiowrapper.a GPIOWrapper.o 14 | 15 | bbb: $(BBB_OBJS) 16 | ar rcs libgpiowrapper.a $(BBB_OBJS) 17 | 18 | pi: $(RASPI_OBJS) 19 | ar rcs libgpiowrapper.a $(RASPI_OBJS) 20 | 21 | clean: 22 | rm -f *.o BeagleBoneBlack-GPIO/GPIO/*.o *.a 23 | -------------------------------------------------------------------------------- /cpp/lib/rapidjson/JSON_Document.d: -------------------------------------------------------------------------------- 1 | JSON_Document.o: JSON_Document.cpp JSON_Document.hpp document.h reader.h \ 2 | rapidjson.h allocators.h encodings.h internal/meta.h internal/stack.h \ 3 | internal/strtod.h internal/../rapidjson.h internal/ieee754.h \ 4 | internal/biginteger.h internal/diyfp.h internal/pow10.h error/error.h \ 5 | internal/strfunc.h JSON_Value.hpp JSON_Values.hpp filereadstream.h 6 | -------------------------------------------------------------------------------- /cpp/lib/rapidjson/JSON_Value.d: -------------------------------------------------------------------------------- 1 | JSON_Value.o: JSON_Value.cpp JSON_Value.hpp document.h reader.h \ 2 | rapidjson.h allocators.h encodings.h internal/meta.h internal/stack.h \ 3 | internal/strtod.h internal/../rapidjson.h internal/ieee754.h \ 4 | internal/biginteger.h internal/diyfp.h internal/pow10.h error/error.h \ 5 | internal/strfunc.h filereadstream.h 6 | -------------------------------------------------------------------------------- /cpp/lib/rapidjson/JSON_Value.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RAPIDJSON_JSON_VALUE_HPP_ 2 | #define _RAPIDJSON_JSON_VALUE_HPP_ 3 | 4 | #include "document.h" 5 | 6 | namespace rapidjson 7 | { 8 | class JSON_Value 9 | { 10 | public: 11 | /** 12 | * Constructor. 13 | * @param value Entry from a JSON document. 14 | */ 15 | JSON_Value(const Value& value); 16 | 17 | /** 18 | * Retreive a string value from the document. 19 | * @param entry The key of the value being searched for. 20 | * @param value The value to be returned. 21 | * @return True if the value is found, otherwise, false. 22 | */ 23 | bool get_string(const char *entry, char **value) const; 24 | 25 | /** 26 | * Retreive an integer value from the document. 27 | * @param entry The key of the value being searched for. 28 | * @param value The value to be returned. 29 | * @return True if the value is found, otherwise, false. 30 | */ 31 | bool get_int(const char *entry, int &value) const; 32 | 33 | /** 34 | * Retreive a double value from the document. 35 | * @param entry The key of the value being searched for. 36 | * @param value The value to be returned. 37 | * @return True if the value is found, otherwise, false. 38 | */ 39 | bool get_double(const char *entry, double &value) const; 40 | 41 | /** 42 | * Retreive an array of double value from the document. 43 | * @param entry The key of the value being searched for. 44 | * @param value The value to be returned. 45 | * @param nentries The number of maximum number of entries the array 46 | * can hold is passed in. 47 | * @return The number of array entries found on success or -1 on 48 | * failure. 49 | */ 50 | int get_doubles(const char *entry, double *value, 51 | unsigned int nentries) const; 52 | 53 | const Value& m_val; 54 | 55 | private: 56 | bool m_valid; 57 | 58 | }; 59 | } 60 | 61 | #endif // _RAPIDJSON_JSON_VALUE_HPP_ 62 | -------------------------------------------------------------------------------- /cpp/lib/rapidjson/JSON_Values.cpp: -------------------------------------------------------------------------------- 1 | #include "JSON_Values.hpp" 2 | #include "filereadstream.h" 3 | 4 | namespace rapidjson 5 | { 6 | 7 | JSON_Values::JSON_Values(const Value &value) 8 | : m_valid(false) 9 | , m_val(value) 10 | { 11 | m_valid = true; 12 | } 13 | 14 | bool JSON_Values::get_string(const char *entry, char **value, 15 | unsigned int e) const 16 | { 17 | if(!m_valid || (m_val.Size() <= e)) 18 | { 19 | return false; 20 | } 21 | 22 | if(m_val[e].HasMember(entry)) 23 | { 24 | if(m_val[e][entry].IsString()) 25 | { 26 | *value = const_cast(m_val[e][entry].GetString()); 27 | return true; 28 | } 29 | } 30 | 31 | return false; 32 | } 33 | 34 | bool JSON_Values::get_int(const char *entry, int &value, 35 | unsigned int e) const 36 | { 37 | if(!m_valid || (m_val.Size() <= e)) 38 | { 39 | return false; 40 | } 41 | 42 | if(m_val[e].HasMember(entry)) 43 | { 44 | if(m_val[e][entry].IsInt()) 45 | { 46 | value = m_val[e][entry].GetInt(); 47 | return true; 48 | } 49 | } 50 | 51 | return false; 52 | } 53 | 54 | bool JSON_Values::get_double(const char *entry, double &value, 55 | unsigned int e) const 56 | { 57 | if(!m_valid || (m_val.Size() <= e)) 58 | { 59 | return false; 60 | } 61 | 62 | if(m_val[e].HasMember(entry)) 63 | { 64 | if(m_val[e][entry].IsDouble()) 65 | { 66 | value = m_val[e][entry].GetDouble(); 67 | return true; 68 | } 69 | } 70 | 71 | return false; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /cpp/lib/rapidjson/JSON_Values.d: -------------------------------------------------------------------------------- 1 | JSON_Values.o: JSON_Values.cpp JSON_Values.hpp document.h reader.h \ 2 | rapidjson.h allocators.h encodings.h internal/meta.h internal/stack.h \ 3 | internal/strtod.h internal/../rapidjson.h internal/ieee754.h \ 4 | internal/biginteger.h internal/diyfp.h internal/pow10.h error/error.h \ 5 | internal/strfunc.h filereadstream.h 6 | -------------------------------------------------------------------------------- /cpp/lib/rapidjson/JSON_Values.hpp: -------------------------------------------------------------------------------- 1 | #ifndef _RAPIDJSON_JSON_VALUES_HPP_ 2 | #define _RAPIDJSON_JSON_VALUES_HPP_ 3 | 4 | #include "document.h" 5 | 6 | namespace rapidjson 7 | { 8 | /** 9 | * This class manages JSON arrays 10 | */ 11 | class JSON_Values 12 | { 13 | public: 14 | /** 15 | * Constructor. 16 | * @param value Array entry from a JSON document. 17 | */ 18 | JSON_Values(const Value &value); 19 | 20 | /** 21 | * Retreive a string value from the document. 22 | * @param entry The key of the value being searched for. 23 | * @param value The value to be returned. 24 | * @param e Array element number to get from. 25 | * @return True if the value is found, otherwise, false. 26 | */ 27 | bool get_string(const char *entry, char **value, unsigned int e) const; 28 | 29 | /** 30 | * Retreive an integer value from the document. 31 | * @param entry The key of the value being searched for. 32 | * @param value The value to be returned. 33 | * @param e Array element number to get from. 34 | * @return True if the value is found, otherwise, false. 35 | */ 36 | bool get_int(const char *entry, int &value, unsigned int e) const; 37 | 38 | /** 39 | * Retreive a double value from the document. 40 | * @param entry The key of the value being searched for. 41 | * @param value The value to be returned. 42 | * @param e Array element number to get from. 43 | * @return True if the value is found, otherwise, false. 44 | */ 45 | bool get_double(const char *entry, double &value, unsigned int e) const; 46 | 47 | const Value &m_val; 48 | 49 | private: 50 | bool m_valid; 51 | 52 | }; 53 | } 54 | 55 | #endif // _RAPIDJSON_JSON_VALUES_HPP_ 56 | -------------------------------------------------------------------------------- /cpp/lib/rapidjson/JSON_Wrapper.d: -------------------------------------------------------------------------------- 1 | JSON_Wrapper.o: JSON_Wrapper.cpp JSON_Wrapper.hpp document.h reader.h \ 2 | rapidjson.h allocators.h encodings.h internal/meta.h internal/stack.h \ 3 | internal/strtod.h internal/../rapidjson.h internal/ieee754.h \ 4 | internal/biginteger.h internal/diyfp.h internal/pow10.h error/error.h \ 5 | internal/strfunc.h filereadstream.h 6 | -------------------------------------------------------------------------------- /cpp/lib/rapidjson/JSON_Wrapper.hpp: -------------------------------------------------------------------------------- 1 | 2 | #include "document.h" 3 | 4 | namespace rapidjson { 5 | 6 | bool loadJSONDocument(rapidjson::Document & d, std::string fileName); 7 | bool loadJSONDocument(rapidjson::Document & d, const char *fileName); 8 | 9 | int get_size(const rapidjson::Document &d, const char *entry); 10 | bool get_string(const rapidjson::Document & d, const char *entry, std::string & value); 11 | int get_strings(const rapidjson::Document & d, const char *entry, std::string *value, int numEntries); 12 | bool get_int(const rapidjson::Document & d, const char *entry, int &value); 13 | int get_ints(const rapidjson::Document & d, const char *entry, int *value, int numEntries); 14 | bool get_int(const rapidjson::Document & d, const char *entry, unsigned int &value); 15 | bool get_bool(const rapidjson::Document & d, const char *entry, bool &value); 16 | bool get_double(const rapidjson::Document & d, const char *entry, double &value); 17 | int get_doubles(const rapidjson::Document & d, const char *entry, double *value, int numEntries); 18 | 19 | int get_size(const rapidjson::Value &v, const char *entry); 20 | bool get_string(const rapidjson::Value & v, const char *entry, std::string & value); 21 | int get_strings(const rapidjson::Value & v, const char *entry, std::string *value, int numEntries); 22 | int get_strings(const rapidjson::Value & input, std::string *output, int maxSize); 23 | bool get_int(const rapidjson::Value & v, const char *entry, int &value); 24 | bool get_int(const rapidjson::Value & v, const char *entry, unsigned int &value); 25 | int get_ints(const rapidjson::Value & v, const char *entry, int *value, int numEntries); 26 | int get_ints(const rapidjson::Value & v, int *value, int numEntries); 27 | bool get_bool(const rapidjson::Value & v, const char *entry, bool &value); 28 | bool get_double(const rapidjson::Value & v, const char *entry, double &value); 29 | int get_doubles(const rapidjson::Value & v, const char *entry, double *value, int numEntries); 30 | } 31 | -------------------------------------------------------------------------------- /cpp/lib/rapidjson/Makefile: -------------------------------------------------------------------------------- 1 | SRC:=JSON_Document.cpp \ 2 | JSON_Value.cpp \ 3 | JSON_Values.cpp \ 4 | JSON_Wrapper.cpp 5 | 6 | TEST_SRC:= 7 | 8 | TGT:=rapidjson 9 | TGTTYPE:=static_lib 10 | 11 | CPPFLAGS+= -fPIC 12 | 13 | SP:=./ 14 | include $(SP)rules.mk 15 | -------------------------------------------------------------------------------- /cpp/lib/rapidjson/internal/strfunc.h: -------------------------------------------------------------------------------- 1 | // Tencent is pleased to support the open source community by making RapidJSON available. 2 | // 3 | // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 4 | // 5 | // Licensed under the MIT License (the "License"); you may not use this file except 6 | // in compliance with the License. You may obtain a copy of the License at 7 | // 8 | // http://opensource.org/licenses/MIT 9 | // 10 | // Unless required by applicable law or agreed to in writing, software distributed 11 | // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 12 | // CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | // specific language governing permissions and limitations under the License. 14 | 15 | #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ 16 | #define RAPIDJSON_INTERNAL_STRFUNC_H_ 17 | 18 | RAPIDJSON_NAMESPACE_BEGIN 19 | namespace internal { 20 | 21 | //! Custom strlen() which works on different character types. 22 | /*! \tparam Ch Character type (e.g. char, wchar_t, short) 23 | \param s Null-terminated input string. 24 | \return Number of characters in the string. 25 | \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. 26 | */ 27 | template 28 | inline SizeType StrLen(const Ch* s) { 29 | const Ch* p = s; 30 | while (*p) ++p; 31 | return SizeType(p - s); 32 | } 33 | 34 | } // namespace internal 35 | RAPIDJSON_NAMESPACE_END 36 | 37 | #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ 38 | -------------------------------------------------------------------------------- /cpp/lib/rapidjson/rules.mk: -------------------------------------------------------------------------------- 1 | 2 | CC:=gcc 3 | CPP:=g++ 4 | LD:=g++ 5 | AR:=ar 6 | 7 | BASEDIR:=$(SP) 8 | LDFLAGS:= 9 | CFLAGS+=-O2 10 | CPPFLAGS+=$(CFLAGS) -g -Wall 11 | 12 | SYSTEM:=$(shell uname) 13 | ARCH:=$(shell uname -m) 14 | SYS_CYGWIN:=CYGWIN_NT-5.1 15 | SYS_MINGW:=MINGW32_NT-5.1 16 | SYS_LINUX:=Linux 17 | SYS_DARWIN:=Darwin 18 | 19 | OBJS:=$(patsubst %.cpp, %.o, $(SRC)) 20 | DEPS:=$(patsubst %.cpp, %.d, $(SRC)) 21 | OBJS:=$(OBJS:%.c=%.o) 22 | DEPS:=$(DEPS:%.c=%.d) 23 | 24 | TEST_OBJS:=$(patsubst %.cpp, %.o, $(TEST_SRC)) 25 | TEST_DEPS+=$(patsubst %.cpp, %.d, $(TEST_SRC)) 26 | 27 | ifeq ($(TGTTYPE), static_lib) 28 | TGT:=lib$(TGT).a 29 | LDFLAGS+=-lrt -ldl -lpthread 30 | endif 31 | 32 | ifeq ($(TGTTYPE), application) 33 | ifeq ($(SYSTEM),$(SYS_CYGWIN)) 34 | TGT:=$(TGT).exe 35 | else 36 | ifeq ($(SYSTEM),$(SYS_MINGW)) 37 | TGT:=$(TGT).exe 38 | else 39 | TGT:=$(TGT) 40 | LDFLAGS+=-ldl -lpthread 41 | endif 42 | endif 43 | endif 44 | 45 | .PHONY:all test clean $(SUBDIRS) 46 | 47 | all: TARGET:=all 48 | all: $(SUBDIRS) $(OBJS) $(TGT) 49 | 50 | $(SUBDIRS): 51 | $(MAKE) -C $@ $(MAKECMDGOALS) 52 | 53 | %.a: $(OBJS) 54 | $(AR) rcs $@ $(OBJS) 55 | 56 | %.d:%.cpp 57 | $(CPP) -MM $(CPPFLAGS) -MT $*.o $< -o $@ 58 | 59 | GTEST:=../lib/gtest 60 | TEST_DRIVER:=run_test 61 | test: TARGET:=test 62 | test: CPPFLAGS+=-DASSERT_THROWS_EXCEPTION -I$(GTEST)/include -L$(GTEST)/cmake \ 63 | -lgtest_main -lgtest 64 | test: $(SUBDIRS) $(TEST_DRIVER) 65 | 66 | $(TEST_DRIVER): $(TEST_OBJS) $(OBJS) 67 | ifdef TEST_OBJS 68 | $(CPP) -o $@ $(CPPFLAGS) $(TEST_OBJS) $(OBJS) $(TESTDEPS) $(LDFLAGS) 69 | endif 70 | TEST_DRIVER:=run_test 71 | 72 | clean: TARGET:=clean 73 | clean: $(SUBDIRS) 74 | rm -f $(OBJS) $(DEPS) $(TEST_OBJS) $(TEST_DEPS) $(TGT) $(TEST_DRIVER) \ 75 | $(EXTRA_CLEAN) *.stackdump *~ 76 | 77 | ifneq ($(MAKECMDGOALS),clean) 78 | -include $(DEPS) 79 | -include $(TEST_DEPS) 80 | endif 81 | -------------------------------------------------------------------------------- /cpp/node/nodeCmds.cpp: -------------------------------------------------------------------------------- 1 | #include "node/nodeCmds.hpp" 2 | #include "comm/commands.hpp" 3 | #include 4 | #include 5 | 6 | using std::vector; 7 | using comm::Command; 8 | using comm::CmdHeader; 9 | 10 | namespace node { 11 | // Node Commands 12 | std::vector NodeCmds::cmds = {NodeCmds::GCSCmd, NodeCmds::FormationCmd, 13 | NodeCmds::ParamUpdate, NodeCmds::ConfigRequest, NodeCmds::ConfigHash}; 14 | 15 | std::unordered_map NodeCmds::cmdDict = {}; 16 | 17 | Node_GCSCmd::Node_GCSCmd(FormationMode modeIn, comm::CmdHeader headerIn, double txIntervalIn) : 18 | Command(NodeCmds::GCSCmd, headerIn, txIntervalIn), 19 | mode(modeIn) 20 | {} 21 | 22 | Node_GCSCmd::Node_GCSCmd(vector & msg) : 23 | Command(NodeCmds::GCSCmd) 24 | {} 25 | 26 | vector Node_GCSCmd::serialize() { 27 | vector packed; 28 | return packed; 29 | } 30 | 31 | Node_ParamUpdate::Node_ParamUpdate(ParamName nameIn, vector valueIn, comm::CmdHeader headerIn, double txIntervalIn) : 32 | Command(NodeCmds::ParamUpdate, headerIn, txIntervalIn), 33 | name(nameIn), 34 | value(valueIn) 35 | {} 36 | 37 | Node_ParamUpdate::Node_ParamUpdate(vector & msg) : 38 | Command(NodeCmds::ParamUpdate) 39 | {} 40 | 41 | vector Node_ParamUpdate::serialize() { 42 | vector packed; 43 | return packed; 44 | } 45 | 46 | Node_ConfigRequest::Node_ConfigRequest(std::string hashIn, comm::CmdHeader headerIn, double txIntervalIn) : 47 | Command(NodeCmds::ConfigRequest, headerIn, txIntervalIn), 48 | hash(hashIn) 49 | {} 50 | 51 | Node_ConfigRequest::Node_ConfigRequest(vector & msg) : 52 | Command(NodeCmds::ConfigRequest) 53 | {} 54 | 55 | vector Node_ConfigRequest::serialize() { 56 | vector packed; 57 | return packed; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /cpp/node/nodeControl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NODE_NODE_CONTROL_HPP 2 | #define NODE_NODE_CONTROL_HPP 3 | 4 | #include "node/nodeInterface.hpp" 5 | #include 6 | #include "comm/radio.hpp" 7 | #include "comm/msgParser.hpp" 8 | #include "comm/serialComm.hpp" 9 | #include "node/nodeController.hpp" 10 | #include "node/nodeExecutive.hpp" 11 | #include 12 | #include 13 | 14 | namespace node { 15 | 16 | class NodeControl { 17 | 18 | public: 19 | 20 | serial::Serial FCSer; 21 | std::unique_ptr FCComm; 22 | std::vector> comms; 23 | std::unique_ptr FCRadio; 24 | std::vector> msgParsers; 25 | std::unique_ptr FCMsgParser; 26 | NodeInterface * commInterface; 27 | std::unique_ptr nodeController; 28 | std::unique_ptr nodeExecutive; 29 | 30 | NodeControl(unsigned int meshNum, comm::Radio * radioIn, NodeInterface * commInterfaceIn, std::ofstream * nodeLogFile, std::ofstream * fcLogFile, std::ofstream * cmdLogFile); 31 | 32 | void run(); 33 | 34 | /** 35 | * Executes node control thread. 36 | */ 37 | void execute(); 38 | }; 39 | 40 | } 41 | 42 | #endif // NODE_NODE_CONTROL_HPP 43 | -------------------------------------------------------------------------------- /cpp/node/nodeController.cpp: -------------------------------------------------------------------------------- 1 | #include "node/nodeController.hpp" 2 | #include "node/nodeParams.hpp" 3 | 4 | namespace node { 5 | 6 | NodeController::NodeController() : 7 | logFile(NULL) 8 | {} 9 | 10 | NodeController::NodeController(std::ofstream * logFileIn) : 11 | logFile(logFileIn), 12 | logTime(0.0) 13 | { 14 | // Set logging precision 15 | if (logFile != NULL) { 16 | logFile->setf(std::ios::fixed); 17 | logFile->precision(6); 18 | } 19 | } 20 | 21 | void NodeController::controlNode() { 22 | // Process commands 23 | processCommands(); 24 | 25 | // Check status of other formation nodes 26 | monitorFormationStatus(); 27 | 28 | // Run unique node behavior 29 | executeNode(); 30 | 31 | // Log data 32 | logData(); 33 | 34 | } 35 | 36 | void NodeController::executeNode() { 37 | monitorFormationStatus(); 38 | } 39 | 40 | void NodeController::processFCCommands(comm::SerialComm * FCComm) { 41 | } 42 | 43 | void NodeController::processNodeCommands(comm::SerialComm * comm) { 44 | } 45 | 46 | void NodeController::processCommands() { 47 | } 48 | 49 | void NodeController::logData() { 50 | } 51 | 52 | void NodeController::monitorFormationStatus() { 53 | // Check that other nodes' status are updating 54 | for (unsigned int i = 0; i < NodeParams::nodeStatus.size(); i++) { 55 | if ((NodeParams::nodeStatus[i].lastStateUpdateTime + NodeParams::config.nodeUpdateTimeout) < NodeParams::clock.getTime()) { 56 | NodeParams::nodeStatus[i].updating = true; 57 | } 58 | else { 59 | NodeParams::nodeStatus[i].updating = false; 60 | } 61 | } 62 | } 63 | 64 | void NodeController::checkNodeLinks() { 65 | // TODO 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /cpp/node/nodeExecutive.cpp: -------------------------------------------------------------------------------- 1 | #include "node/nodeExecutive.hpp" 2 | 3 | using std::vector; 4 | using std::unique_ptr; 5 | 6 | namespace node { 7 | 8 | NodeExecutive::NodeExecutive() : 9 | nodeController(NULL), 10 | FCComm(NULL), 11 | fcLogFile(NULL) 12 | {} 13 | 14 | NodeExecutive::NodeExecutive(NodeController * controllerIn, vector> & nodeCommIn, comm::SerialComm * FCCommIn, std::ofstream * fcLogFileIn) : 15 | nodeController(controllerIn), 16 | FCComm(FCCommIn), 17 | fcLogFile(fcLogFileIn) 18 | { 19 | for (unsigned int i = 0; i < nodeCommIn.size(); i++) { 20 | nodeComm.push_back(nodeCommIn[i].get()); 21 | } 22 | } 23 | 24 | void NodeExecutive::executeNodeSoftware() { 25 | // Process data from flight computer 26 | processFCMsg(); 27 | 28 | // Check mesh connections for new messages 29 | for (unsigned int i = 0; i < nodeComm.size(); i++) { 30 | processNodeMsg(nodeComm[i]); 31 | } 32 | 33 | // Run node control algorithms 34 | if (nodeController != NULL) { 35 | nodeController->controlNode(); 36 | } 37 | 38 | // Send commands to flight computer 39 | sendFCCmds(); 40 | 41 | // Send outgoing node messages to other formation nodeParams 42 | sendNodeCmds(); 43 | } 44 | 45 | void NodeExecutive::processFCMsg() { 46 | if (FCComm != NULL) { 47 | FCComm->readMsgs(); 48 | } 49 | } 50 | 51 | void NodeExecutive::processNodeMsg(comm::SerialComm * comm) { 52 | if (comm != NULL) { 53 | comm->readMsgs(); 54 | } 55 | } 56 | 57 | void NodeExecutive::sendFCCmds() { 58 | 59 | } 60 | 61 | void NodeExecutive::sendNodeCmds() { 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /cpp/node/nodeExecutive.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NODE_NODE_EXECUTIVE_HPP 2 | #define NODE_NODE_EXECUTIVE_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include "comm/serialComm.hpp" 8 | #include "node/nodeController.hpp" 9 | 10 | namespace node { 11 | 12 | class NodeExecutive { 13 | 14 | public: 15 | 16 | /** 17 | * Node controller instance for this node. 18 | */ 19 | NodeController * nodeController; 20 | 21 | /** 22 | * Container of node communication instances. 23 | */ 24 | std::vector nodeComm; 25 | 26 | /** 27 | * Flight computer comm instance. 28 | */ 29 | comm::SerialComm * FCComm; 30 | 31 | /** 32 | * Flight computer logging file stream. 33 | */ 34 | std::ofstream * fcLogFile; 35 | 36 | /** 37 | * Default constructor. 38 | */ 39 | NodeExecutive(); 40 | 41 | /** 42 | * Constructor. 43 | * @param controller NodeController instance pointer. 44 | * @param nodeComm Container of node communication instances. 45 | * @param FCComm Flight computer comm instance. 46 | * @param fcLogFile Flight computer logging file stream. 47 | */ 48 | NodeExecutive(NodeController * controller, std::vector> & nodeComm, comm::SerialComm * FCComm, std::ofstream * fcLogFile); 49 | 50 | /** 51 | * Controls execution of all node software in the proper sequence. 52 | */ 53 | virtual void executeNodeSoftware(); 54 | 55 | /** 56 | * Processes messages from flight computer. 57 | */ 58 | virtual void processFCMsg(); 59 | 60 | /** 61 | * Processes messages from other nodes. 62 | * @param comm Comm instance to processes messages from. 63 | */ 64 | virtual void processNodeMsg(comm::SerialComm * comm); 65 | 66 | /** 67 | * Sends outgoing flight computer messages. 68 | */ 69 | virtual void sendFCCmds(); 70 | 71 | /** 72 | * Sends outgoing node communications. 73 | */ 74 | virtual void sendNodeCmds(); 75 | }; 76 | 77 | } 78 | 79 | #endif // NODE_NODE_EXECUTIVE_HPP 80 | -------------------------------------------------------------------------------- /cpp/node/nodeInterface.cpp: -------------------------------------------------------------------------------- 1 | #include "node/nodeInterface.hpp" 2 | 3 | namespace node { 4 | 5 | NodeInterface::NodeInterface() : 6 | nodeControlRunFlag(false) 7 | {} 8 | 9 | } 10 | -------------------------------------------------------------------------------- /cpp/node/nodeInterface.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NODE_NODE_INTERFACE_HPP 2 | #define NODE_NODE_INTERFACE_HPP 3 | 4 | #include 5 | 6 | namespace node { 7 | 8 | class NodeInterface { 9 | 10 | public: 11 | 12 | std::atomic nodeControlRunFlag; 13 | 14 | /** 15 | * Default constructor. 16 | */ 17 | NodeInterface(); 18 | 19 | }; 20 | 21 | } 22 | 23 | #endif // NODE_NODE_INTERFACE_HPP 24 | -------------------------------------------------------------------------------- /cpp/node/nodeParams.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NODE_NODE_PARAMS_HPP 2 | #define NODE_NODE_PARAMS_HPP 3 | 4 | #include 5 | #include 6 | #include "node/nodeConfig.hpp" 7 | #include "comm/commBuffer.hpp" 8 | #include "node/nodeState.hpp" 9 | #include "comm/formationClock.hpp" 10 | 11 | namespace node { 12 | 13 | class NodeParams { 14 | 15 | public: 16 | 17 | /** 18 | * Load parameters from node configuration. 19 | * @param config Node configuration. 20 | */ 21 | static void loadParams(NodeConfig & config); 22 | static void loadParams(std::string configFile); 23 | 24 | static void init(); 25 | 26 | /** 27 | * Populates command dictionary. 28 | */ 29 | //static void loadCmdDict(); 30 | 31 | /** 32 | * Get new command counter value. 33 | @return Returns command counter value. 34 | */ 35 | static uint16_t getCmdCounter(); 36 | 37 | /** 38 | * Node configuration instance. 39 | */ 40 | static NodeConfig config; 41 | 42 | /** 43 | * Command counter history FIFO buffer. 44 | */ 45 | static comm::CommBuffer cmdHistory; 46 | 47 | /** 48 | * Node status structure. 49 | */ 50 | static std::vector nodeStatus; 51 | 52 | /** 53 | * Random number generator. 54 | */ 55 | static std::default_random_engine generator; 56 | 57 | /** 58 | * Random number distribution. 59 | */ 60 | static std::uniform_int_distribution distribution; 61 | 62 | /** 63 | * Formation clock. 64 | */ 65 | static comm::FormationClock clock; 66 | 67 | /** 68 | * Node parameters loaded flag. 69 | */ 70 | static bool nodeParamsLoaded; 71 | 72 | /** 73 | * Configuration check confirmation flag. 74 | */ 75 | static bool configConfirmed; 76 | 77 | /** 78 | * Network links status. 79 | */ 80 | static std::vector< std::vector > linkStatus; 81 | 82 | }; 83 | } 84 | 85 | #endif // NODE_NODE_PARAMS_HPP 86 | -------------------------------------------------------------------------------- /cpp/node/nodeState.cpp: -------------------------------------------------------------------------------- 1 | #include "node/nodeState.hpp" 2 | #include "comm/formationClock.hpp" 3 | 4 | namespace node { 5 | 6 | NodeState::NodeState(uint8_t idIn) : 7 | id(idIn), 8 | present(false), 9 | updating(false), 10 | flightMode(0), 11 | formationMode(0), 12 | failsafeType(0), 13 | timestamp(-1.0), 14 | timeOffset(comm::FormationClock::invalidOffset), 15 | numMsgsReceived(0), 16 | lastStateUpdateTime(0.0), 17 | lastMsgRcvdTime(0.0), 18 | status(0) 19 | {} 20 | } 21 | -------------------------------------------------------------------------------- /cpp/node/nodeState.hpp: -------------------------------------------------------------------------------- 1 | #ifndef NODE_NODE_STATE_HPP 2 | #define NODE_NODE_STATE_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace node { 8 | 9 | enum LinkStatus { 10 | NoLink = 0, 11 | IndirectLink = 2, 12 | GoodLink = 1, 13 | BadLink = 3 14 | }; 15 | 16 | class NodeState { 17 | 18 | public: 19 | 20 | /** 21 | * Constructor. 22 | * @param id Node id number. 23 | */ 24 | NodeState(uint8_t id = 0); 25 | 26 | /** 27 | * Node id number. 28 | */ 29 | uint8_t id; 30 | 31 | /** 32 | * Presence flag. 33 | */ 34 | bool present; 35 | 36 | /** 37 | * Status updating flag. 38 | */ 39 | bool updating; 40 | 41 | /** 42 | * Current flight mode. 43 | */ 44 | uint8_t flightMode; 45 | 46 | /** 47 | * Current formation mode. 48 | */ 49 | uint8_t formationMode; 50 | 51 | /** 52 | * Current failsafe type if applicable. 53 | */ 54 | uint8_t failsafeType; 55 | 56 | /** 57 | * State vector 58 | */ 59 | std::vector state; 60 | 61 | /** 62 | * Timestamp corresponding to last received state update. 63 | */ 64 | double timestamp; 65 | 66 | /** 67 | * Current clock time offset. 68 | */ 69 | double timeOffset; 70 | 71 | /** 72 | * Number of messages received from this node. 73 | */ 74 | uint16_t numMsgsReceived; 75 | 76 | /** 77 | * Time that last state update was received. 78 | */ 79 | double lastStateUpdateTime; 80 | 81 | /** 82 | * Time that last message was received. 83 | */ 84 | double lastMsgRcvdTime; 85 | 86 | /** 87 | * Status byte to indicate various status conditions. 88 | */ 89 | uint8_t status; 90 | 91 | }; 92 | } 93 | 94 | #endif // NODE_NODE_STATE_HPP 95 | -------------------------------------------------------------------------------- /cpp/nodeConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "node": { 3 | "nodeId": 2, 4 | "maxNumNodes": 6, 5 | "platform": "generic", 6 | "nodeUpdateTimeout": 5.0, 7 | "FCCommWriteInterval": 0.2, 8 | "FCCommDevice": "/dev/ttyO1", 9 | "FCBaudrate": 57600, 10 | "cmdInterval": 0.2, 11 | "logInterval": 0.05, 12 | "commType": "TDMA", 13 | "numMeshNetworks": 1, 14 | "meshDevices": ["/dev/ttyO4"], 15 | "radios": ["Xbee"], 16 | "msgParsers": ["SLIP"], 17 | "meshBaudrate": 57600, 18 | "parseMsgMax": 50, 19 | "rxBufferSize": 2000, 20 | "gcsPresent": true 21 | }, 22 | 23 | "interface": { 24 | "nodeCommIntIP": "127.0.0.1", 25 | "commRdPort": 30000, 26 | "commWrPort": 30001 27 | }, 28 | 29 | "tdmaConfig": { 30 | "sleepPin": "P8_12", 31 | "enableLength": 0.005, 32 | "slotGuardLength": 0.005, 33 | "preTxGuardLength": 0.005, 34 | "postTxGuardLength": 0.005, 35 | "txLength": 0.100, 36 | "rxDelay": 0.0, 37 | "initTimeToWait": 5.0, 38 | "maxNumSlots": 6, 39 | "desiredDataRate": 1.0, 40 | "initSyncBound": 1.0, 41 | "operateSyncBound": 2.0, 42 | "offsetTimeout": 60.0, 43 | "offsetTxInterval": 10.0, 44 | "statusTxInterval": 0.0, 45 | "linksTxInterval": 1.0, 46 | "maxTxBlockSize": 5, 47 | "blockTxRequestTimeout": 3, 48 | "minBlockTxDelay": 6, 49 | "fpga": true, 50 | "fpgaFailsafePin": "P8_16", 51 | "fpgaFifoSize": 512, 52 | "enablePin": "P8_15", 53 | "statusPin": "P8_18" 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /cpp/nodeConfig_bad.json: -------------------------------------------------------------------------------- 1 | { 2 | "node": { 3 | "nodeId": 1, 4 | "platform": "generic", 5 | "nodeUpdateTimeout": 5.0, 6 | "FCCommWriteInterval": 0.2, 7 | "FCCommDevice": "/dev/ttyO1", 8 | "FCBaudrate": 57600, 9 | "cmdInterval": 0.2, 10 | "logInterval": 0.05, 11 | "commType": "TDMA", 12 | "numMeshNetworks": 1, 13 | "meshDevices": ["/dev/ttyO4"], 14 | "radios": ["Xbee"], 15 | "msgParsers": ["SLIP"], 16 | "meshBaudrate": 57600, 17 | "parseMsgMax": 50, 18 | "rxBufferSize": 2000, 19 | "gcsPresent": true 20 | }, 21 | 22 | "interface": { 23 | "nodeCommIntIP": "127.0.0.1", 24 | "commRdPort": 30000, 25 | "commWrPort": 30001 26 | }, 27 | 28 | "tdmaConfig": { 29 | "sleepPin": "P8_12", 30 | "txBaudrate": 57600, 31 | "enableLength": 0.005, 32 | "slotGuardLength": 0.005, 33 | "preTxGuardLength": 0.005, 34 | "postTxGuardLength": 0.005, 35 | "txLength": 0.100, 36 | "rxDelay": 0.0, 37 | "initTimeToWait": 5.0, 38 | "maxNumSlots": 6, 39 | "desiredDataRate": 1.0, 40 | "initSyncBound": 1.0, 41 | "operateSyncBound": 2.0, 42 | "offsetTimeout": 60.0, 43 | "offsetTxInterval": 10.0, 44 | "statusTxInterval": 0.0, 45 | "linksTxInterval": 1.0, 46 | "maxTxBlockSize": 5, 47 | "blockTxRequestTimeout": 3, 48 | "minBlockTxDelay": 6, 49 | "fpga": false, 50 | "fpgaFailsafePin": "P8_16", 51 | "fpgaFifoSize": 512, 52 | "enablePin": "P8_15", 53 | "statusPin": "P8_18" 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /cpp/nodeConfig_noNodeId.json: -------------------------------------------------------------------------------- 1 | { 2 | "node": { 3 | "nodeId": 1, 4 | "maxNumNodes": 6, 5 | "platform": "generic", 6 | "nodeUpdateTimeout": 5.0, 7 | "FCCommWriteInterval": 0.2, 8 | "FCCommDevice": "/dev/ttyO1", 9 | "FCBaudrate": 57600, 10 | "cmdInterval": 0.2, 11 | "logInterval": 0.05, 12 | "commType": "TDMA", 13 | "numMeshNetworks": 1, 14 | "meshDevices": ["/dev/ttyO4"], 15 | "radios": ["Xbee"], 16 | "msgParsers": ["SLIP"], 17 | "meshBaudrate": 57600, 18 | "parseMsgMax": 50, 19 | "rxBufferSize": 2000, 20 | "gcsPresent": true 21 | }, 22 | 23 | "interface": { 24 | "nodeCommIntIP": "127.0.0.1", 25 | "commRdPort": 30000, 26 | "commWrPort": 30001 27 | }, 28 | 29 | "tdmaConfig": { 30 | "sleepPin": "P8_12", 31 | "enableLength": 0.005, 32 | "slotGuardLength": 0.005, 33 | "preTxGuardLength": 0.005, 34 | "postTxGuardLength": 0.005, 35 | "txLength": 0.100, 36 | "rxDelay": 0.0, 37 | "initTimeToWait": 5.0, 38 | "maxNumSlots": 6, 39 | "desiredDataRate": 1.0, 40 | "initSyncBound": 1.0, 41 | "operateSyncBound": 2.0, 42 | "offsetTimeout": 60.0, 43 | "offsetTxInterval": 10.0, 44 | "statusTxInterval": 0.0, 45 | "linksTxInterval": 1.0, 46 | "maxTxBlockSize": 5, 47 | "blockTxRequestTimeout": 3, 48 | "minBlockTxDelay": 6, 49 | "fpga": true, 50 | "fpgaFailsafePin": "P8_16", 51 | "fpgaFifoSize": 512, 52 | "enablePin": "P8_15", 53 | "statusPin": "P8_18" 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /cpp/readme.md: -------------------------------------------------------------------------------- 1 | Library dependencies: 2 | -Serial (https://github.com/wjwwood/serial) 3 | -Requires catkin to build (Install from source option: http://wiki.ros.org/catkin, 'sudo apt-get install catkin') 4 | -JSON (https://github.com/miloyip/rapidjson) with additional wrapper functions. Wrapper library folder already includes rapidjson required files. 5 | -Google test (https://github.com/abseil/googletest) 6 | -GPIO 7 | -Beaglebone Black (https://github.com/mkaczanowski/BeagleBoneBlack-GPIO) 8 | -Raspberry Pi (wiringpi.com) 9 | -OpenSSL library - for SHA1 hash calculations (https://www.openssl.org/docs/manmaster/crypto/crypto.html, 'sudo apt-get install libssl-dev') 10 | -Google Protocol Buffers (requires version 3 beta for Python3 support) - Download latest release from Github and build following readme directions. Build for both c++ and python. https://github.com/google/protobuf/releases 11 | 12 | Test dependencies: 13 | -Since some tests will exercise GPIO functions, they must be run on a platform with GPIO pins (i.e. BBB or Raspberry Pi). These tests are named with a "gpio" tag. To exclude these tests, run the test executable using the gtest filter flag (i.e. ./run_test --gtest_filter=-*gpio*). 14 | -Likewise for ntp required tests, use filter "ntp". 15 | -Filters can be chained with a ":", i.e. --gtest_filter=-*gpio*:-*ntp* 16 | 17 | Python test run script: 18 | -Unit tests can be run using the runTest.py script. This script will set up required testing dependencies like virtual serial ports. 19 | -To pass test filters, use the '-f' option, i.e. sudo python3 runTest.py -f=-*gpio*. If the filter has "-" in it, you must use the equal sign or the arguments will not be parsed correctly. 20 | -------------------------------------------------------------------------------- /cpp/rules.mk: -------------------------------------------------------------------------------- 1 | 2 | CC:=gcc 3 | CPP:=g++ 4 | CXX:=g++ 5 | LD:=g++ 6 | AR:=ar 7 | 8 | #CC:=/home/aerom/test/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc 9 | #CPP:=/home/aerom/test/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ 10 | #CXX:=/home/aerom/test/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ 11 | #LD:=/home/aerom/test/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++ 12 | #AR:=/home/aerom/test/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-ar 13 | #CPLUS_INCLUDE_PATH=-I/usr/local/include/ -I/usr/include/ 14 | 15 | BASEDIR:=$(SP) 16 | LDFLAGS:= 17 | CFLAGS+=-O2 18 | CPPFLAGS+=$(CFLAGS) -g -Wall 19 | 20 | SYSTEM:=$(shell uname) 21 | ARCH:=$(shell uname -m) 22 | SYS_CYGWIN:=CYGWIN_NT-5.1 23 | SYS_MINGW:=MINGW32_NT-5.1 24 | SYS_LINUX:=Linux 25 | SYS_DARWIN:=Darwin 26 | 27 | ## Object and fependency files 28 | # Comm object and dependency files 29 | COMM_OBJS:=$(patsubst %.cpp, %.o, $(COMM_SRC)) 30 | COMM_DEPS:=$(patsubst %.cpp, %.d, $(COMM_SRC)) 31 | 32 | # Node object and dependency files 33 | NODE_OBJS:=$(patsubst %.cpp, %.o, $(NODE_SRC)) 34 | NODE_DEPS:=$(patsubst %.cpp, %.d, $(NODE_SRC)) 35 | 36 | # Test object and dependency files 37 | TEST_OBJS:=$(patsubst %.cpp, %.o, $(TEST_SRC)) 38 | TEST_DEPS+=$(patsubst %.cpp, %.d, $(TEST_SRC)) 39 | 40 | ## Targets 41 | all: $(SUBDIRS) comm $(TGT) 42 | 43 | comm: $(COMM_OBJS) commControl 44 | 45 | node: $(SUBDIRS) $(COMM_OBJS) $(NODE_OBJS) $(TGT) 46 | 47 | $(SUBDIRS): 48 | $(MAKE) -C $@ $(MAKECMDGOALS) 49 | 50 | %.a: $(COMM_OBJS) $(NODE_OBJS) 51 | $(AR) rcs $@ $(COMM_OBJS) $(NODE_OBJS) 52 | 53 | %.d:%.cpp 54 | $(CPP) -MM $(CPPFLAGS) -MT $*.o $< -o $@ 55 | 56 | 57 | ifeq ($(TGTTYPE), static_lib) 58 | TGT:=lib$(TGT).a 59 | LDFLAGS+=-lrt -ldl -lpthread 60 | endif 61 | 62 | ifeq ($(TGTTYPE), application) 63 | ifeq ($(SYSTEM),$(SYS_CYGWIN)) 64 | TGT:=$(TGT).exe 65 | else 66 | ifeq ($(SYSTEM),$(SYS_MINGW)) 67 | TGT:=$(TGT).exe 68 | else 69 | TGT:=$(TGT) 70 | LDFLAGS+=-ldl -lpthread 71 | endif 72 | endif 73 | endif 74 | 75 | clean: TARGET:=clean 76 | clean: $(SUBDIRS) 77 | rm -f *.o $(COMM_OBJS) $(NODE_OBJS) $(COMM_DEPS) $(NODE_DEPS) $(TEST_OBJS) $(TEST_DEPS) $(TGT) $(TEST_DRIVER) \ 78 | $(EXTRA_CLEAN) gtest* *.stackdump *~ 79 | 80 | ifneq ($(MAKECMDGOALS),clean) 81 | -include $(COMM_DEPS) 82 | -include $(TEST_DEPS) 83 | endif 84 | 85 | -------------------------------------------------------------------------------- /cpp/runTest.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "gtest/gtest.h" 3 | 4 | int main(int argc, char **argv) { 5 | 6 | ::testing::InitGoogleTest(&argc, argv); 7 | return RUN_ALL_TESTS(); 8 | } 9 | -------------------------------------------------------------------------------- /cpp/runTest.py: -------------------------------------------------------------------------------- 1 | from subprocess import Popen, call 2 | import time 3 | import argparse 4 | 5 | parser = argparse.ArgumentParser(description="Run unit tests") 6 | parser.add_argument('-f', '--filter', action='store', default="*", help="Filter tests to run") 7 | args = parser.parse_args() 8 | print(args) 9 | argValues = vars(args) 10 | 11 | # Open virtual serial port 12 | serP = Popen(["sudo", "socat", "pty,link=/dev/ttyV2,raw", "pty,link=/dev/ttyV3,raw"], shell=False) 13 | time.sleep(0.5) 14 | 15 | # Execute unit tests 16 | testFilter = argValues['filter'] 17 | call(["sudo", "./run_test", "--gtest_filter=" + testFilter]) 18 | 19 | serP.terminate() 20 | -------------------------------------------------------------------------------- /cpp/tests/SLIPMsgParser_UT.cpp: -------------------------------------------------------------------------------- 1 | #include "tests/SLIPMsgParser_UT.hpp" 2 | #include 3 | #include 4 | #include 5 | #include "comm/crc.hpp" 6 | #include "comm/utilities.hpp" 7 | 8 | using std::vector; 9 | 10 | vector msgIn = {0, 1, comm::SLIP_END, 2, comm::SLIP_ESC, 3, comm::SLIP_END_TDMA, 4, 5}; 11 | 12 | namespace comm 13 | { 14 | 15 | SLIPMsgParser_UT::SLIPMsgParser_UT() 16 | : m_slipmsgparser() 17 | { 18 | } 19 | 20 | void SLIPMsgParser_UT::SetUpTestCase(void) { 21 | 22 | } 23 | 24 | void SLIPMsgParser_UT::SetUp(void) 25 | { 26 | } 27 | 28 | TEST_F(SLIPMsgParser_UT, encodeMsg) { 29 | // Test that CRC is appended 30 | crc8_t crc = crc8_create(msgIn); 31 | vector encoded = m_slipmsgparser.encodeMsg(msgIn); 32 | m_slipmsgparser.slipMsg.decodeSLIPMsg(encoded, 0); 33 | EXPECT_TRUE(m_slipmsgparser.slipMsg.msg.size() == msgIn.size() + sizeof(crc)); // length matches 34 | crc8_t crcParsed; 35 | util::serialBytesToVariable(m_slipmsgparser.slipMsg.msg, m_slipmsgparser.slipMsg.msg.size()-sizeof(crc), &crcParsed); 36 | EXPECT_TRUE(crc == crcParsed); // crc is correct 37 | 38 | } 39 | 40 | TEST_F(SLIPMsgParser_UT, parseSerialMsg) { 41 | // Test that valid message is parsed 42 | vector encoded = m_slipmsgparser.encodeMsg(msgIn); 43 | m_slipmsgparser.parseSerialMsg(encoded, 0); 44 | ASSERT_TRUE(m_slipmsgparser.parsedMsgs.size() == 1); 45 | EXPECT_TRUE(m_slipmsgparser.parsedMsgs[0].size() == msgIn.size()); 46 | for (unsigned int i = 0; i < m_slipmsgparser.parsedMsgs[0].size(); i++) { 47 | EXPECT_TRUE(m_slipmsgparser.parsedMsgs[0][i] == msgIn[i]); 48 | } 49 | 50 | // Check that new messages are appended 51 | m_slipmsgparser.parseSerialMsg(encoded, 0); 52 | EXPECT_TRUE(m_slipmsgparser.parsedMsgs.size() == 2); 53 | 54 | // Check that message with invalid CRC is not parsed 55 | encoded[encoded.size()-1] = encoded[encoded.size()-1] + 1; 56 | m_slipmsgparser.parseSerialMsg(encoded, 0); 57 | EXPECT_TRUE(m_slipmsgparser.parsedMsgs.size() == 2); 58 | 59 | } 60 | 61 | 62 | } 63 | -------------------------------------------------------------------------------- /cpp/tests/SLIPMsgParser_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_SLIPMSGPARSER_UT_HPP__ 2 | #define __COMM_SLIPMSGPARSER_UT_HPP__ 3 | 4 | #include 5 | #include "comm/SLIPMsgParser.hpp" 6 | 7 | namespace comm 8 | { 9 | class SLIPMsgParser_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | SLIPMsgParser_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | /* The class under test. 20 | */ 21 | SLIPMsgParser m_slipmsgparser; 22 | 23 | }; 24 | } 25 | 26 | #endif // __COMM_SLIPMSGPARSER_UT_HPP__ 27 | -------------------------------------------------------------------------------- /cpp/tests/SLIPMsg_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_SLIPMSG_UT_HPP__ 2 | #define __COMM_SLIPMSG_UT_HPP__ 3 | 4 | #include 5 | #include "comm/SLIPMsg.hpp" 6 | 7 | namespace comm 8 | { 9 | class SLIPMsg_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | SLIPMsg_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | /* The class under test. 20 | */ 21 | SLIPMsg m_slipmsg; 22 | 23 | }; 24 | } 25 | 26 | #endif // __COMM_SLIPMSG_UT_HPP__ 27 | -------------------------------------------------------------------------------- /cpp/tests/checksum_UT.cpp: -------------------------------------------------------------------------------- 1 | #include "tests/checksum_UT.hpp" 2 | #include 3 | #include 4 | #include 5 | #include "comm/checksum.hpp" 6 | 7 | using std::vector; 8 | 9 | namespace { 10 | vector testMsg = {1, 2, 3, 4, 5, 100, 90, 80, 70, 60}; 11 | vector validChecksum = {159, 130}; 12 | } 13 | namespace comm 14 | { 15 | 16 | checksum_UT::checksum_UT() 17 | { 18 | } 19 | 20 | void checksum_UT::SetUpTestCase(void) { 21 | 22 | } 23 | 24 | void checksum_UT::SetUp(void) 25 | { 26 | } 27 | 28 | TEST_F(checksum_UT, calculate8bitFletcher) { 29 | vector checksum = calculate8bitFletcherChecksum(testMsg); 30 | ASSERT_TRUE(checksum.size() == 2); 31 | EXPECT_TRUE(checksum[0] == validChecksum[0]); 32 | EXPECT_TRUE(checksum[1] == validChecksum[1]); 33 | } 34 | 35 | TEST_F(checksum_UT, compareChecksum) { 36 | EXPECT_TRUE(compareChecksum(testMsg, validChecksum)); 37 | 38 | // Alter valid checksum and recompare 39 | validChecksum[0] += 1; 40 | EXPECT_TRUE(compareChecksum(testMsg, validChecksum) == false); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /cpp/tests/checksum_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_CHECKSUM_UT_HPP 2 | #define COMM_CHECKSUM_UT_HPP 3 | 4 | #include 5 | 6 | namespace comm 7 | { 8 | class checksum_UT : public ::testing::Test 9 | { 10 | public: 11 | 12 | protected: 13 | checksum_UT(); 14 | 15 | virtual void SetUp(void); 16 | static void SetUpTestCase(void); 17 | 18 | }; 19 | } 20 | 21 | #endif // COMM_CHECKSUM_UT_HPP 22 | -------------------------------------------------------------------------------- /cpp/tests/cmdHeader_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_CMDHEADER_UT_HPP__ 2 | #define __COMM_CMDHEADER_UT_HPP__ 3 | 4 | #include 5 | 6 | namespace comm 7 | { 8 | class CmdHeader_UT : public ::testing::Test 9 | { 10 | public: 11 | 12 | protected: 13 | CmdHeader_UT(); 14 | 15 | virtual void SetUp(void); 16 | static void SetUpTestCase(void); 17 | 18 | }; 19 | } 20 | 21 | #endif // __COMM_CMDHEADER_UT_HPP__ 22 | -------------------------------------------------------------------------------- /cpp/tests/commBuffer_UT.cpp: -------------------------------------------------------------------------------- 1 | #include "tests/commBuffer_UT.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | using std::vector; 7 | 8 | namespace { 9 | 10 | } 11 | 12 | namespace comm 13 | { 14 | CommBuffer_UT::CommBuffer_UT() : 15 | m_commBuffer(CommBuffer< vector >(5)) 16 | { 17 | } 18 | 19 | void CommBuffer_UT::SetUpTestCase(void) { 20 | } 21 | 22 | void CommBuffer_UT::SetUp(void) 23 | { 24 | } 25 | 26 | TEST_F(CommBuffer_UT, pushAndPop) { 27 | vector testVec = {0,1,2,3,4,5}; 28 | 29 | // Push into buffer and track size (update first element to track entries) 30 | EXPECT_TRUE(m_commBuffer.size() == 0); 31 | for (unsigned int i = 0; i < m_commBuffer.maxSize; i++) { 32 | m_commBuffer.push(testVec); 33 | EXPECT_TRUE(m_commBuffer.size() == i+1); 34 | testVec[0] = testVec[0] + 1; 35 | } 36 | EXPECT_TRUE(m_commBuffer.size() == m_commBuffer.maxSize); 37 | 38 | // Overrun buffer size and then check that first element popped out 39 | m_commBuffer.push(testVec); 40 | ASSERT_TRUE(m_commBuffer.size() == m_commBuffer.maxSize); 41 | 42 | // Check if old data removed correctly when max size reached 43 | unsigned int initialSize = m_commBuffer.size(); 44 | for (unsigned int i = 0; i < m_commBuffer.maxSize; i++) { 45 | vector entry = m_commBuffer.pop(); 46 | EXPECT_TRUE(entry[0] == i + 1); 47 | EXPECT_TRUE(m_commBuffer.size() == --initialSize); 48 | } 49 | 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /cpp/tests/commBuffer_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_COMM_BUFFER_UT_HPP__ 2 | #define __COMM_COMM_BUFFER_UT_HPP__ 3 | 4 | #include 5 | #include "comm/commBuffer.hpp" 6 | #include 7 | 8 | namespace comm 9 | { 10 | class CommBuffer_UT : public ::testing::Test 11 | { 12 | public: 13 | 14 | protected: 15 | CommBuffer_UT(); 16 | 17 | virtual void SetUp(void); 18 | static void SetUpTestCase(void); 19 | 20 | /* The class under test. 21 | */ 22 | CommBuffer< std::vector > m_commBuffer; 23 | 24 | }; 25 | } 26 | 27 | #endif // __COMM_COMM_BUFFER_UT_HPP__ 28 | -------------------------------------------------------------------------------- /cpp/tests/commProcessor_UT.cpp: -------------------------------------------------------------------------------- 1 | #include "tests/commProcessor_UT.hpp" 2 | #include "comm/testMsgProcessor.hpp" 3 | #include "comm/tdmaCmds.hpp" 4 | #include "comm/msgProcessor.hpp" 5 | #include 6 | #include 7 | 8 | using std::vector; 9 | 10 | namespace { 11 | comm::TestMsgProcessor testProcessor; 12 | vector msgProcessors = {&testProcessor}; 13 | } 14 | 15 | namespace comm 16 | { 17 | CommProcessor_UT::CommProcessor_UT() : 18 | m_commProcessor(CommProcessor(vector())) 19 | { 20 | } 21 | 22 | void CommProcessor_UT::SetUpTestCase(void) { 23 | } 24 | 25 | void CommProcessor_UT::SetUp(void) 26 | { 27 | } 28 | 29 | TEST_F(CommProcessor_UT, processMsg) { 30 | // Test with no message processors 31 | vector msg = {TDMACmds::MeshStatus,2,3,4,5}; 32 | MsgProcessorArgs args; 33 | EXPECT_TRUE(m_commProcessor.processMsg(msg, args) == -1); 34 | 35 | // Test with proper processor 36 | m_commProcessor.msgProcessors = msgProcessors; 37 | EXPECT_TRUE(m_commProcessor.processMsg(msg, args) == 0); 38 | 39 | // Test with multiple processors 40 | comm::TestMsgProcessor badProcessor; 41 | badProcessor.cmdIds = vector({255}); 42 | m_commProcessor.msgProcessors = vector({&badProcessor, &testProcessor}); 43 | EXPECT_TRUE(m_commProcessor.processMsg(msg, args) == 1); 44 | 45 | 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /cpp/tests/commProcessor_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_COMM_PROCESSOR_UT_HPP__ 2 | #define __COMM_COMM_PROCESSOR_UT_HPP__ 3 | 4 | #include 5 | #include "comm/commProcessor.hpp" 6 | 7 | namespace comm 8 | { 9 | class CommProcessor_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | CommProcessor_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | /* The class under test. 20 | */ 21 | CommProcessor m_commProcessor; 22 | 23 | }; 24 | } 25 | 26 | #endif // __COMM_COMM_PROCESSOR_UT_HPP__ 27 | -------------------------------------------------------------------------------- /cpp/tests/commandUtils_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_COMMAND_UTILS_UT_HPP__ 2 | #define __COMM_COMMAND_UTILS_UT_HPP__ 3 | 4 | #include 5 | 6 | namespace comm 7 | { 8 | class CommandUtils_UT : public ::testing::Test 9 | { 10 | public: 11 | 12 | protected: 13 | CommandUtils_UT(); 14 | 15 | virtual void SetUp(void); 16 | static void SetUpTestCase(void); 17 | 18 | }; 19 | } 20 | 21 | #endif // __COMM_COMMAND_UTILS_UT_HPP__ 22 | -------------------------------------------------------------------------------- /cpp/tests/command_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_COMMAND_UT_HPP__ 2 | #define __COMM_COMMAND_UT_HPP__ 3 | 4 | #include 5 | 6 | namespace comm 7 | { 8 | class Command_UT : public ::testing::Test 9 | { 10 | public: 11 | 12 | protected: 13 | Command_UT(); 14 | 15 | virtual void SetUp(void); 16 | static void SetUpTestCase(void); 17 | 18 | }; 19 | } 20 | 21 | #endif // __COMM_COMMAND_UT_HPP__ 22 | -------------------------------------------------------------------------------- /cpp/tests/crc_UT.cpp: -------------------------------------------------------------------------------- 1 | #include "tests/crc_UT.hpp" 2 | #include 3 | #include 4 | #include 5 | #include "comm/crc.hpp" 6 | 7 | using std::vector; 8 | 9 | vector testMsg = {1, 2, 3, 4, 5, 100, 90, 80, 70, 60}; 10 | comm::crc_t validCRC = 21788; 11 | vector crcBytes = {0x55, 0x1C}; 12 | 13 | namespace comm 14 | { 15 | 16 | crc_UT::crc_UT() 17 | { 18 | } 19 | 20 | void crc_UT::SetUpTestCase(void) { 21 | 22 | } 23 | 24 | void crc_UT::SetUp(void) 25 | { 26 | } 27 | 28 | TEST_F(crc_UT, create) { 29 | crc_t crc = crc_create(testMsg); 30 | EXPECT_TRUE(crc == validCRC); 31 | } 32 | 33 | TEST_F(crc_UT, bytesToCrc) { 34 | EXPECT_TRUE(bytesToCrc(crcBytes) == validCRC); 35 | } 36 | 37 | TEST_F(crc_UT, crcToBytes) { 38 | vector bytes = crcToBytes(validCRC); 39 | EXPECT_TRUE(bytes[0] == crcBytes[0]); 40 | EXPECT_TRUE(bytes[1] == crcBytes[1]); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /cpp/tests/crc_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef COMM_CRC_UT_HPP 2 | #define COMM_CRC_UT_HPP 3 | 4 | #include 5 | 6 | namespace comm 7 | { 8 | class crc_UT : public ::testing::Test 9 | { 10 | public: 11 | 12 | protected: 13 | crc_UT(); 14 | 15 | virtual void SetUp(void); 16 | static void SetUpTestCase(void); 17 | 18 | }; 19 | } 20 | 21 | #endif // COMM_CRC_UT_HPP 22 | -------------------------------------------------------------------------------- /cpp/tests/formationClock_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_FORMATION_CLOCK_UT_HPP__ 2 | #define __COMM_FORMATION_CLOCK_UT_HPP__ 3 | 4 | #include 5 | #include "comm/formationClock.hpp" 6 | 7 | namespace comm 8 | { 9 | class FormationClock_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | FormationClock_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | /* The class under test. 20 | */ 21 | FormationClock m_clock; 22 | 23 | }; 24 | } 25 | 26 | #endif // __COMM_FORMATION_CLOCK_UT_HPP__ 27 | -------------------------------------------------------------------------------- /cpp/tests/li1Radio_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_LI1_RADIO_UT_HPP__ 2 | #define __COMM_LI1_RADIO_UT_HPP__ 3 | 4 | #include 5 | #include "comm/li1Radio.hpp" 6 | 7 | namespace comm 8 | { 9 | class Li1Radio_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | Li1Radio_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | /* The class under test. 20 | */ 21 | Li1Radio m_li1Radio; 22 | 23 | }; 24 | } 25 | 26 | #endif // __COMM_LI1_RADIO_UT_HPP__ 27 | -------------------------------------------------------------------------------- /cpp/tests/msgParser_UT.cpp: -------------------------------------------------------------------------------- 1 | #include "tests/msgParser_UT.hpp" 2 | #include 3 | #include 4 | #include 5 | 6 | namespace comm 7 | { 8 | 9 | MsgParser_UT::MsgParser_UT() 10 | : m_msgParser(10) 11 | { 12 | } 13 | 14 | void MsgParser_UT::SetUpTestCase(void) { 15 | 16 | } 17 | 18 | void MsgParser_UT::SetUp(void) 19 | { 20 | } 21 | 22 | TEST_F(MsgParser_UT, encodeMsg) { 23 | const unsigned int msgLength = 5; 24 | uint8_t data[msgLength] = {1,2,3,4,5}; 25 | std::vector dataIn(data, data + msgLength); 26 | 27 | std::vector out = m_msgParser.encodeMsg(dataIn); 28 | EXPECT_TRUE(out.size() == msgLength); 29 | for (unsigned int i = 0; i < msgLength; i++) { 30 | EXPECT_TRUE(data[i] == out[i]); 31 | } 32 | 33 | } 34 | 35 | TEST_F(MsgParser_UT, parseSerialMsg) { 36 | const unsigned int msgLength = 5; 37 | uint8_t data[msgLength] = {1,2,3,4,5}; 38 | std::vector dataIn(data, data + msgLength); 39 | 40 | // Parse entire message 41 | m_msgParser.parseSerialMsg(dataIn, 0); 42 | EXPECT_TRUE(m_msgParser.parsedMsgs.size() == 1); 43 | EXPECT_TRUE(m_msgParser.parsedMsgs[0].size() == msgLength); 44 | for (unsigned int i = 0; i < msgLength; i++) { 45 | EXPECT_TRUE(data[i] == m_msgParser.parsedMsgs[0][i]); 46 | } 47 | 48 | // Parse partial message 49 | m_msgParser.parseSerialMsg(dataIn, 1); 50 | EXPECT_TRUE(m_msgParser.parsedMsgs.size() == 2); 51 | EXPECT_TRUE(m_msgParser.parsedMsgs[1].size() == msgLength-1); 52 | for (unsigned int i = 0; i < msgLength-1; i++) { 53 | EXPECT_TRUE(data[i+1] == m_msgParser.parsedMsgs[1][i]); 54 | } 55 | } 56 | 57 | TEST_F(MsgParser_UT, parseMsgs) { 58 | const unsigned int msgLength = 5; 59 | uint8_t data[msgLength] = {1,2,3,4,5}; 60 | std::vector dataIn(data, data + msgLength); 61 | 62 | m_msgParser.parseMsgs(dataIn); 63 | EXPECT_TRUE(m_msgParser.parsedMsgs.size() == 1); 64 | EXPECT_TRUE(m_msgParser.parsedMsgs[0].size() == msgLength); 65 | for (unsigned int i = 0; i < msgLength; i++) { 66 | EXPECT_TRUE(data[i] == m_msgParser.parsedMsgs[0][i]); 67 | } 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /cpp/tests/msgParser_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_MSG_PARSER_UT_HPP__ 2 | #define __COMM_MSG_PARSER_UT_HPP__ 3 | 4 | #include 5 | #include "comm/msgParser.hpp" 6 | 7 | namespace comm 8 | { 9 | class MsgParser_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | MsgParser_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | /* The class under test. 20 | */ 21 | MsgParser m_msgParser; 22 | 23 | }; 24 | } 25 | 26 | #endif // __COMM_MSG_PARSER_UT_HPP__ 27 | -------------------------------------------------------------------------------- /cpp/tests/nodeCmds_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_NODE_CMDS_UT_HPP__ 2 | #define __COMM_NODE_CMDS_UT_HPP__ 3 | 4 | #include 5 | 6 | namespace comm 7 | { 8 | class NodeCmds_UT : public ::testing::Test 9 | { 10 | public: 11 | 12 | protected: 13 | NodeCmds_UT(); 14 | 15 | virtual void SetUp(void); 16 | static void SetUpTestCase(void); 17 | 18 | }; 19 | } 20 | 21 | #endif // __COMM_NODE_CMDS_UT_HPP__ 22 | -------------------------------------------------------------------------------- /cpp/tests/nodeConfig_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __NODE_NODE_CONFIG_UT_HPP__ 2 | #define __NODE_NODE_CONFIG_UT_HPP__ 3 | 4 | #include 5 | #include "node/nodeConfig.hpp" 6 | 7 | namespace node 8 | { 9 | class NodeConfig_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | NodeConfig_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | // The class under test. 20 | node::NodeConfig m_nodeConfig; 21 | 22 | }; 23 | } 24 | 25 | #endif // __NODE_NODE_CONFIG_UT_HPP__ 26 | -------------------------------------------------------------------------------- /cpp/tests/nodeMsgProcessor_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_NODE_MSG_PROCESSOR_UT_HPP__ 2 | #define __COMM_NODE_MSG_PROCESSOR_UT_HPP__ 3 | 4 | #include 5 | #include "comm/msgProcessor.hpp" 6 | #include "comm/command.hpp" 7 | #include "comm/nodeMsgProcessor.hpp" 8 | #include 9 | 10 | namespace comm 11 | { 12 | class NodeMsgProcessor_UT : public ::testing::Test 13 | { 14 | public: 15 | 16 | protected: 17 | NodeMsgProcessor_UT(); 18 | 19 | virtual void SetUp(void); 20 | static void SetUpTestCase(void); 21 | 22 | /* 23 | * Message processing arguments. 24 | */ 25 | MsgProcessorArgs m_args; 26 | 27 | /* 28 | * Command queue. 29 | */ 30 | std::unordered_map > m_cmdQueue; 31 | 32 | /* 33 | * Command relay buffer. 34 | */ 35 | std::vector m_relayBuffer; 36 | 37 | /* 38 | * The class under test. 39 | */ 40 | NodeMsgProcessor m_nodeMsgProcessor; 41 | 42 | }; 43 | } 44 | 45 | #endif // __COMM_NODE_MSG_PROCESSOR_UT_HPP__ 46 | -------------------------------------------------------------------------------- /cpp/tests/nodeParams_UT.cpp: -------------------------------------------------------------------------------- 1 | #include "tests/nodeParams_UT.hpp" 2 | #include 3 | #include "node/nodeConfig.hpp" 4 | #include "comm/utilities.hpp" 5 | #include "comm/formationClock.hpp" 6 | 7 | using std::vector; 8 | 9 | namespace { 10 | 11 | } 12 | 13 | namespace node 14 | { 15 | NodeParams_UT::NodeParams_UT() 16 | { 17 | } 18 | 19 | void NodeParams_UT::SetUpTestCase(void) { 20 | // Load node params 21 | NodeConfig config("nodeConfig.json"); 22 | NodeParams::loadParams(config); 23 | } 24 | 25 | void NodeParams_UT::SetUp(void) 26 | { 27 | } 28 | 29 | TEST_F(NodeParams_UT, loadParams) { 30 | // Confirm successful loading of parameters 31 | EXPECT_TRUE(NodeParams::nodeStatus.size() == NodeParams::config.maxNumNodes); 32 | 33 | EXPECT_TRUE(NodeParams::nodeParamsLoaded); 34 | } 35 | 36 | TEST_F(NodeParams_UT, getCmdCounter) { 37 | unsigned int counterValue; 38 | // Test random counter 39 | for (unsigned int i = 0; i < 20; i++) { 40 | counterValue = NodeParams::getCmdCounter(); 41 | EXPECT_TRUE(counterValue >= 0 && counterValue <=65536); 42 | } 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /cpp/tests/nodeParams_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_NODE_PARAMS_UT_HPP__ 2 | #define __COMM_NODE_PARAMS_UT_HPP__ 3 | 4 | #include 5 | #include "node/nodeParams.hpp" 6 | 7 | namespace node 8 | { 9 | class NodeParams_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | NodeParams_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | }; 20 | } 21 | 22 | #endif // __COMM_NODE_PARAMS_UT_HPP__ 23 | -------------------------------------------------------------------------------- /cpp/tests/radio_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_RADIO_UT_HPP__ 2 | #define __COMM_RADIO_UT_HPP__ 3 | 4 | #include 5 | #include "comm/radio.hpp" 6 | 7 | namespace comm 8 | { 9 | class Radio_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | Radio_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | /* The class under test. 20 | */ 21 | Radio m_radio; 22 | 23 | }; 24 | } 25 | 26 | #endif // __COMM_RADIO_UT_HPP__ 27 | -------------------------------------------------------------------------------- /cpp/tests/serialComm_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_SERIAL_COMM_UT_HPP__ 2 | #define __COMM_SERIAL_COMM_UT_HPP__ 3 | 4 | #include 5 | #include "comm/serialComm.hpp" 6 | #include "comm/msgProcessor.hpp" 7 | #include "comm/nodeMsgProcessor.hpp" 8 | #include 9 | 10 | namespace comm 11 | { 12 | class SerialComm_UT : public ::testing::Test 13 | { 14 | public: 15 | 16 | protected: 17 | SerialComm_UT(); 18 | 19 | virtual void SetUp(void); 20 | static void SetUpTestCase(void); 21 | 22 | /* 23 | * Message processor container. 24 | */ 25 | std::vector m_msgProcessors; 26 | 27 | /* 28 | * Message processor for test usage 29 | */ 30 | NodeMsgProcessor m_nodeProcessor; 31 | 32 | /* 33 | * The class under test. 34 | */ 35 | SerialComm m_serialComm; 36 | 37 | 38 | }; 39 | } 40 | 41 | #endif // __COMM_SERIAL_COMM_UT_HPP__ 42 | -------------------------------------------------------------------------------- /cpp/tests/serialRadio_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_SERIAL_RADIO_UT_HPP__ 2 | #define __COMM_SERIAL_RADIO_UT_HPP__ 3 | 4 | #include 5 | #include "comm/serialRadio.hpp" 6 | 7 | namespace comm 8 | { 9 | class SerialRadio_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | SerialRadio_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | /* The class under test. 20 | */ 21 | SerialRadio m_radio; 22 | 23 | }; 24 | } 25 | 26 | #endif // __COMM_SERIAL_RADIO_UT_HPP__ 27 | -------------------------------------------------------------------------------- /cpp/tests/tdmaCmds_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_TDMA_CMDS_UT_HPP__ 2 | #define __COMM_TDMA_CMDS_UT_HPP__ 3 | 4 | #include 5 | 6 | namespace comm 7 | { 8 | class TDMACmds_UT : public ::testing::Test 9 | { 10 | public: 11 | 12 | protected: 13 | TDMACmds_UT(); 14 | 15 | virtual void SetUp(void); 16 | static void SetUpTestCase(void); 17 | 18 | }; 19 | } 20 | 21 | #endif // __COMM_TDMA_CMDS_UT_HPP__ 22 | -------------------------------------------------------------------------------- /cpp/tests/tdmaComm_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_TDMA_COMM_UT_HPP__ 2 | #define __COMM_TDMA_COMM_UT_HPP__ 3 | 4 | #include 5 | #include "comm/tdmaComm.hpp" 6 | #include "comm/tdmaMsgProcessor.hpp" 7 | #include "comm/serialRadio.hpp" 8 | //#include "comm/commProcessor.hpp" 9 | #include "comm/SLIPMsgParser.hpp" 10 | #include 11 | 12 | namespace comm 13 | { 14 | class TDMAComm_UT : public ::testing::Test 15 | { 16 | public: 17 | 18 | protected: 19 | TDMAComm_UT(); 20 | 21 | virtual void SetUp(void); 22 | static void SetUpTestCase(void); 23 | 24 | /* 25 | * Support objects. 26 | */ 27 | comm::TDMAMsgProcessor m_tdmaProcessor; 28 | std::vector m_msgProcessors; 29 | 30 | /* The class under test. 31 | */ 32 | TDMAComm m_tdmaComm; 33 | 34 | }; 35 | } 36 | 37 | #endif // __COMM_TDMA_COMM_UT_HPP__ 38 | -------------------------------------------------------------------------------- /cpp/tests/tdmaMsgProcessor_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_TDMA_MSG_PROCESSOR_UT_HPP__ 2 | #define __COMM_TDMA_MSG_PROCESSOR_UT_HPP__ 3 | 4 | #include 5 | #include "comm/msgProcessor.hpp" 6 | #include "comm/command.hpp" 7 | #include "comm/tdmaMsgProcessor.hpp" 8 | #include 9 | 10 | namespace comm 11 | { 12 | class TDMAMsgProcessor_UT : public ::testing::Test 13 | { 14 | public: 15 | 16 | protected: 17 | TDMAMsgProcessor_UT(); 18 | 19 | virtual void SetUp(void); 20 | static void SetUpTestCase(void); 21 | 22 | /* 23 | * Message processing arguments. 24 | */ 25 | MsgProcessorArgs m_args; 26 | 27 | /* 28 | * Command queue. 29 | */ 30 | std::unordered_map > m_cmdQueue; 31 | 32 | /* 33 | * Command relay buffer. 34 | */ 35 | std::vector m_relayBuffer; 36 | 37 | /* 38 | * The class under test. 39 | */ 40 | TDMAMsgProcessor m_tdmaMsgProcessor; 41 | 42 | }; 43 | } 44 | 45 | #endif // __COMM_TDMA_MSG_PROCESSOR_UT_HPP__ 46 | -------------------------------------------------------------------------------- /cpp/tests/utilities_UT.cpp: -------------------------------------------------------------------------------- 1 | #include "tests/utilities_UT.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace util 8 | { 9 | Utilities_UT::Utilities_UT() 10 | { 11 | } 12 | 13 | void Utilities_UT::SetUpTestCase(void) { 14 | } 15 | 16 | void Utilities_UT::SetUp(void) 17 | { 18 | } 19 | 20 | TEST_F(Utilities_UT, hashElement) { 21 | SHA_CTX context; 22 | SHA1_Init(&context); 23 | 24 | // Test hashing of int 25 | unsigned int intVal = 120; 26 | unsigned char hashVal[20] = {119, 91, 197, 195, 14, 39, 240, 229, 98, 17, 93, 19, 110, 127, 126, 219, 211, 206, 173, 137}; 27 | hashElement(&context, intVal); 28 | unsigned char outHash[20]; 29 | SHA1_Final(outHash, &context); 30 | for (unsigned int i = 0; i < 20; i++) { 31 | EXPECT_TRUE(outHash[i] == hashVal[i]); 32 | } 33 | 34 | // Test proper truncation of floats 35 | double doubleVal = 123456789.987654321; 36 | unsigned char doubleHashVal[20] = {57, 184, 2, 193, 35, 225, 250, 6, 9, 174, 32, 17, 151, 2, 189, 243, 98, 4, 114, 56}; 37 | SHA1_Init(&context); 38 | hashElement(&context, doubleVal); 39 | SHA1_Final(outHash, &context); 40 | for (unsigned int i = 0; i < 20; i++) { 41 | EXPECT_TRUE(outHash[i] == doubleHashVal[i]); 42 | } 43 | 44 | // Test equality of floats 45 | SHA1_Init(&context); 46 | hashElement(&context, 123456789.9876543); 47 | SHA1_Final(outHash, &context); 48 | for (unsigned int i = 0; i < 20; i++) { 49 | EXPECT_TRUE(outHash[i] == doubleHashVal[i]); 50 | } 51 | 52 | // Test hashing of string 53 | unsigned char strHashVal[20] = {32, 7, 193, 121, 130, 25, 101, 249, 148, 120, 27, 125, 133, 199, 187, 217, 166, 183, 81, 227}; 54 | std::string strVal = "thisIsAString"; 55 | SHA1_Init(&context); 56 | hashElement(&context, strVal); 57 | SHA1_Final(outHash, &context); 58 | for (unsigned int i = 0; i < 20; i++) { 59 | EXPECT_TRUE(outHash[i] == strHashVal[i]); 60 | } 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /cpp/tests/utilities_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __UTIL_UTILITIES_UT_HPP__ 2 | #define __UTIL_UTILITIES_UT_HPP__ 3 | 4 | #include 5 | #include "comm/utilities.hpp" 6 | 7 | namespace util 8 | { 9 | class Utilities_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | Utilities_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | }; 20 | } 21 | 22 | #endif // __UTIL_UTILITIES_UT_HPP__ 23 | -------------------------------------------------------------------------------- /cpp/tests/xbeeRadio_UT.cpp: -------------------------------------------------------------------------------- 1 | #include "tests/xbeeRadio_UT.hpp" 2 | #include "GPIOWrapper/GPIOWrapper.hpp" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace comm 9 | { 10 | serial::Serial xbeeSer("/dev/ttyV2", 9600, serial::Timeout::simpleTimeout(10)); 11 | comm::RadioConfig xbeeConfig; 12 | static int testPin; 13 | 14 | XbeeRadio_UT::XbeeRadio_UT() 15 | : m_xbeeRadio(&xbeeSer, xbeeConfig, GPIOWrapper::getPin("P8_26")) 16 | { 17 | } 18 | 19 | void XbeeRadio_UT::SetUpTestCase(void) { 20 | testPin = GPIOWrapper::getPin("P8_19"); 21 | GPIOWrapper::setupPin(testPin, GPIOWrapper::INPUT); 22 | } 23 | 24 | void XbeeRadio_UT::SetUp(void) 25 | { 26 | } 27 | 28 | TEST_F(XbeeRadio_UT, wake_gpio) { 29 | m_xbeeRadio.wake(); 30 | std::cout << "Wake pin value: " << GPIOWrapper::getValue(testPin) << std::endl; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /cpp/tests/xbeeRadio_UT.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __COMM_XBEE_RADIO_UT_HPP__ 2 | #define __COMM_XBEE_RADIO_UT_HPP__ 3 | 4 | #include 5 | #include "comm/xbeeRadio.hpp" 6 | 7 | namespace comm 8 | { 9 | class XbeeRadio_UT : public ::testing::Test 10 | { 11 | public: 12 | 13 | protected: 14 | XbeeRadio_UT(); 15 | 16 | virtual void SetUp(void); 17 | static void SetUpTestCase(void); 18 | 19 | /* The class under test. 20 | */ 21 | XbeeRadio m_xbeeRadio; 22 | 23 | }; 24 | } 25 | 26 | #endif // __COMM_XBEE_RADIO_UT_HPP__ 27 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = python3 -msphinx 7 | SPHINXPROJ = MeshNetworkCommunicationSystem 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /doc/README: -------------------------------------------------------------------------------- 1 | -Autogenerate Sphinx sources for a python module 2 | To autogenerate Sphinx source files for a python module use the sphinx-apidoc tool. Copy resulting .rst files into source directory and link to existing source structure. 3 | -------------------------------------------------------------------------------- /doc/build/doctrees/api.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/api.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/config.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/config.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/cpp.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/cpp.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/design.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/design.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/environment.pickle -------------------------------------------------------------------------------- /doc/build/doctrees/hardware.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/hardware.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/hostInterface.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/hostInterface.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/index.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/mesh.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/mesh.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/mesh.generic.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/mesh.generic.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/mesh.interface.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/mesh.interface.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/python.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/python.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/setup.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/setup.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/software.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/software.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/unittests.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/unittests.doctree -------------------------------------------------------------------------------- /doc/build/doctrees/vhdl.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/doctrees/vhdl.doctree -------------------------------------------------------------------------------- /doc/build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: d9a6297229d63b71d185f276d39efb5b 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /doc/build/html/_images/blockTx_sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_images/blockTx_sequence.png -------------------------------------------------------------------------------- /doc/build/html/_images/hardware_1stgen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_images/hardware_1stgen.png -------------------------------------------------------------------------------- /doc/build/html/_images/hardware_2ndgen_astrodev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_images/hardware_2ndgen_astrodev.png -------------------------------------------------------------------------------- /doc/build/html/_images/hardware_2ndgen_xbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_images/hardware_2ndgen_xbee.png -------------------------------------------------------------------------------- /doc/build/html/_images/hardware_currentgen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_images/hardware_currentgen.png -------------------------------------------------------------------------------- /doc/build/html/_images/tdma_frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_images/tdma_frame.png -------------------------------------------------------------------------------- /doc/build/html/_images/topology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_images/topology.png -------------------------------------------------------------------------------- /doc/build/html/_sources/api.rst.txt: -------------------------------------------------------------------------------- 1 | API 2 | === 3 | 4 | -------------------------------------------------------------------------------- /doc/build/html/_sources/cpp.rst.txt: -------------------------------------------------------------------------------- 1 | C++ 2 | === 3 | 4 | 5 | 6 | Coming soon! 7 | 8 | C++ API 9 | ^^^^^^^^^^ 10 | -------------------------------------------------------------------------------- /doc/build/html/_sources/mesh.interface.rst.txt: -------------------------------------------------------------------------------- 1 | mesh\.interface package 2 | ======================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | mesh\.interface\.nodeInterface\_pb2 module 8 | ------------------------------------------ 9 | 10 | .. automodule:: mesh.interface.nodeInterface_pb2 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: mesh.interface 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /doc/build/html/_sources/mesh.rst.txt: -------------------------------------------------------------------------------- 1 | mesh package 2 | ============ 3 | 4 | The **mesh** package contains all of the network management and control logic for the Python implementation of the Mesh Network. This package has two subpackages: *generic* and *interface*. The generic package contains the actual mesh network control code, while the interface package is used to provide interprocess communication between the communication control process and the node control process, which serves as the interface between the mesh network control and the rest of the host platform's computing logic. In the case of a flight vehicle, the node control process would interface with the vehicle's flight computer. The interface package makes use of the Google Protocol Buffer API to serialize and exchange data between processes. 5 | 6 | Subpackages 7 | ----------- 8 | 9 | .. toctree:: 10 | 11 | mesh.generic 12 | mesh.interface 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: mesh 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /doc/build/html/_sources/setup.rst.txt: -------------------------------------------------------------------------------- 1 | Setup 2 | ===== 3 | -------------------------------------------------------------------------------- /doc/build/html/_sources/unittests.rst.txt: -------------------------------------------------------------------------------- 1 | Unit Testing 2 | ============ 3 | -------------------------------------------------------------------------------- /doc/build/html/_static/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_static/ajax-loader.gif -------------------------------------------------------------------------------- /doc/build/html/_static/comment-bright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_static/comment-bright.png -------------------------------------------------------------------------------- /doc/build/html/_static/comment-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_static/comment-close.png -------------------------------------------------------------------------------- /doc/build/html/_static/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_static/comment.png -------------------------------------------------------------------------------- /doc/build/html/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* This file intentionally left blank. */ 2 | -------------------------------------------------------------------------------- /doc/build/html/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | var DOCUMENTATION_OPTIONS = { 2 | URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), 3 | VERSION: '2.0', 4 | LANGUAGE: 'None', 5 | COLLAPSE_INDEX: false, 6 | FILE_SUFFIX: '.html', 7 | HAS_SOURCE: true, 8 | SOURCELINK_SUFFIX: '.txt', 9 | NAVIGATION_WITH_KEYS: false 10 | }; -------------------------------------------------------------------------------- /doc/build/html/_static/down-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_static/down-pressed.png -------------------------------------------------------------------------------- /doc/build/html/_static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_static/down.png -------------------------------------------------------------------------------- /doc/build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_static/file.png -------------------------------------------------------------------------------- /doc/build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_static/minus.png -------------------------------------------------------------------------------- /doc/build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_static/plus.png -------------------------------------------------------------------------------- /doc/build/html/_static/up-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_static/up-pressed.png -------------------------------------------------------------------------------- /doc/build/html/_static/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/_static/up.png -------------------------------------------------------------------------------- /doc/build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/build/html/objects.inv -------------------------------------------------------------------------------- /doc/hardware_1stgen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/hardware_1stgen.png -------------------------------------------------------------------------------- /doc/hardware_2ndgen_astrodev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/hardware_2ndgen_astrodev.png -------------------------------------------------------------------------------- /doc/hardware_2ndgen_xbee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/hardware_2ndgen_xbee.png -------------------------------------------------------------------------------- /doc/hardware_currentgen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/hardware_currentgen.png -------------------------------------------------------------------------------- /doc/source/cpp.rst: -------------------------------------------------------------------------------- 1 | C++ 2 | === 3 | 4 | 5 | 6 | Coming soon! 7 | 8 | C++ API 9 | ^^^^^^^^^^ 10 | -------------------------------------------------------------------------------- /doc/source/mesh.interface.rst: -------------------------------------------------------------------------------- 1 | mesh\.interface package 2 | ======================= 3 | 4 | Submodules 5 | ---------- 6 | 7 | mesh\.interface\.nodeInterface\_pb2 module 8 | ------------------------------------------ 9 | 10 | .. automodule:: mesh.interface.nodeInterface_pb2 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: mesh.interface 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /doc/source/mesh.rst: -------------------------------------------------------------------------------- 1 | mesh package 2 | ============ 3 | 4 | The **mesh** package contains all of the network management and control logic for the Python implementation of the Mesh Network. This package has two subpackages: *generic* and *interface*. The generic package contains the actual mesh network control code, while the interface package is used to provide interprocess communication between the communication control process and the node control process, which serves as the interface between the mesh network control and the rest of the host platform's computing logic. In the case of a flight vehicle, the node control process would interface with the vehicle's flight computer. The interface package makes use of the Google Protocol Buffer API to serialize and exchange data between processes. 5 | 6 | Subpackages 7 | ----------- 8 | 9 | .. toctree:: 10 | 11 | mesh.generic 12 | mesh.interface 13 | 14 | Module contents 15 | --------------- 16 | 17 | .. automodule:: mesh 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /doc/source/unittests.rst: -------------------------------------------------------------------------------- 1 | Unit Testing 2 | ============ 3 | -------------------------------------------------------------------------------- /doc/tdma_frame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/tdma_frame.png -------------------------------------------------------------------------------- /doc/topology.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/doc/topology.png -------------------------------------------------------------------------------- /interface/nodeConfig.proto: -------------------------------------------------------------------------------- 1 | syntax ="proto3"; 2 | package nodeConfig; 3 | 4 | message NodeConfiguration { 5 | uint32 nodeId = 1; 6 | uint32 maxNumNodes = 2; 7 | string platform = 3; 8 | float nodeUpdateTimeout = 4; 9 | float FCCommWriteInterval = 5; 10 | string FCCommDevice = 6; 11 | uint64 FCBaudrate = 7; 12 | float cmdInterval = 8; 13 | float logInterval = 9; 14 | string commType = 10; 15 | uint32 numMeshNetworks = 11; 16 | repeated string meshDevices = 12; 17 | repeated string radios = 13; 18 | repeated string msgParsers = 14; 19 | uint64 meshBaudrate = 15; 20 | uint32 parseMsgMax = 16; 21 | uint32 rxBufferSize = 17; 22 | bool gcsPresent = 18; 23 | } 24 | 25 | message InterfaceConfiguration { 26 | string nodeCommIntIP = 1; 27 | uint32 commRdPort = 2; 28 | uint32 commWrPort = 3; 29 | } 30 | 31 | message TDMAConfiguration { 32 | string sleepPin = 1; 33 | float enableLength = 2; 34 | float slotGuardLength = 3; 35 | float preTxGuardLength = 4; 36 | float postTxGuardLength = 5; 37 | float txLength = 6; 38 | float rxDelay = 7; 39 | float initTimeToWait = 8; 40 | uint32 maxNumSlots = 9; 41 | float desiredDataRate = 10; 42 | uint32 initSyncBound = 11; 43 | uint32 operateSyncBound = 12; 44 | float offsetTimeout = 13; 45 | float offsetTxInterval = 14; 46 | float statusTxInterval = 15; 47 | float linksTxInterval = 16; 48 | float linkTimeout = 17; 49 | uint32 blockTxMaxLength = 18; 50 | uint32 blockTxReceiptTimeout = 19; 51 | uint32 blockTxPacketRetry = 20; 52 | float blockTxEndMult = 21; 53 | bool fpga = 22; 54 | string fpgaFailsafePin = 23; 55 | uint32 fpgaFifoSize = 24; 56 | string enablePin = 25; 57 | string statusPin = 26; 58 | bool recvAllMsgs = 27; 59 | uint32 restartDelay = 28; 60 | uint32 pollTimeout = 29; 61 | bool adminEnable = 30; 62 | uint32 adminLength = 31; 63 | uint32 adminBytesMaxLength = 32; 64 | uint32 msgPayloadMaxLength = 33; 65 | } 66 | 67 | message NodeConfig_proto { 68 | NodeConfiguration node = 1; 69 | InterfaceConfiguration interface = 2; 70 | TDMAConfiguration tdma = 3; 71 | } 72 | -------------------------------------------------------------------------------- /interface/nodeInterface.proto: -------------------------------------------------------------------------------- 1 | syntax ="proto3"; 2 | package nodeInterface; 3 | 4 | message Command { 5 | float txInterval = 1; 6 | bytes msgBytes = 2; 7 | uint32 cmdId = 3; 8 | uint32 destId = 4; 9 | } 10 | 11 | message NodeThreadMsg { 12 | enum NodeMsgType { 13 | NODE = 0; 14 | COMM = 1; 15 | } 16 | 17 | NodeMsgType type = 1; 18 | double timestamp = 2; 19 | bytes cmdRelay = 3; 20 | repeated Command cmds = 4; 21 | repeated uint32 linkStatus = 5; 22 | bytes rcvdBytes = 6; 23 | bytes dataBlock = 7; 24 | } 25 | 26 | message MeshMsg { 27 | uint32 msgType = 1; 28 | uint32 cmdId = 2; 29 | uint32 status = 3; 30 | bytes msgBytes = 4; 31 | } 32 | 33 | message MeshMsgs { 34 | repeated MeshMsg msgs = 1; 35 | } 36 | -------------------------------------------------------------------------------- /python/demoController.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.nodeController import NodeController 2 | 3 | class DemoController(NodeController): 4 | """Demo node controller.""" 5 | 6 | def executeNode(self): 7 | """Executes any processing logic required by this node.""" 8 | 9 | # Update node status 10 | self.nodeParams.updateStatus() 11 | 12 | # Send dummy outgoing broadcast message 13 | self.queueOut[0] = b'12345' 14 | -------------------------------------------------------------------------------- /python/execute.py: -------------------------------------------------------------------------------- 1 | import serial 2 | import os, time, sys 3 | from multiprocessing import Value 4 | from mesh.generic.nodeParams import NodeParams 5 | from commProcess import CommProcess 6 | from nodeControlProcess import NodeControlProcess 7 | 8 | # Example of how to execute and communicate between TDMA comm element and generic node control software 9 | if __name__ == '__main__': 10 | # Node control shared run flag 11 | # Used by comm process to trigger node control software. Since comm process is time critical, flags keeps node control from unintentionally blocking comm. 12 | runFlag = Value('B', 1) 13 | 14 | # Load network node configuration 15 | configFile = 'nodeConfig.json' 16 | nodeParams = NodeParams(configFile=configFile) 17 | 18 | # Create node communication processes (one process per network) 19 | commProcesses = [None]*nodeParams.config.numMeshNetworks 20 | for i in range(nodeParams.config.numMeshNetworks): 21 | commProcesses[i] = CommProcess(configFile, i, runFlag) 22 | commProcesses[i].daemon = True 23 | 24 | # Create node control process 25 | nodeControlProcess = NodeControlProcess(configFile, runFlag) 26 | nodeControlProcess.daemon = True 27 | 28 | # Start all processes 29 | for process in commProcesses: 30 | process.start() 31 | 32 | nodeControlProcess.start() 33 | 34 | # Monitor running processes and look for termination signal from user 35 | while 1: 36 | try: 37 | time.sleep(10.0) 38 | except KeyboardInterrupt: 39 | print("Stopping program") 40 | for process in commProcesses: 41 | process.terminate() 42 | nodeControlProcess.terminate() 43 | break 44 | 45 | -------------------------------------------------------------------------------- /python/globalCfg.py: -------------------------------------------------------------------------------- 1 | #platform = 'bbb' 2 | platform = 'pc' 3 | -------------------------------------------------------------------------------- /python/mesh/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/python/mesh/__init__.py -------------------------------------------------------------------------------- /python/mesh/generic/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /python/mesh/generic/blockTx.py: -------------------------------------------------------------------------------- 1 | class BlockTxPacketStatus(object): 2 | def __init__(self, packet, packetNum): 3 | self.packet = packet # outgoing mesh packet 4 | self.packetNum = packetNum 5 | self.responsesRcvd = [] 6 | self.retries = 0 7 | self.framesSinceTx = 0 # counter since this packet sent 8 | 9 | class BlockTx(object): 10 | def __init__(self, reqId, length, srcId, destId, startTime, endTime, rawData=None): 11 | self.complete = False 12 | self.reqId = reqId 13 | self.length = length 14 | self.srcId = srcId 15 | self.destId = destId 16 | self.startTime = startTime 17 | self.endTime = endTime 18 | self.packets = dict() 19 | self.data = rawData 20 | self.dataLoc = 0 21 | self.packetNum = 0 22 | self.dataComplete = False 23 | 24 | def allPacketsRcvd(self): 25 | for packetNum in range(self.length): 26 | if (packetNum + 1 not in self.packets): # packet not received 27 | return False 28 | 29 | return True # all packets have been received 30 | 31 | def getData(self): 32 | # Verify that block data is complete 33 | if (self.allPacketsRcvd()): 34 | self.dataComplete = True 35 | 36 | outData = b'' 37 | 38 | for packetNum in range(self.length): 39 | if (packetNum+1 in self.packets): # packet received 40 | outData += self.packets[packetNum+1] 41 | 42 | return outData 43 | 44 | #else: # missing packets 45 | # return b'' 46 | -------------------------------------------------------------------------------- /python/mesh/generic/checksum.py: -------------------------------------------------------------------------------- 1 | from struct import unpack 2 | 3 | def calc8bitFletcherChecksum(msgBytes): 4 | """Calculate 8-bit Fletcher checksum for Li-1 radio packets. 5 | 6 | Args: 7 | msgBytes: Raw message bytes to calculate checksum of. 8 | """ 9 | ck_A = 0 10 | ck_B = 0 11 | for msgByte in msgBytes: 12 | ck_A += int(msgByte) 13 | ck_B += ck_A 14 | 15 | return [ck_A & 0xFF, ck_B & 0xFF] 16 | 17 | def compareChecksum(msgBytes, checksumBytes): 18 | """Compute and compare Li-1 message checksum. 19 | 20 | Args: 21 | msgBytes: Raw message bytes. 22 | checksumBytes: Checksum to compare against. 23 | Returns: 24 | A boolean of whether checksum matched or not. 25 | """ 26 | 27 | checksum = calc8bitFletcherChecksum(msgBytes) 28 | msgChecksum = list(unpack('BB', checksumBytes)) 29 | 30 | if checksum == msgChecksum: 31 | return True # check sum matches 32 | else: 33 | return False 34 | -------------------------------------------------------------------------------- /python/mesh/generic/cmdDict.py: -------------------------------------------------------------------------------- 1 | from struct import pack 2 | from mesh.generic.commandType import CommandType 3 | from mesh.generic.cmds import NodeCmds 4 | from mesh.generic.tdmaCmdDict import TDMACmdDict 5 | from mesh.generic.gndCmdDict import GndCmdDict 6 | from mesh.generic.nodeConfig import configHashSize 7 | #from mesh.generic.testCmdDict import TestCmdDict 8 | 9 | # Serialize methods 10 | def serialize_NodeCmds_CmdResponse(cmdData, timestamp): 11 | """Method for serializing NodeCmds['CmdReponse'] command for serial transmission.""" 12 | return pack(NodeCmdDict[NodeCmds['CmdResponse']].packFormat, cmdData['cmdId'], cmdData['cmdCounter'], cmdData['cmdResponse']) 13 | 14 | def serialize_NodeCmds_GCSCmd(cmdData, timestamp): 15 | """Method for serializing NodeCmds['GCSCmd'] command for serial transmission.""" 16 | #gcsCmd = cmdData['cmd'] 17 | return pack(NodeCmdDict[NodeCmds['GCSCmd']].packFormat, cmdData['destId'], cmdData['mode']) 18 | 19 | def serialize_NodeCmds_ConfigRequest(cmdData, timestamp): 20 | """Method for serializing NodeCmds['ConfigRequest'] command for serial transmission.""" 21 | configHash = cmdData['configHash'] 22 | #msgBytes = pack(NodeCmdDict[NodeCmds['ConfigRequest']].packFormat, NodeCmds['ConfigRequest'], cmdData['nodeId']) 23 | #return msgBytes + configHash 24 | return configHash 25 | 26 | def serialize_NodeCmds_ParamUpdate(cmdData, timestamp): 27 | """Method for serializing NodeCmds['ParamUpdate'] command for serial transmission.""" 28 | paramValue = cmdData['paramValue'] # already converted for transmission 29 | msgBytes = pack(NodeCmdDict[NodeCmds['ParamUpdate']].packFormat, cmdData['destId'], cmdData['paramId'], cmdData['dataLength']) 30 | return msgBytes + paramValue 31 | 32 | NodeCmdDict = {NodeCmds['NoOp']: CommandType('', [], [], header='NodeHeader'), \ 33 | NodeCmds['CmdResponse']: CommandType('=BHB', serialize_NodeCmds_CmdResponse, ['cmdId', 'cmdCounter', 'cmdResponse'], header='SourceHeader'), \ 34 | NodeCmds['GCSCmd']: CommandType('=BB', serialize_NodeCmds_GCSCmd, ['destId', 'mode'], header='NodeHeader'), \ 35 | NodeCmds['ConfigRequest']: CommandType('<' + str(configHashSize) + 's', serialize_NodeCmds_ConfigRequest, ['configHash'], header='NodeHeader'), \ 36 | NodeCmds['ParamUpdate']: CommandType('=BBB', serialize_NodeCmds_ParamUpdate, ['destId', 'paramId', 'dataLength'], header='NodeHeader')} 37 | 38 | CmdDict = dict() 39 | CmdDict.update(NodeCmdDict) 40 | CmdDict.update(TDMACmdDict) 41 | CmdDict.update(GndCmdDict) 42 | #CmdDict.update(TestCmdDict) 43 | -------------------------------------------------------------------------------- /python/mesh/generic/cmdStatus.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | class CmdStatus(IntEnum): 4 | accepted = 0 5 | rejected = -1 6 | invalid = 1 7 | notAllowed = 2 8 | staleTarget = 3 9 | 10 | -------------------------------------------------------------------------------- /python/mesh/generic/cmds.py: -------------------------------------------------------------------------------- 1 | 2 | NodeCmds = {'NoOp': 0, 'CmdResponse': 5, 'GCSCmd': 10, 'ParamUpdate': 30, 'ConfigRequest': 40, 'ConfigUpdate': 35} 3 | 4 | PixhawkCmds = NodeCmds.copy() 5 | PixhawkCmds.update({'FormationCmd': 20, 'NodeStateUpdate': 111, 'StateUpdate': 101, 'TargetUpdate': 105, 'PosCmd': 100}) 6 | 7 | SatFCCmds = NodeCmds.copy() 8 | SatFCCmds.update({'StateUpdate': 201, 'NodeStateUpdate': 211, 'ManeuverCmd': 210}) 9 | 10 | PixhawkFCCmds = {'ModeChange': 50, 'ArmCommand': 55, 'VehicleStatus': 60, 'PosCmd': 100} 11 | 12 | TDMACmds = {'MeshStatus': 90, 'TimeOffset': 91, 'TimeOffsetSummary': 92, 'LinkStatus': 93, 'LinkStatusSummary': 94, 'BlockTxRequest': 95, 'BlockTxPacketReceipt': 97, 'BlockTxStatus': 98, 'BlockData': 99, 'CurrentConfig': 120, 'ConfigUpdate': 121, 'NetworkRestart': 125} 13 | 14 | GndCmds = {'TimeOffsetSummary': 92, 'LinkStatusSummary': 94} 15 | 16 | TestCmds = {'SendDataBlock': 150} 17 | 18 | FPGACmds = {'FPGAMsgStart': 250} 19 | 20 | # Commands that should be relayed 21 | cmdsToRelay = [] 22 | #cmdsToRelay = [NodeCmds['GCSCmd'], NodeCmds['ConfigRequest'], NodeCmds['ParamUpdate'], TDMACmds['BlockTxRequest'], TDMACmds['BlockTxRequestResponse'], TDMACmds['BlockTxStatus'], TestCmds['SendDataBlock']] 23 | -------------------------------------------------------------------------------- /python/mesh/generic/commPorts.py: -------------------------------------------------------------------------------- 1 | import os 2 | import itertools 3 | from natsort import natsorted 4 | 5 | def getCommPorts(commPrefix): 6 | commPorts = [] 7 | if os.name == 'nt': # windows 8 | import winreg 9 | 10 | path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM' 11 | try: 12 | key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path) 13 | except WindowsError: 14 | raise IterationError 15 | 16 | ports = [] 17 | for i in itertools.count(): 18 | try: 19 | ports.append(winreg.EnumValue(key, i)[1]) 20 | except EnvironmentError: 21 | break 22 | 23 | for port in ports: 24 | if commPrefix in port: 25 | commPorts.append(port) 26 | 27 | # for i in range(10): 28 | # try: 29 | # s = serial.Serial(i) 30 | # s.close() 31 | # commPorts.append('COM' + str(i + 1)) 32 | # except serial.SerialException: 33 | # pass 34 | elif os.name == 'posix': # unix 35 | import glob 36 | commPorts = glob.glob("/dev/" + commPrefix + "*") 37 | #commPorts = glob.glob("/dev/ttyUSB*") 38 | 39 | return natsorted(commPorts) 40 | -------------------------------------------------------------------------------- /python/mesh/generic/command.py: -------------------------------------------------------------------------------- 1 | from struct import pack 2 | from mesh.generic.nodeHeader import headers, createHeader, packHeader 3 | from mesh.generic.cmdDict import CmdDict 4 | from mesh.generic.customExceptions import CommandIdNotFound 5 | 6 | class Command(object): 7 | def __init__(self, cmdId, cmdData, header=[], txInterval=[], lastTxTime=0.0): 8 | self.cmdId = cmdId 9 | self.cmdData = cmdData 10 | self.txInterval = txInterval 11 | self.lastTxTime = lastTxTime 12 | 13 | try: 14 | if header: # create standard header for cmdId 15 | self.header = createHeader([CmdDict[cmdId].header, header]) # command header 16 | else: 17 | self.header = [] 18 | self.packFormat = CmdDict[cmdId].packFormat # serial pack format 19 | self.serializeMethod = CmdDict[cmdId].serialize # method to serialize command 20 | except KeyError as e: 21 | raise CommandIdNotFound("Command Id {} not found", cmdId) 22 | 23 | def serialize(self, timestamp=[]): 24 | 25 | # Serialize and return command data 26 | return self.packHeader() + self.packBody(timestamp) # combine header with command payload data 27 | 28 | def packBody(self, timestamp=[]): 29 | body = bytearray() 30 | 31 | if self.serializeMethod: 32 | body = self.serializeMethod(self.cmdData, timestamp) 33 | 34 | return body 35 | 36 | def packHeader(self): 37 | header = bytearray() 38 | 39 | # Serialize command data 40 | if self.header: # Pack header 41 | header = packHeader(self.header) 42 | 43 | return header 44 | -------------------------------------------------------------------------------- /python/mesh/generic/commandMsg.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.cmdDict import CmdDict 2 | import time 3 | 4 | class CommandMsg(object): 5 | """Command message class for storing command parameters. 6 | 7 | Attributes: 8 | destId: Node ID of command destination. 9 | cmdData: Command data payload. 10 | timestamp: Creation time of command. 11 | """ 12 | def __init__(self, cmdId=[], cmdData=[], time=time.time(), destId=None): 13 | if cmdId and cmdData: # Create command data based on command ID 14 | self.cmdData = self.parseCommand(cmdId, cmdData) 15 | else: # Store command data directly 16 | self.cmdData = cmdData 17 | self.timestamp = time 18 | if destId != None: 19 | self.destId = destId 20 | 21 | 22 | def parseCommand(self, cmdId=[], cmdData=[]): 23 | """Parses command data based on message format of command ID.""" 24 | #if cmdId and cmdData and cmdId in MessageFormat: # Parse command data based on command ID 25 | if cmdId and cmdData and CmdDict[cmdId].messageFormat: # Parse command data based on command ID 26 | cmdBody = dict() 27 | for i in range(len(CmdDict[cmdId].messageFormat)): 28 | cmdBody[CmdDict[cmdId].messageFormat[i]] = cmdData[i] 29 | return cmdBody 30 | else: # Store raw command data input 31 | return cmdData 32 | -------------------------------------------------------------------------------- /python/mesh/generic/commandType.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | 3 | CommandType = namedtuple('CommandType', ['packFormat', 'serialize', 'messageFormat', 'header']) 4 | -------------------------------------------------------------------------------- /python/mesh/generic/constants.py: -------------------------------------------------------------------------------- 1 | degToRad = 0.0174532925 # conversion from degrees to radians 2 | latLonToM = degToRad * 6378137 # conversion from lat/lon (degrees) to distance (meters) 3 | mu = 398600.4418 # Earth gravitational parameter 4 | Re = 6378.137 # Earth radius (km) 5 | -------------------------------------------------------------------------------- /python/mesh/generic/customExceptions.py: -------------------------------------------------------------------------------- 1 | import serial 2 | 3 | class NoSerialConnection(serial.SerialException): 4 | """Exception to raise if trying to read/write to invalid serial connection.""" 5 | 6 | class NoSocket(serial.SerialException): 7 | """Exception to raise if trying to read/write to invalid socket connection.""" 8 | 9 | class NoCommandHeader(Exception): 10 | """Exception to raise if required commmand header missing.""" 11 | 12 | class InvalidCmdCounter(Exception): 13 | """Exception to raise if attempt made to set command counter outside of allowable range.""" 14 | 15 | class NoCommandHeaderDefined(Exception): 16 | """Exception to raise if command does not define a header.""" 17 | 18 | class InvalidTDMASlotNumber(Exception): 19 | """Exception to raise if TDMA slot number is invalid.""" 20 | 21 | class InvalidRadio(Exception): 22 | """Exception to raise if no valid Radio provided.""" 23 | 24 | class NodeConfigFileError(Exception): 25 | """Exception to raise if error loading node configuration files.""" 26 | 27 | class TDMAConfigError(Exception): 28 | """Exception to raise if error with TDMA comm configuration.""" 29 | 30 | class InsufficientMsgBytes(Exception): 31 | """Exception to raise if attempting to process raw message bytes of insufficient length.""" 32 | 33 | class CommandIdNotFound(Exception): 34 | """Exception to raise if command ID not defined.""" 35 | -------------------------------------------------------------------------------- /python/mesh/generic/formationClock.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.timeLib import getTimeOffset 2 | import time 3 | 4 | class FormationClock: 5 | """The formation clock is used to provide a command time reference among the formation nodes. The clock provides the time with respect to a reference time established upon initialization. 6 | 7 | 8 | Attributes: 9 | time: Current clock time with respect to reference time. 10 | referenceTime: Reference time used by clock to compute clock time upon request. 11 | """ 12 | 13 | def __init__(self, referenceTime=[], timeSource=None): 14 | self.timeSource = None 15 | 16 | if referenceTime: # Initialize time from some reference time 17 | self.referenced = True 18 | self.referenceTime = referenceTime 19 | else: 20 | self.referenced = False 21 | 22 | def getTime(self): 23 | if self.referenced: 24 | return (time.time() - self.referenceTime) 25 | else: 26 | return time.time() 27 | 28 | def getOffset(self): 29 | return getTimeOffset(self.timeSource) 30 | -------------------------------------------------------------------------------- /python/mesh/generic/fpgaRadio.py: -------------------------------------------------------------------------------- 1 | import struct 2 | from mesh.generic.radio import Radio 3 | from mesh.generic.slipMsg import SLIP_END 4 | from mesh.generic.cmds import FPGACmds 5 | import crcmod.predefined 6 | 7 | class FPGARadio(Radio): 8 | 9 | def __init__(self, serial, config): 10 | Radio.__init__(self, serial, config) 11 | 12 | self.crc16 = crcmod.predefined.mkCrcFun('crc16') 13 | 14 | def sendMsg(self, msgBytes): 15 | """Package message to send to FPGA.""" 16 | #print("outgoing message:", SLIP_END + struct.pack('=BH',FPGACmds['FPGAMsgStart'], len(msgBytes)) + msgBytes + struct.pack("H", self.crc16(msgBytes))) 17 | self.sendBytes(SLIP_END + struct.pack('=BH',FPGACmds['FPGAMsgStart'], len(msgBytes)) + msgBytes + struct.pack("H", self.crc16(msgBytes))) 18 | 19 | -------------------------------------------------------------------------------- /python/mesh/generic/gndCmdDict.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.cmds import GndCmds 2 | from mesh.generic.commandType import CommandType 3 | from struct import pack 4 | from mesh.generic.nodeHeader import headers 5 | 6 | # Serialize methods 7 | 8 | def serialize_GndCmds_TimeOffsetSummary(cmdData, timestamp): 9 | nodeStatus = cmdData['nodeStatus'] 10 | 11 | # Assemble message 12 | msg = pack(GndCmdDict[GndCmds['TimeOffsetSummary']].packFormat, len(nodeStatus)) 13 | packFormat = GndCmdDict['TimeOffsetSummaryContents'].packFormat 14 | for status in nodeStatus: 15 | msg += pack(packFormat, int(status.timeOffset*100)) 16 | 17 | return msg 18 | 19 | def serialize_GndCmds_LinkStatusSummary(cmdData, timestamp): 20 | linkStatus = cmdData['linkStatus'] 21 | 22 | # Assemble message 23 | msg = bytearray() 24 | for i in range(len(linkStatus)): 25 | for j in range(len(linkStatus[i])): 26 | msg += pack('=' + GndCmdDict['LinkStatusSummaryContents'].packFormat, int(linkStatus[i][j])) 27 | 28 | return msg 29 | 30 | GndCmdDict = {GndCmds['TimeOffsetSummary']: CommandType('=B', serialize_GndCmds_TimeOffsetSummary, ['numNodes'], header='MinimalHeader'), \ 31 | 'TimeOffsetSummaryContents': CommandType('=H', [], ['offset'], None), \ 32 | GndCmds['LinkStatusSummary']: CommandType('', serialize_GndCmds_LinkStatusSummary, [], header='MinimalHeader'), \ 33 | 'LinkStatusSummaryContents': CommandType('B', [], ['linkStatus'], None)} 34 | -------------------------------------------------------------------------------- /python/mesh/generic/gpio.py: -------------------------------------------------------------------------------- 1 | import globalCfg 2 | if (globalCfg.platform == "bbb"): 3 | import Adafruit_BBIO.GPIO as GPIO 4 | 5 | # GPIO wrapper 6 | def setup(pin, direction): 7 | if (globalCfg.platform == "bbb"): 8 | if (direction == "in"): 9 | GPIO.setup(pin, GPIO.IN) 10 | elif (direction == "out"): 11 | GPIO.setup(pin, GPIO.OUT) 12 | else: # invalid direction provided 13 | return -1 14 | 15 | return 0 16 | else: 17 | return -1 18 | def output(pin, value): 19 | if (globalCfg.platform == "bbb"): 20 | if (value == "low"): 21 | GPIO.output(pin, GPIO.LOW) 22 | elif (value == "high"): 23 | GPIO.output(pin, GPIO.HIGH) 24 | else: # invalid value 25 | return -1 26 | 27 | return 0 28 | else: 29 | return -1 30 | 31 | def input(pin): 32 | if (globalCfg.platform == "bbb"): 33 | return GPIO.input(pin) 34 | else: 35 | return -1 36 | 37 | def wait_for_edge(pin, edgeType): 38 | if (globalCfg.platform == "bbb"): 39 | if (edgeType == "rising"): 40 | GPIO.wait_for_edge(self.ppsPin, GPIO.RISING) 41 | elif (edgeType == "falling"): 42 | GPIO.wait_for_edge(self.ppsPin, GPIO.FALLING) 43 | elif (edgeType == "both"): 44 | GPIO.wait_for_edge(self.ppsPin, GPIO.BOTH) 45 | else: # invalid edge type 46 | return -1 47 | 48 | return 0 49 | 50 | else: 51 | return -1 52 | -------------------------------------------------------------------------------- /python/mesh/generic/li1RadioCmds.py: -------------------------------------------------------------------------------- 1 | 2 | # Commands with payload 3 | Li1RadioPayloadCmds = {'ReceivedData': 0x2004} 4 | 5 | # All commands 6 | Li1RadioCmds = Li1RadioPayloadCmds.copy() 7 | Li1RadioCmds.update({'Transmit': 0x1003, 'NoOp': 0x1001}) 8 | -------------------------------------------------------------------------------- /python/mesh/generic/msgParser.py: -------------------------------------------------------------------------------- 1 | 2 | class MsgParser: 3 | """This class is responsible for taking raw serial bytes and searching them for valid SLIP messages. 4 | 5 | Attributes: 6 | parsedMsgs: Valid serial messages stored in this variable upon confirmation of valid CRC. 7 | parseMsgMax: Maximum attempts at parsing messages from the raw receive buffer. 8 | """ 9 | 10 | def __init__(self, config, msg=[]): 11 | self.parsedMsgs = [] 12 | self.parseMsgMax = config['parseMsgMax'] 13 | self.msg = msg 14 | 15 | 16 | # Parsing methods 17 | def parseSerialMsg(self, msgBytes, msgStart): 18 | """Searches raw serial data for messages and then parses them using the specified message format. Valid parsed messages are then stored for processing.""" 19 | if len(msgBytes) > 0: 20 | if (self.msg): # message format specified 21 | parsedMsg = self.msg.parseMsg(msgBytes, msgStart) 22 | if (parsedMsg): # message parsed successfully 23 | self.parsedMsgs.append(parsedMsg) 24 | return self.msg.msgEnd 25 | else: # no format so store all received bytes 26 | self.parsedMsgs.append(msgBytes[msgStart:]) 27 | return len(msgBytes) 28 | 29 | def parseMsgs(self, rxBuffer): 30 | """Parse read serial data.""" 31 | msgEnd = -1 32 | for loopCtr in range(self.parseMsgMax): # Continuing looping until end of buffer reached or max loop iterations 33 | if msgEnd < len(rxBuffer): # More bytes in buffer to parse 34 | msgEnd = self.parseSerialMsg(rxBuffer, msgEnd+1) 35 | else: # end of buffer reached 36 | break 37 | 38 | # Message creation methods 39 | 40 | def encodeMsg(self, msg): 41 | if msg: # non-zero length message: 42 | if self.msg: # Package using message protocol 43 | self.msg.encodeMsg(msg) 44 | return self.msg.encoded 45 | else: # default to returning input bytes 46 | return msg 47 | else: # no message 48 | return [] 49 | 50 | -------------------------------------------------------------------------------- /python/mesh/generic/multiProcess.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def getNewBytes(conn): 4 | """Checks a pipe connection for new messages.""" 5 | # Check for new messages 6 | readAttempts = 0 7 | receivedData = bytearray() 8 | while readAttempts < 100: 9 | dataAvailable = conn.poll(0) 10 | if dataAvailable: 11 | receivedData += conn.recv_bytes() 12 | else: 13 | break 14 | readAttempts += 1 15 | 16 | return receivedData 17 | 18 | def getNewMsgs(conn): 19 | """Checks a pipe connection for new messages.""" 20 | # Check for new messages 21 | readAttempts = 0 22 | receivedData = [] 23 | while readAttempts < 100: 24 | dataAvailable = conn.poll(0) 25 | if dataAvailable: 26 | receivedData.append(conn.recv()) 27 | else: 28 | break 29 | readAttempts += 1 30 | 31 | return receivedData 32 | -------------------------------------------------------------------------------- /python/mesh/generic/navigation.py: -------------------------------------------------------------------------------- 1 | import math 2 | from switch import switch 3 | 4 | class Navigation(object): 5 | """Maintains current state data for the formation node. 6 | 7 | This is the generic class for maintaining the current state data for a formation node. 8 | A derived class should be implemented for data and behavior for specific node types. 9 | 10 | Attributes: 11 | state: The current state vector for this vehicle. 12 | timestamp: The timestamp for the stored state vector. 13 | """ 14 | 15 | def __init__(self): 16 | self.state = [] 17 | self.timestamp = 1 18 | 19 | def update(self, state=[], time=[]): 20 | """Processes and stores state updates.""" 21 | 22 | # Update current position 23 | if state: 24 | self.state = state 25 | 26 | # Update timestamp 27 | if time: 28 | self.timestamp = time 29 | 30 | 31 | def convertLatLonAlt(inputData, conversion='int', precision=[10000000, 100]): 32 | """Converts latitude, longitude, and altitude for transmission over serial and back.""" 33 | 34 | if conversion == 'int': 35 | lat = int(inputData[0]*precision[0]) 36 | lon = int(inputData[1]*precision[0]) 37 | alt = int(inputData[2]*precision[1]) 38 | elif conversion == 'float': 39 | lat = inputData[0]/float(precision[0]) 40 | lon = inputData[1]/float(precision[0]) 41 | alt = inputData[2]/float(precision[1]) 42 | else: 43 | return None 44 | 45 | return [lat, lon, alt] 46 | 47 | 48 | -------------------------------------------------------------------------------- /python/mesh/generic/nodeHeader.py: -------------------------------------------------------------------------------- 1 | from struct import pack 2 | 3 | headers = {'NodeHeader': {'format': '=BBH', 'entries': ['cmdId', 'sourceId', 'cmdCounter']}, \ 4 | 'MinimalHeader': {'format': '=B', 'entries': ['cmdId']}, \ 5 | 'SourceHeader': {'format': '=BB', 'entries': ['cmdId', 'sourceId']}} 6 | 7 | def createHeader(headerIn=[]): 8 | if not headerIn or isinstance(headerIn, list) == False: 9 | # Invalid input 10 | return [] 11 | header = [] 12 | header = dict() 13 | 14 | # Check for valid header type 15 | if headerIn[0] not in headers: 16 | # Invalid header type 17 | return [] 18 | header['type'] = headerIn[0] 19 | 20 | if len(headerIn) == 2: # header contents provided so parse header 21 | headerData = headerIn[1] 22 | header['header'] = dict() 23 | for i in range(len(headers[header['type']]['entries'])): 24 | header['header'][headers[header['type']]['entries'][i]] = headerData[i] 25 | 26 | #if header['type'] == 'NodeHeader': 27 | # header.update({'header': {'cmdId': headerData[0], 'sourceId': headerData[1], 'cmdCounter': headerData[2]}}) 28 | #elif header['type'] == 'SourceHeader': 29 | # header.update({'header': {'cmdId': headerData[0], 'sourceId': headerData[1]}}) 30 | #elif header['type'] == 'MinimalHeader': 31 | # header.update({'header': {'cmdId': headerData[0]}}) 32 | return header 33 | 34 | def packHeader(header): 35 | if header['type'] in headers: # Pack header 36 | return pack(headers[header['type']]['format'], *[header['header'][entry] for entry in headers[header['type']]['entries']]) 37 | else: # No header defined 38 | return None 39 | 40 | 41 | -------------------------------------------------------------------------------- /python/mesh/generic/nodeState.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum 2 | 3 | class NodeState(object): 4 | """The NodeState is a container class for storing the state and status data from other nodes in the formation. 5 | 6 | Attributes: 7 | id: Node id of the node whose status is stored in this instance 8 | present: Boolean flag showing whether this node is currently present in the formation. Defaults to false and is set true upon first communication received from the node. 9 | updating: Boolean flag showing whether this node is currently reporting current state data. 10 | flightMode: Current flight computer mode of this node. 11 | formationMode: Current formation mode reported by this node. 12 | state: Current state data of this node. 13 | timestamp: Timestamp of the current state data. 14 | numMsgsReceived: Cumulative total number of messages received from this node. 15 | lastStateUpdateTime: Time that last state update was received. 16 | lastMsgRcvdTime: Time that last message was received. 17 | status: Status byte for storing status information about the node. 18 | """ 19 | 20 | 21 | 22 | def __init__(self, nodeId): 23 | self.id = nodeId 24 | self.present = False 25 | self.updating = False 26 | self.timeOffset = 127 27 | self.lastMsgRcvdTime = 0.0 28 | self.lastStateUpdateTime = 0.0 29 | self.status = 0 30 | self.restartConfirmed = False 31 | 32 | class LinkStatus(IntEnum): 33 | """Enumeration of mesh link status. 34 | 35 | Attributes: 36 | NoLink: No direct communication with this node ever. 37 | Present: Previous direct communication with this node. 38 | GoodLink: Currently good link to this node. 39 | BadLink: Currently no link to this node. 40 | """ 41 | NoLink = 0 42 | IndirectLink = 2 43 | GoodLink = 1 44 | BadLink = 3 45 | 46 | -------------------------------------------------------------------------------- /python/mesh/generic/nodeTools.py: -------------------------------------------------------------------------------- 1 | import subprocess, os 2 | 3 | def isBeaglebone(): 4 | # Check if running on Windows (therefore not a BBB) 5 | if os.name == 'nt': # Windows 6 | return False 7 | # Check if running on beaglebone 8 | proc = subprocess.Popen(['lscpu'], stdout=subprocess.PIPE) 9 | output = proc.stdout.read().decode('utf-8').split('\n') 10 | for line in output: # Look for cpu architecture 11 | if "Architecture" in line: 12 | cpuType = line.split()[-1] 13 | if 'arm' in cpuType.lower(): # is a BBB 14 | return True 15 | else: 16 | return False 17 | -------------------------------------------------------------------------------- /python/mesh/generic/pipeConn.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.multiProcess import getNewBytes 2 | import time 3 | 4 | class PipeConn(object): 5 | """Wrapper class to make pipe connection act like serial link.""" 6 | def __init__(self, conn): 7 | self.conn = conn 8 | 9 | def read(self, numBytesToRead): 10 | """Reads from pipe connection.""" 11 | serMsgs = getNewBytes(self.conn) 12 | 13 | return serMsgs 14 | 15 | def write(self, msg): 16 | """Writes to pipe connection.""" 17 | if msg: 18 | self.conn.send(msg) 19 | -------------------------------------------------------------------------------- /python/mesh/generic/tdmaState.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum, Enum 2 | 3 | class TDMAMode(IntEnum): 4 | sleep = 0 5 | init = 1 6 | receive = 2 7 | transmit = 3 8 | failsafe = 4 9 | admin = 7 10 | 11 | class TDMABlockTxStatus(Enum): 12 | false = 0 13 | pending = 1 14 | confirmed = 2 15 | active = 3 16 | 17 | class TDMAStatus(IntEnum): 18 | nominal = 1 19 | blockTx = 2 20 | -------------------------------------------------------------------------------- /python/mesh/generic/testCmdDict.py: -------------------------------------------------------------------------------- 1 | from struct import pack 2 | from mesh.generic.commandType import CommandType 3 | from mesh.generic.cmds import TestCmds 4 | 5 | # Serialize methods 6 | def serialize_TestCmds_SendDataBlock(cmdData, timestamp): 7 | """Method for serializing TestCmds['SendDataBlock'] command for serial transmission.""" 8 | return pack(TestCmdDict[TestCmds['SendDataBlock']].packFormat, cmdData['destId']) 9 | 10 | TestCmdDict = {TestCmds['SendDataBlock']: CommandType('=B', serialize_TestCmds_SendDataBlock, ['destId'], header='NodeHeader')} 11 | -------------------------------------------------------------------------------- /python/mesh/generic/testCmdProcessor.py: -------------------------------------------------------------------------------- 1 | from switch import switch 2 | from mesh.generic.deserialize import deserialize 3 | from mesh.generic.cmds import TestCmds 4 | from mesh.generic.cmdProcessor import checkCmdCounter 5 | 6 | # Processor method 7 | def processMsg(self, cmdId, msg, args): 8 | nodeStatus = args['nodeStatus'] 9 | comm = args['comm'] 10 | 11 | if len(msg) > 0: 12 | # Parse command header 13 | header = deserialize(msg, cmdId, 'header') 14 | if header != None: 15 | # Check for command counter 16 | cmdStatus = checkCmdCounter(self, header, msg, comm) 17 | if cmdStatus == False: # old command counter 18 | return 19 | 20 | # Parse message contents 21 | try: 22 | msgContents = deserialize(msg, cmdId, 'body') 23 | if msgContents == None: 24 | return 25 | except KeyError: 26 | print("Invalid command ID.") 27 | return 28 | 29 | # Process message by command id 30 | for case in switch(cmdId): 31 | if case(TestCmds['SendDataBlock']): 32 | if header['sourceId'] == 0: # message from GCS (node 0) 33 | if msgContents['destId'] == self.nodeParams.config.nodeId: # command is for this node 34 | print("Send Block Data command received") 35 | comm.sendDataBlock(b'1234567890'*100) # start block transfer process 36 | break 37 | 38 | # Test command processor 39 | TestCmdProcessor = {'cmdList': TestCmds, 'msgProcessor': processMsg} 40 | -------------------------------------------------------------------------------- /python/mesh/generic/timeLib.py: -------------------------------------------------------------------------------- 1 | import subprocess, time, sys, threading 2 | 3 | def getTimeOffset(offsetType='standard'): 4 | if offsetType == None: # no offset calculation 5 | return 0.0 # default to no offset 6 | elif offsetType == 'ntp-pps': 7 | # Parse ntpq -p command 8 | try: 9 | proc = subprocess.Popen(['ntpq', '-p'], stdout=subprocess.PIPE) 10 | output = proc.stdout.read().decode('utf-8').split('\n') 11 | except: 12 | return None 13 | 14 | offset = None 15 | for line in output: 16 | if "PPS" in line: 17 | ppsStatus = line.split() 18 | if ppsStatus[4].isdigit(): # last update value is only digits so is seconds 19 | if int(ppsStatus[4]) < 32: # last update less than 2 poll cycles old 20 | offset = abs(float(ppsStatus[8])) 21 | elif ppsStatus[4] == '-': # could be 0 or no response - check if good reach 22 | if ppsStatus[6].isdigit() and int(ppsStatus[6]) > 177: # no more than 1 missed in last 8 polls 23 | offset = abs(float(ppsStatus[8])) 24 | break 25 | 26 | return offset 27 | 28 | elif offsetType == 'ntp': 29 | # Parse ntpq -crv command 30 | proc = subprocess.Popen(['ntpq', '-crv'], stdout=subprocess.PIPE) 31 | output = proc.stdout.read() 32 | 33 | ntpStatus = str(output).replace(' ', '').split(',') # remove whitespace and split string 34 | serverSynched = False 35 | offset = None 36 | for entry in ntpStatus: 37 | if entry == 'sync_pps': # PPS sync 38 | serverSynched = True 39 | elif serverSynched and entry[0:6] == 'offset': # time offset 40 | offset = abs(float(entry[7:])) 41 | #print("Offset:", str(offset)) 42 | return serverSynched, offset 43 | 44 | return None 45 | 46 | -------------------------------------------------------------------------------- /python/mesh/generic/udpRadio.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from mesh.generic.radio import Radio 3 | from mesh.generic.customExceptions import NoSocket 4 | 5 | class UDPRadio(Radio): 6 | 7 | def __init__(self, config): 8 | Radio.__init__(self, [], config) 9 | 10 | # Read port 11 | self.sockRead = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 12 | self.sockRead.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 13 | self.sockRead.bind((config['ipAddr'], config['readPort'])) 14 | self.sockRead.setblocking(0) # non-blocking to prevent hanging thread 15 | 16 | # Write port 17 | self.sockWrite = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 18 | self.sockWrite.setblocking(0) 19 | self.sockWriteIp = config['ipAddr'] 20 | self.sockWritePort = config['writePort'] 21 | 22 | def readBytes(self, bufferFlag): 23 | """Reads raw bytes from udp connection""" 24 | if not self.sockRead: 25 | raise NoSocket("No read socket connection available") 26 | return 0 27 | 28 | # Read from socket 29 | newBytes = [] 30 | try: 31 | readAttempts = 0 32 | newBytes = bytearray() 33 | while readAttempts < 10: # Check for multiple messages 34 | newData, source = self.sockRead.recvfrom(4096) 35 | newBytes = newBytes + newData 36 | readAttempts = readAttempts + 1 37 | 38 | except Exception as e: 39 | pass 40 | #print("UDP socket read error.") 41 | 42 | # Process rx bytes 43 | if newBytes: 44 | self.processRxBytes(newBytes, bufferFlag) 45 | return len(newBytes) 46 | else: 47 | return 0 48 | 49 | 50 | def sendBytes(self, msgBytes): 51 | """Send bytes over udp connection.""" 52 | if not self.sockWrite: 53 | raise NoSocket("No write socket connection available") 54 | return 0 55 | 56 | try: 57 | self.sockWrite.sendto(msgBytes, (self.sockWriteIp, self.sockWritePort)) 58 | return len(msgBytes) 59 | except Exception as e: 60 | return 0 61 | #print(e) 62 | #print("UDP socket write error.") 63 | -------------------------------------------------------------------------------- /python/mesh/generic/utilities.py: -------------------------------------------------------------------------------- 1 | import struct 2 | 3 | def packData(data, length, endianness='little'): 4 | packFormat = '' 5 | 6 | # Determine endianness for packing 7 | if (endianness == 'little'): 8 | packFormat += '<' 9 | else: 10 | packFormat += '>' 11 | 12 | # Pack provided data 13 | try: 14 | if (length == 1): 15 | return struct.pack(packFormat + 'B', data) 16 | elif (length == 2): 17 | return struct.pack(packFormat + 'H', data) 18 | elif (length == 4): 19 | return struct.pack(packFormat + 'I', data) 20 | elif (length == 8): 21 | return struct.pack(packFormat + 'Q', data) 22 | except Exception as e: 23 | raise e 24 | 25 | def unpackData(data, length, endianness='little'): 26 | packFormat = '' 27 | 28 | # Determine endianness for unpacking 29 | if (endianness == 'little'): 30 | packFormat += '<' 31 | else: 32 | packFormat += '>' 33 | 34 | # Pack provided data 35 | try: 36 | if (length == 1): 37 | return struct.unpack(packFormat + 'B', data)[0] 38 | elif (length == 2): 39 | return struct.unpack(packFormat + 'H', data)[0] 40 | elif (length == 4): 41 | return struct.unpack(packFormat + 'I', data)[0] 42 | elif (length == 8): 43 | return struct.unpack(packFormat + 'Q', data)[0] 44 | except Exception as e: 45 | raise e 46 | 47 | def truncateFloat(floatIn, numDigits): 48 | formatStr = '%.' + str(numDigits) + 'f' 49 | return float(formatStr%(floatIn)) 50 | 51 | -------------------------------------------------------------------------------- /python/mesh/generic/xbeeRadio.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.radio import Radio, RadioMode 2 | import mesh.generic.gpio as GPIO 3 | 4 | class XbeeRadio(Radio): 5 | def __init__(self, serial, config, sleepPin = []): 6 | Radio.__init__(self, serial, config) 7 | self.sleepPin = sleepPin 8 | # Setup sleep pin 9 | if self.sleepPin: 10 | GPIO.setup(self.sleepPin, "out") 11 | self.setOff() # default to off mode 12 | pass 13 | 14 | def setSleep(self): 15 | if self.sleepPin: 16 | GPIO.output(self.sleepPin, "high") 17 | self.mode = RadioMode.sleep 18 | 19 | def setOff(self): 20 | self.setSleep() 21 | self.mode = RadioMode.off 22 | 23 | def setReceive(self): 24 | self.wake() 25 | self.mode = RadioMode.receive 26 | 27 | def setTransmit(self): 28 | self.wake() 29 | self.mode = RadioMode.transmit 30 | 31 | def wake(self): 32 | if self.sleepPin: 33 | GPIO.output(self.sleepPin, "low") 34 | -------------------------------------------------------------------------------- /python/mesh/interface/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nasa/meshNetwork/ff4bd66e0ca6bd424fd8897a97252bb3925d8b3c/python/mesh/interface/__init__.py -------------------------------------------------------------------------------- /python/nodeConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "node": { 3 | "nodeId": 2, 4 | "maxNumNodes": 6, 5 | "platform": "generic", 6 | "nodeUpdateTimeout": 5.0, 7 | "FCCommWriteInterval": 0.2, 8 | "FCCommDevice": "", 9 | "FCBaudrate": 57600, 10 | "cmdInterval": 0.2, 11 | "logInterval": 0.05, 12 | "commType": "TDMA", 13 | "numMeshNetworks": 1, 14 | "meshDevices": ["/dev/ttyUSB0"], 15 | "radios": ["Xbee"], 16 | "msgParsers": ["HDLC"], 17 | "meshBaudrate": 57600, 18 | "parseMsgMax": 50, 19 | "rxBufferSize": 2000, 20 | "gcsPresent": true 21 | }, 22 | 23 | "interface": { 24 | "nodeCommIntIP": "127.0.0.1", 25 | "commRdPort": 30000, 26 | "commWrPort": 30001 27 | }, 28 | 29 | "tdmaConfig": { 30 | "sleepPin": "P8_12", 31 | "enableLength": 0.005, 32 | "slotGuardLength": 0.005, 33 | "preTxGuardLength": 0.005, 34 | "postTxGuardLength": 0.005, 35 | "txLength": 0.100, 36 | "rxDelay": 0.0, 37 | "initTimeToWait": 60.0, 38 | "maxNumSlots": 6, 39 | "desiredDataRate": 1.0, 40 | "initSyncBound": 1, 41 | "operateSyncBound": 2, 42 | "offsetTimeout": 60.0, 43 | "offsetTxInterval": 10.0, 44 | "statusTxInterval": 10.0, 45 | "linksTxInterval": 30.0, 46 | "linkTimeout": 60.0, 47 | "adminBytesMaxLength": 100, 48 | "msgPayloadMaxLength": 500, 49 | "blockTxMaxLength": 50, 50 | "blockTxReceiptTimeout": 3, 51 | "blockTxPacketRetry": 1, 52 | "blockTxEndMult": 1.5, 53 | "fpga": false, 54 | "fpgaFailsafePin": "P8_16", 55 | "fpgaFifoSize": 512, 56 | "enablePin": "P8_15", 57 | "statusPin": "P8_18", 58 | "recvAllMsgs": true, 59 | "adminEnable": true, 60 | "adminLength": 100, 61 | "restartDelay": 3, 62 | "pollTimeout": 60 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /python/switch.py: -------------------------------------------------------------------------------- 1 | class switch(object): 2 | def __init__(self, value): 3 | self.value = value 4 | self.fall = False 5 | 6 | def __iter__(self): 7 | """Return the match method once, then stop""" 8 | yield self.match 9 | return 10 | #raise StopIteration 11 | 12 | def match(self, *args): 13 | """Indicate whether or not to enter a case suite""" 14 | if self.fall or not args: 15 | return True 16 | elif self.value in args: # changed for v1.5, see below 17 | self.fall = True 18 | return True 19 | else: 20 | return False 21 | -------------------------------------------------------------------------------- /python/unittests/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /python/unittests/executeTests.py: -------------------------------------------------------------------------------- 1 | import sys, pytest 2 | sys.path.append('../') 3 | 4 | # Execute requested test 5 | if len(sys.argv) > 1: 6 | pytest.main([sys.argv[1]]) 7 | else: 8 | pytest.main() 9 | -------------------------------------------------------------------------------- /python/unittests/generic/test_commandMsg.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.commandMsg import CommandMsg 2 | from mesh.generic.cmds import NodeCmds 3 | from mesh.generic.cmdDict import CmdDict 4 | 5 | class TestCommandMsg: 6 | 7 | def setup_method(self, method): 8 | pass 9 | 10 | def test_parseCommand(self): 11 | """Test parsing command message contents.""" 12 | # Test parsing message based on cmdId 13 | cmdId = NodeCmds['GCSCmd'] # test command 14 | cmdData = [5, 3] 15 | msg = CommandMsg(cmdId, cmdData) 16 | for i in range(len(CmdDict[cmdId].messageFormat)): 17 | entry = CmdDict[cmdId].messageFormat[i] 18 | assert(entry in msg.cmdData) 19 | assert(msg.cmdData[entry] == cmdData[i]) 20 | 21 | # Test creating message parsing without cmdId 22 | msg = CommandMsg(cmdData=cmdData) 23 | assert(msg.cmdData == cmdData) 24 | -------------------------------------------------------------------------------- /python/unittests/generic/test_formationClock.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.formationClock import FormationClock 2 | import time 3 | 4 | class TestFormationClock: 5 | 6 | 7 | def setup_method(self, method): 8 | 9 | # Create FormationClock instance 10 | 11 | if method.__name__ == "test_referenceClock": 12 | self.clock = FormationClock(time.time()) 13 | else: 14 | self.clock = FormationClock() 15 | 16 | def test_nonreferenceClock(self): 17 | """Test non-referenced clock functionality.""" 18 | startTime = time.time() 19 | clockTime = self.clock.getTime() 20 | endTime = time.time() 21 | assert(clockTime >= startTime and clockTime <= endTime) # Check that returned time is correct 22 | 23 | def test_referenceClock(self): 24 | """Test referenced clock functionality.""" 25 | assert(self.clock.getTime() <= time.time() - self.clock.referenceTime) 26 | 27 | def test_getOffset(self): 28 | """Test time offset functionality.""" 29 | # Test zero offset returned when no time source 30 | self.clock.timeSource = None 31 | offset = self.clock.getOffset() 32 | assert(abs(offset) < 0.00001) 33 | 34 | -------------------------------------------------------------------------------- /python/unittests/generic/test_gndCmdProcessor.py: -------------------------------------------------------------------------------- 1 | from struct import calcsize 2 | from mesh.generic.gndCmdProcessor import GndCmdProcessor 3 | from mesh.generic.cmds import GndCmds 4 | from mesh.generic.command import Command 5 | from mesh.generic.cmdDict import CmdDict 6 | from mesh.generic.nodeParams import NodeParams 7 | from mesh.generic.nodeState import NodeState 8 | from mesh.generic.nodeHeader import packHeader, headers 9 | from mesh.generic.radio import Radio 10 | from mesh.generic.serialComm import SerialComm 11 | from unittests.testCmds import testCmds 12 | from unittests.testConfig import configFilePath 13 | 14 | cmdsToTest = [GndCmds['TimeOffsetSummary'], GndCmds['LinkStatusSummary']] 15 | 16 | class TestGndCmdProcessor: 17 | 18 | def setup_method(self, method): 19 | self.nodeStatus = [NodeState(i+1) for i in range(5)] 20 | self.nodeParams = NodeParams(configFile=configFilePath) 21 | radio = Radio([], {'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000}) 22 | self.comm = SerialComm([GndCmdProcessor], self.nodeParams, radio, []) 23 | 24 | def test_processMsg(self): 25 | """Test processMsg method of GndCmdProcessor.""" 26 | 27 | # Test processing of all GndCmds 28 | for cmdId in cmdsToTest: 29 | self.comm.processMsg(testCmds[cmdId].serialize(), args = {'nodeStatus': self.nodeStatus, 'comm': self.comm, 'clock': self.nodeParams.clock}) 30 | if cmdId == GndCmds['TimeOffsetSummary']: 31 | for i in range(len(testCmds[cmdId].cmdData['nodeStatus'])): 32 | assert(self.nodeStatus[i].timeOffset == testCmds[cmdId].cmdData['nodeStatus'][i].timeOffset) # offset pulled from summary message and stored 33 | elif cmdId == GndCmds['LinkStatusSummary']: 34 | msgNodeId = testCmds[cmdId].cmdData['nodeId'] 35 | for i in range(0, self.nodeParams.config.maxNumNodes): 36 | for j in range(0, self.nodeParams.config.maxNumNodes): 37 | assert(self.nodeParams.linkStatus[i][i] == testCmds[cmdId].cmdData['linkStatus'][i][j]) 38 | -------------------------------------------------------------------------------- /python/unittests/generic/test_hdlcMsgParser.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.msgParser import MsgParser 2 | from mesh.generic.hdlcMsg import HDLCMsg 3 | from test_HDLCMsg import truthHDLCMsg, testMsg 4 | from mesh.generic.utilities import packData 5 | 6 | class TestHDLCMsgParser: 7 | 8 | def setup_method(self, method): 9 | # Create HDLCMsgParser instance 10 | self.msgParser = MsgParser({'parseMsgMax': 10}, HDLCMsg(256)) 11 | 12 | def test_parseSerialMsg(self): 13 | """Test parseSerialMessage method of HDLCMsgParser.""" 14 | # Check rejection of message with invalid CRC 15 | self.msgParser.parseSerialMsg(truthHDLCMsg, 0) 16 | assert(self.msgParser.msg.msgFound == True) # hdlc msg found 17 | assert(self.msgParser.msg.msgEnd != 1) # message end found 18 | assert(self.msgParser.parsedMsgs == []) # message rejected 19 | 20 | # Check acceptance of message with valid CRC 21 | crc = self.msgParser.msg.crc(testMsg) 22 | hdlcMsg = HDLCMsg(256) 23 | hdlcMsg.encodeMsg(testMsg) 24 | self.msgParser.parseSerialMsg(hdlcMsg.encoded, 0) 25 | assert(self.msgParser.msg.msgFound == True) # hdlc msg found 26 | assert(self.msgParser.msg.msgEnd != 1) # message end found 27 | assert(self.msgParser.parsedMsgs[0] == testMsg) # message accepted 28 | 29 | # Check that proper message end position is returned 30 | self.msgParser.parsedMsgs = [] 31 | paddedMsg = hdlcMsg.encoded + b'989898' 32 | msgEnd = self.msgParser.parseSerialMsg(paddedMsg, 0) 33 | assert(self.msgParser.parsedMsgs[0] == testMsg) 34 | assert(msgEnd == len(hdlcMsg.encoded)-1) 35 | 36 | def test_encodeMsg(self): 37 | """Test encodeMsg method of HDLCMsgParser.""" 38 | hdlcMsg = HDLCMsg(256) 39 | hdlcMsg.encodeMsg(testMsg) 40 | encodedMsg = self.msgParser.encodeMsg(testMsg) 41 | assert(encodedMsg == hdlcMsg.encoded) 42 | -------------------------------------------------------------------------------- /python/unittests/generic/test_msgParser.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.msgParser import MsgParser 2 | from struct import pack 3 | 4 | class TestMsgParser: 5 | 6 | def setup_method(self, method): 7 | # Create SerialMsgParser instance 8 | self.msgParser = MsgParser({'parseMsgMax': 10}) 9 | 10 | def test_parseSerialMsg(self): 11 | """Test parseSerialMsg method of MsgParser.""" 12 | msg = b'12345' 13 | msgStart = 1 14 | self.msgParser.parseSerialMsg(msg, msgStart) 15 | assert(len(self.msgParser.parsedMsgs) == 1) 16 | assert(self.msgParser.parsedMsgs[0] == msg[msgStart:]) 17 | 18 | def test_encodeMsg(self): 19 | """Test encode passthrough of message.""" 20 | msg = b'12345' 21 | assert(self.msgParser.encodeMsg(msg) == msg) 22 | 23 | def test_parseMsgs(self): 24 | """Test parseMsgs method of MsgParser.""" 25 | msg = b'12345' 26 | msg = b'12345' 27 | msg2 = b'6789' 28 | self.msgParser.parseMsgs(msg) 29 | self.msgParser.parseMsgs(msg2) 30 | assert(len(self.msgParser.parsedMsgs) == 2) 31 | assert(self.msgParser.parsedMsgs[0] == msg) 32 | assert(self.msgParser.parsedMsgs[1] == msg2) 33 | 34 | -------------------------------------------------------------------------------- /python/unittests/generic/test_navigation.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.navigation import convertLatLonAlt, Navigation 2 | 3 | class TestNavigation: 4 | 5 | def setup_method(self, method): 6 | self.navigation = Navigation() 7 | 8 | def test_update(self): 9 | """Test update method of Navigation class.""" 10 | ## Set state using update method and confirm change 11 | state = [123.456, 999.888, 100.200] 12 | time = 505.3 13 | 14 | # Pre-update check 15 | assert(self.navigation.state != state) 16 | assert(self.navigation.timestamp != time) 17 | 18 | self.navigation.update(state, time) 19 | 20 | # Post-update check 21 | assert(self.navigation.state == state) 22 | assert(self.navigation.timestamp == time) 23 | 24 | 25 | def test_convertLatLonAlt(self): 26 | """Test conversion of latitude, longitude, and and altitude.""" 27 | lla = [34.987654321, -85.123456789, 20.5678] 28 | precision = [10000, 10000, 10] 29 | 30 | # Test default conversion to int 31 | convertedLLA = convertLatLonAlt(lla) 32 | self.checkConvertedLLA(convertedLLA, lla, 'int') 33 | 34 | # Test default conversion to float 35 | floatLLA = convertLatLonAlt(convertedLLA, 'float') 36 | self.checkConvertedLLA(floatLLA, convertedLLA, 'float') 37 | 38 | # Test conversion with provided precision 39 | convertedLLA = convertLatLonAlt(lla, precision=precision) 40 | self.checkConvertedLLA(convertedLLA, lla, 'int', precision) 41 | floatLLA = convertLatLonAlt(convertedLLA, 'float', precision) 42 | self.checkConvertedLLA(floatLLA, convertedLLA, 'float', precision) 43 | 44 | def checkConvertedLLA(self, convertedLLA, truthLLA, conversion, precision=[10000000,100]): 45 | for i in range(len(truthLLA)): 46 | if i < 2: 47 | prec = precision[0] 48 | else: 49 | prec = precision[1] 50 | if conversion == 'int': 51 | assert(convertedLLA[i] == int(truthLLA[i]*prec)) 52 | else: # float 53 | assert(convertedLLA[i] == truthLLA[i]/float(prec)) 54 | 55 | -------------------------------------------------------------------------------- /python/unittests/generic/test_nodeHeader.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.nodeHeader import createHeader, packHeader, headers 2 | from struct import pack 3 | 4 | class TestNodeHeader: 5 | 6 | 7 | def setup_method(self, method): 8 | self.nodeHeaderIn = ['NodeHeader', [3, 4, 5]] 9 | self.minimalHeaderIn = ['MinimalHeader', [3]] 10 | self.sourceHeaderIn = ['SourceHeader', [3, 4]] 11 | pass 12 | 13 | 14 | def test_createHeader(self): 15 | """Test creation of all header types.""" 16 | # NodeHeader 17 | header = createHeader(self.nodeHeaderIn) 18 | self.checkHeaderContents(header, self.nodeHeaderIn) 19 | 20 | # MinimalHeader 21 | header = createHeader(self.minimalHeaderIn) 22 | self.checkHeaderContents(header, self.minimalHeaderIn) 23 | 24 | # SourceHeader 25 | header = createHeader(self.sourceHeaderIn) 26 | self.checkHeaderContents(header, self.sourceHeaderIn) 27 | 28 | def test_packHeader(self): 29 | """Test packing of all defined header types.""" 30 | # NodeHeader 31 | nodeHeader = createHeader(self.nodeHeaderIn) 32 | packedHeader = pack(headers[self.nodeHeaderIn[0]]['format'], *self.nodeHeaderIn[1]) 33 | assert(packHeader(nodeHeader) == packedHeader) 34 | 35 | # MinimalHeader 36 | minimalHeader = createHeader(self.minimalHeaderIn) 37 | packedHeader = pack(headers[self.minimalHeaderIn[0]]['format'], *self.minimalHeaderIn[1]) 38 | assert(packHeader(minimalHeader) == packedHeader) 39 | 40 | # SourceHeader 41 | sourceHeader = createHeader(self.sourceHeaderIn) 42 | packedHeader = pack(headers[self.sourceHeaderIn[0]]['format'], *self.sourceHeaderIn[1]) 43 | assert(packHeader(sourceHeader) == packedHeader) 44 | 45 | def checkHeaderContents(self, header, headerIn): 46 | headerType = headerIn[0] 47 | assert(header['type'] == headerType) 48 | assert(len(header['header']) == len(headerIn[1])) 49 | for i in range(len(headers[headerType]['entries'])): 50 | assert(header['header'][headers[headerType]['entries'][i]] == headerIn[1][i]) 51 | 52 | 53 | -------------------------------------------------------------------------------- /python/unittests/generic/test_slipMsgParser.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.msgParser import MsgParser 2 | from mesh.generic.slipMsg import SLIPMsg 3 | from test_SLIPMsg import truthSLIPMsg, testMsg 4 | from mesh.generic.utilities import packData 5 | 6 | class TestSLIPMsgParser: 7 | 8 | def setup_method(self, method): 9 | # Create SLIPMsgParser instance 10 | self.msgParser = MsgParser({'parseMsgMax': 10}, SLIPMsg(256)) 11 | 12 | def test_parseSerialMsg(self): 13 | """Test parseSerialMessage method of SLIPMsgParser.""" 14 | # Check rejection of message with invalid CRC 15 | self.msgParser.parseSerialMsg(truthSLIPMsg, 0) 16 | assert(self.msgParser.msg.msgFound == True) # slip msg found 17 | assert(self.msgParser.msg.msgEnd != 1) # message end found 18 | assert(self.msgParser.parsedMsgs == []) # message rejected 19 | 20 | # Check acceptance of message with valid CRC 21 | crc = self.msgParser.msg.crc(testMsg) 22 | slipMsg = SLIPMsg(256) 23 | slipMsg.encodeMsg(testMsg) 24 | self.msgParser.parseSerialMsg(slipMsg.encoded, 0) 25 | assert(self.msgParser.msg.msgFound == True) # slip msg found 26 | assert(self.msgParser.msg.msgEnd != 1) # message end found 27 | assert(self.msgParser.parsedMsgs[0] == testMsg) # message accepted 28 | 29 | # Check that proper message end position is returned 30 | self.msgParser.parsedMsgs = [] 31 | paddedMsg = slipMsg.encoded + b'989898' 32 | msgEnd = self.msgParser.parseSerialMsg(paddedMsg, 0) 33 | assert(self.msgParser.parsedMsgs[0] == testMsg) 34 | assert(msgEnd == len(slipMsg.encoded)-1) 35 | 36 | def test_encodeMsg(self): 37 | """Test encodeMsg method of SLIPMsgParser.""" 38 | slipMsg = SLIPMsg(256) 39 | slipMsg.encodeMsg(testMsg) 40 | encodedMsg = self.msgParser.encodeMsg(testMsg) 41 | assert(encodedMsg == slipMsg.encoded) 42 | -------------------------------------------------------------------------------- /python/unittests/generic/test_tdmaTime.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.nodeTools import isBeaglebone 2 | from mesh.generic.tdmaTime import getTimeOffset 3 | import pytest 4 | from numbers import Real 5 | 6 | class TestTDMATime: 7 | pytestmark = pytest.mark.skipif(isBeaglebone() == False, reason="requires configured formation node") 8 | 9 | def setup_method(self, method): 10 | pass 11 | 12 | def test_getTimeOffset(self): 13 | """Test getTimeOffset method.""" 14 | 15 | # Test pps offset 16 | offset = getTimeOffset('pps') 17 | assert(offset == None or (isinstance(offset, Real) and offset > 0)) 18 | 19 | # Test standard offset 20 | retValue = getTimeOffset('standard') 21 | assert(isinstance(retValue, tuple)) 22 | assert(isinstance(retValue[0], bool)) 23 | assert(retValue[1] == None or (isinstance(retValue[1], Real) and retValue[1] > 0)) 24 | 25 | -------------------------------------------------------------------------------- /python/unittests/generic/test_udpRadio.py: -------------------------------------------------------------------------------- 1 | import socket, time 2 | from mesh.generic.udpRadio import UDPRadio 3 | from mesh.generic.nodeParams import NodeParams 4 | from unittests.testConfig import configFilePath 5 | from mesh.generic.customExceptions import NoSocket 6 | import pytest 7 | 8 | class TestUDPRadio: 9 | def setup_method(self, method): 10 | 11 | self.nodeParams = NodeParams(configFile=configFilePath) 12 | self.radio = UDPRadio({'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000, 'ipAddr': "127.0.0.1", 'readPort': 5000, 'writePort': 5000}) 13 | 14 | def test_readBytes(self): 15 | """Test readBytes method of Radio.""" 16 | # Write bytes and read 17 | msgBytes = b'ABC' 18 | self.radio.sockWrite.sendto(msgBytes, (self.radio.sockWriteIp, self.radio.sockWritePort)) 19 | time.sleep(0.1) 20 | self.radio.readBytes(False) 21 | assert(self.radio.bytesInRxBuffer == len(msgBytes)) 22 | serBytes = self.radio.getRxBytes() 23 | assert(serBytes == msgBytes) 24 | 25 | # Test exception raising 26 | self.radio.sockRead = [] 27 | with pytest.raises(NoSocket): 28 | self.radio.readBytes(False) 29 | 30 | def test_sendMsg(self): 31 | """Test sendMsg method of UDPRadio (using UDPRadio implementation of sendBytes).""" 32 | # Send test message 33 | testMsg = b'123456789' 34 | msgBytes = testMsg 35 | self.radio.sendMsg(testMsg) 36 | time.sleep(0.1) 37 | self.radio.readBytes(True) 38 | readBytes = self.radio.getRxBytes() 39 | assert(readBytes == msgBytes) 40 | 41 | # Test exception raising 42 | self.radio.sockWrite = [] 43 | with pytest.raises(NoSocket): 44 | self.radio.sendMsg(testMsg) 45 | 46 | -------------------------------------------------------------------------------- /python/unittests/generic/test_xbeeRadio.py: -------------------------------------------------------------------------------- 1 | from mesh.generic.nodeTools import isBeaglebone 2 | from mesh.generic.radio import RadioMode 3 | from mesh.generic.nodeParams import NodeParams 4 | from unittests.testConfig import configFilePath 5 | import pytest 6 | 7 | class TestXbeeRadio: 8 | pytestmark = pytest.mark.skipif(isBeaglebone() == False, reason="requires GPIO") 9 | 10 | def setup_method(self, method): 11 | from mesh.generic.xbeeRadio import XbeeRadio 12 | self.nodeParams = NodeParams(configFile=configFilePath) 13 | self.xbeeRadio = XbeeRadio([], {'uartNumBytesToRead': self.nodeParams.config.uartNumBytesToRead, 'rxBufferSize': 2000}, "P8_12") 14 | 15 | def test_modeChanges(self): 16 | """Test mode changes of XbeeRadio.""" 17 | import Adafruit_BBIO.GPIO as GPIO 18 | assert(self.xbeeRadio.mode == RadioMode.off) 19 | 20 | # Set mode to receive 21 | self.changeMode(RadioMode.receive) 22 | assert(GPIO.input("P8_12") == 0) 23 | 24 | # Set mode to off 25 | self.changeMode(RadioMode.off) 26 | assert(GPIO.input("P8_12") == 1) 27 | 28 | # Set mode to transmit 29 | self.changeMode(RadioMode.transmit) 30 | assert(GPIO.input("P8_12") == 0) 31 | 32 | # Set mode to sleep 33 | self.changeMode(RadioMode.sleep) 34 | assert(GPIO.input("P8_12") == 1) 35 | 36 | 37 | def changeMode(self, mode): 38 | self.xbeeRadio.setMode(mode) 39 | assert(self.xbeeRadio.mode == mode) 40 | 41 | 42 | -------------------------------------------------------------------------------- /python/unittests/nodeConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "node": { 3 | "nodeId": 2, 4 | "maxNumNodes": 6, 5 | "platform": "generic", 6 | "nodeUpdateTimeout": 5.0, 7 | "FCCommWriteInterval": 0.2, 8 | "FCCommDevice": "", 9 | "FCBaudrate": 57600, 10 | "cmdInterval": 0.2, 11 | "logInterval": 0.05, 12 | "commType": "TDMA", 13 | "numMeshNetworks": 1, 14 | "meshDevices": ["/dev/ttyUSB0"], 15 | "radios": ["Xbee"], 16 | "msgParsers": ["HDLC"], 17 | "meshBaudrate": 57600, 18 | "parseMsgMax": 50, 19 | "rxBufferSize": 2000, 20 | "gcsPresent": true 21 | }, 22 | 23 | "interface": { 24 | "nodeCommIntIP": "127.0.0.1", 25 | "commRdPort": 30000, 26 | "commWrPort": 30001 27 | }, 28 | 29 | "tdmaConfig": { 30 | "sleepPin": "P8_12", 31 | "enableLength": 0.005, 32 | "slotGuardLength": 0.005, 33 | "preTxGuardLength": 0.005, 34 | "postTxGuardLength": 0.005, 35 | "txLength": 0.100, 36 | "rxDelay": 0.0, 37 | "initTimeToWait": 5.0, 38 | "maxNumSlots": 6, 39 | "desiredDataRate": 1.0, 40 | "initSyncBound": 1, 41 | "operateSyncBound": 2, 42 | "offsetTimeout": 60.0, 43 | "offsetTxInterval": 10.0, 44 | "statusTxInterval": 0.0, 45 | "linksTxInterval": 30.0, 46 | "maxTxBlockSize": 5, 47 | "linkTimeout": 60.0, 48 | "blockTxRequestTimeout": 3, 49 | "minBlockTxDelay": 6, 50 | "fpga": false, 51 | "fpgaFailsafePin": "P8_16", 52 | "fpgaFifoSize": 512, 53 | "enablePin": "P8_15", 54 | "statusPin": "P8_18", 55 | "recvAllMsgs": true, 56 | "restartDelay": 3, 57 | "pollTimeout": 60 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /python/unittests/nodeConfig_bad.json: -------------------------------------------------------------------------------- 1 | { 2 | "node": { 3 | "nodeId": 1, 4 | "platform": "generic", 5 | "nodeUpdateTimeout": 5.0, 6 | "FCCommWriteInterval": 0.2, 7 | "FCCommDevice": "/dev/ttyO1", 8 | "FCBaudrate": 57600, 9 | "cmdInterval": 0.2, 10 | "logInterval": 0.05, 11 | "commType": "TDMA", 12 | "numMeshNetworks": 1, 13 | "meshDevices": ["/dev/ttyO4"], 14 | "radios": ["Xbee"], 15 | "msgParsers": ["SLIP"], 16 | "meshBaudrate": 57600, 17 | "parseMsgMax": 50, 18 | "rxBufferSize": 2000, 19 | "gcsPresent": true 20 | }, 21 | 22 | "interface": { 23 | "nodeCommIntIP": "127.0.0.1", 24 | "commRdPort": 30000, 25 | "commWrPort": 30001 26 | }, 27 | 28 | "tdmaConfig": { 29 | "sleepPin": "P8_12", 30 | "txBaudrate": 57600, 31 | "enableLength": 0.005, 32 | "slotGuardLength": 0.005, 33 | "preTxGuardLength": 0.005, 34 | "postTxGuardLength": 0.005, 35 | "txLength": 0.100, 36 | "rxDelay": 0.0, 37 | "initTimeToWait": 5.0, 38 | "maxNumSlots": 6, 39 | "desiredDataRate": 1.0, 40 | "initSyncBound": 1.0, 41 | "operateSyncBound": 2.0, 42 | "offsetTimeout": 60.0, 43 | "offsetTxInterval": 10.0, 44 | "statusTxInterval": 0.0, 45 | "linksTxInterval": 1.0, 46 | "maxTxBlockSize": 5, 47 | "blockTxRequestTimeout": 3, 48 | "minBlockTxDelay": 6, 49 | "fpga": false, 50 | "fpgaFailsafePin": "P8_16", 51 | "fpgaFifoSize": 512, 52 | "enablePin": "P8_15", 53 | "statusPin": "P8_18" 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /python/unittests/nodeConfig_noNodeId.json: -------------------------------------------------------------------------------- 1 | { 2 | "node": { 3 | "maxNumNodes": 6, 4 | "platform": "generic", 5 | "nodeUpdateTimeout": 5.0, 6 | "FCCommWriteInterval": 0.2, 7 | "FCCommDevice": "", 8 | "FCBaudrate": 57600, 9 | "cmdInterval": 0.2, 10 | "logInterval": 0.05, 11 | "commType": "TDMA", 12 | "numMeshNetworks": 1, 13 | "meshDevices": ["/dev/ttyUSB0"], 14 | "radios": ["Xbee"], 15 | "msgParsers": ["HDLC"], 16 | "meshBaudrate": 57600, 17 | "parseMsgMax": 50, 18 | "rxBufferSize": 2000, 19 | "gcsPresent": true 20 | }, 21 | 22 | "interface": { 23 | "nodeCommIntIP": "127.0.0.1", 24 | "commRdPort": 30000, 25 | "commWrPort": 30001 26 | }, 27 | 28 | "tdmaConfig": { 29 | "sleepPin": "P8_12", 30 | "enableLength": 0.005, 31 | "slotGuardLength": 0.005, 32 | "preTxGuardLength": 0.005, 33 | "postTxGuardLength": 0.005, 34 | "txLength": 0.100, 35 | "rxDelay": 0.0, 36 | "initTimeToWait": 60.0, 37 | "maxNumSlots": 6, 38 | "desiredDataRate": 1.0, 39 | "initSyncBound": 1, 40 | "operateSyncBound": 2, 41 | "offsetTimeout": 60.0, 42 | "offsetTxInterval": 10.0, 43 | "statusTxInterval": 10.0, 44 | "linksTxInterval": 5.0, 45 | "maxTxBlockSize": 5, 46 | "linkTimeout": 60.0, 47 | "blockTxRequestTimeout": 3, 48 | "minBlockTxDelay": 6, 49 | "fpga": false, 50 | "fpgaFailsafePin": "P8_16", 51 | "fpgaFifoSize": 512, 52 | "enablePin": "P8_15", 53 | "statusPin": "P8_18", 54 | "recvAllMsgs": true, 55 | "restartDelay": 3, 56 | "pollTimeout": 60 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /python/unittests/pixhawkNodeController.log: -------------------------------------------------------------------------------- 1 | Active move state change: ActiveMoveState.holding 2 | Active move state change: ActiveMoveState.initAltChange 3 | Active move state change: ActiveMoveState.holding 4 | Active move state change: ActiveMoveState.initAltChange 5 | Active move state change: ActiveMoveState.finalAltChange 6 | Active move state change: ActiveMoveState.translating 7 | -------------------------------------------------------------------------------- /python/unittests/testConfig.py: -------------------------------------------------------------------------------- 1 | configFilePath = '../nodeConfig.json' 2 | badConfigFilePath = 'nodeConfig_bad.json' 3 | noNodeConfigFilePath = 'nodeConfig_noNodeId.json' 4 | testSerialPort = '/dev/ttyUSB0' 5 | testSerialPort2 = '/dev/ttyUSB1' 6 | -------------------------------------------------------------------------------- /python/unittests/testHelpers.py: -------------------------------------------------------------------------------- 1 | import crcmod.predefined 2 | from mesh.generic.slipMsg import SLIPMsg 3 | from struct import pack 4 | 5 | def createEncodedMsg(msg, msgEncoder): 6 | """Create encoded SLIP message with CRC.""" 7 | crc16 = crcmod.predefined.mkCrcFun('crc16') 8 | crc = crc16(msg) 9 | msgEncoder.encodeMsg(msg + pack('H',crc)) 10 | return msgEncoder.encoded 11 | -------------------------------------------------------------------------------- /python/unittests/test_blank.py: -------------------------------------------------------------------------------- 1 | class TestClass: 2 | 3 | def setup_method(self, method): 4 | pass 5 | 6 | def test_method(self): 7 | """Test method.""" 8 | pass 9 | 10 | -------------------------------------------------------------------------------- /vhdl/commandTypes.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | use ieee.std_logic_1164.all; 3 | use IEEE.STD_LOGIC_unsigned.all; 4 | use ieee.numeric_std.all; 5 | use work.meshPack.all; 6 | 7 | package commandTypes is 8 | 9 | constant numCmds : integer range 0 to 10 := 10; 10 | constant maxCmdSize : integer range 0 to 255 := 5; 11 | 12 | 13 | -- Definitions 14 | type CmdHeaderType is (MinimalHeader, SourceHeader, NodeHeader, InvalidHeader); 15 | type CommandType is record 16 | valid : std_logic; 17 | timestamp : integer range 0 to maxTimeSec; 18 | unique : std_logic; 19 | end record; 20 | 21 | type CommandTypeArray is array(0 to numCmds) of CommandType; 22 | 23 | signal cmdTypes : CommandTypeArray; 24 | 25 | -- Helper functions 26 | function getCmdHeaderType(cmdId : std_logic_vector(7 downto 0)) return CmdHeaderType; 27 | 28 | end package; 29 | 30 | package body commandTypes is 31 | 32 | function getCmdHeaderType(cmdId : std_logic_vector(7 downto 0)) return CmdHeaderType is 33 | variable cmdIdInt : integer range 0 to 255 := to_integer(unsigned(cmdId)); 34 | 35 | begin 36 | if (cmdIdInt = 111) then -- PixhawkCmds.NodeStateUpdate 37 | return SourceHeader; 38 | elsif (cmdIdInt = 90) then -- TDMACmds.MeshStatus 39 | return SourceHeader; 40 | else -- invalid value 41 | return InvalidHeader; 42 | end if; 43 | 44 | end getCmdHeaderType; 45 | 46 | end commandTypes; 47 | 48 | -------------------------------------------------------------------------------- /vhdl/customClock.vhd: -------------------------------------------------------------------------------- 1 | -- uartRx.vhd 2 | -- 3 | -- UART transmitter model for the camera link interface. 4 | -- 5 | -- David Hyde 6 | -- NASA MSFC EI31 7 | -- 3/6/2006 8 | library ieee; 9 | use ieee.std_logic_1164.all; 10 | use ieee.std_logic_unsigned.all; 11 | use work.meshPack.all; 12 | 13 | entity customClock is 14 | generic( 15 | clockDivider : integer range 0 to 100000 := 2; 16 | halfClk : integer range 0 to 100000 := 1 17 | ); 18 | port ( 19 | clk : in std_logic; 20 | rst : in std_logic; 21 | clkOut : out std_logic 22 | ); 23 | end customClock; 24 | 25 | architecture behave of customClock is 26 | 27 | type clockStates is (waitForClkHigh,waitForClkLow); 28 | signal clockState : clockStates; 29 | 30 | signal cnt : integer range 0 to clockDivider := 0; 31 | begin 32 | 33 | -- transmitter 34 | process(rst, clk) 35 | begin 36 | if rst = '0' then 37 | clockState <= waitForClkLow; 38 | cnt <= 1; 39 | clkOut <= '0'; 40 | 41 | elsif (clk'event and clk = '1') then 42 | if (cnt = clockDivider) then 43 | clkOut <= '1'; 44 | cnt <= 1; 45 | -- elsif (cnt >= halfClk) then 46 | -- clkOut <= '0'; 47 | -- cnt <= cnt + 1; 48 | else 49 | clkOut <= '0'; 50 | cnt <= cnt + 1; 51 | end if; 52 | 53 | 54 | end if; 55 | end process; 56 | 57 | 58 | 59 | ------------------------------------------------------------------------------------------ 60 | 61 | 62 | end behave; 63 | 64 | -------------------------------------------------------------------------------- /vhdl/dualRankSync.vhd: -------------------------------------------------------------------------------- 1 | -- dualRankSyncR0.vhd 2 | -- 3 | -- dual rank synchronizer, generic determines reset val 4 | -- 5 | -- David Hyde 6 | -- NASA EI31 7 | -- 3/9/2006 8 | 9 | library ieee; 10 | use ieee.std_logic_1164.all; 11 | 12 | entity dualRankSync is 13 | generic ( resetVal : std_logic := '0'); 14 | port ( 15 | inData, clk, rst : in std_logic; 16 | outData : out std_logic ); 17 | end dualRankSync; 18 | 19 | architecture behave of dualRankSync is 20 | 21 | signal inDataS : std_logic; 22 | 23 | begin 24 | 25 | process (rst, clk) 26 | begin 27 | if rst = '0' then 28 | outdata <= resetVal; 29 | inDataS <= resetVal; 30 | elsif clk'event and clk = '1' then 31 | indataS <= inData; 32 | outData <= indataS; 33 | end if; 34 | end process; 35 | end behave; 36 | 37 | -------------------------------------------------------------------------------- /vhdl/dualRankSyncBus.vhd: -------------------------------------------------------------------------------- 1 | -- dualRankSyncR0.vhd 2 | -- 3 | -- dual rank synchronizer, generic determines reset val 4 | -- 5 | -- David Hyde 6 | -- NASA EI31 7 | -- 3/9/2006 8 | 9 | library ieee; 10 | use ieee.std_logic_1164.all; 11 | 12 | entity dualRankSyncBus is 13 | generic ( 14 | resetVal : std_logic := '0'; 15 | busWidth : integer := 2 16 | ); 17 | port ( 18 | clk, rst : in std_logic; 19 | inData : in std_logic_vector(busWidth - 1 downto 0); 20 | outData : out std_logic_vector(busWidth - 1 downto 0) 21 | ); 22 | end dualRankSyncBus; 23 | 24 | architecture behave of dualRankSyncBus is 25 | 26 | signal inDataS : std_logic_vector(busWidth - 1 downto 0); 27 | 28 | begin 29 | 30 | process (rst, clk) 31 | begin 32 | if rst = '0' then 33 | outdata <= (others => resetVal); 34 | inDataS <= (others => resetVal); 35 | elsif clk'event and clk = '1' then 36 | indataS <= inData; 37 | outData <= indataS; 38 | end if; 39 | end process; 40 | end behave; 41 | 42 | -------------------------------------------------------------------------------- /vhdl/rstDualRankSync.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- rstDualRankSync.vhd 3 | -- 4 | -- This module is used to synchronize the asyncronous reset input. The reset output can then be used as an async reset 5 | -- throughout the design. 6 | -- 7 | -- The synchronous reset output will assert asynchronously as soon as the exteranl async reset is asserted but 8 | -- it will de-assert synchronously. This design guarantees the timing of the reset release with respect 9 | -- the the rising clock edge and allows the reset to remian out of the datapath feeding the D-input to the 10 | -- flops in the design. The design was taken from the paper: 11 | -- http://www.sunburst-design.com/papers/CummingsSNUG2003Boston_Resets.pdf 12 | -- 13 | -- David Hyde 14 | -- NASA ES33 15 | -- 16 | library ieee; 17 | use ieee.std_logic_1164.all; 18 | use ieee.std_logic_unsigned.all; 19 | 20 | entity rstDualRankSync is 21 | generic ( asyncRstAssertVal : std_logic := '0'); 22 | port ( 23 | clk : in std_logic; 24 | asyncRst : in std_logic; 25 | syncRst : out std_logic ); 26 | end rstDualRankSync; 27 | 28 | architecture behave of rstDualRankSync is 29 | 30 | signal ff0Q : std_logic; 31 | 32 | begin 33 | 34 | process (asyncRst, clk) 35 | begin 36 | if asyncRst = asyncRstAssertVal then 37 | syncRst <= asyncRstAssertVal; 38 | ff0Q <= asyncRstAssertVal; 39 | elsif rising_edge(clk) then 40 | ff0Q <= not(asyncRstAssertVal); 41 | syncRst <= ff0Q; 42 | end if; 43 | end process; 44 | end behave; 45 | 46 | --------------------------------------------------------------------------------