![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Fork to see if I can get working
Dependencies: BufferedSerial OneWire WinbondSPIFlash libxDot-dev-mbed5-deprecated
Fork of xDotBridge_update_test20180823 by
xDotBridge/src/CommProtocolPeerBrute.cpp
- Committer:
- mbriggs_vortex
- Date:
- 2017-11-29
- Revision:
- 100:0882cf295f8e
- Parent:
- 95:aa9908d459c2
File content as of revision 100:0882cf295f8e:
/* * CommProtocolPeerBrute.cpp * * Created on: Jan 30, 2017 * Author: mbriggs */ #include "CommProtocolPeerBrute.h" #include "dot_util.h" #include "util.h" #include "MyLog.h" #include "ChannelPlans.h" // wireless bridge protocol const uint8_t TX_PWR = 20; // 20 dBm const float RX_SLEEP_TIME = 2000; // ms (one second resolution, min 2 seconds) const uint8_t TX_TIME = 30*2; // in ms //const unsigned int nTimesToTx = ceil(RX_SLEEP_TIME / ((float)TX_TIME)); const unsigned int nTimesToTx = 75; // Hand tuned to be over 2.03 seconds of transmitting //const uint8_t maxPayloadSize = 10; // Number of bytes (used for toa calcultion) CommProtocolPeerBrute::CommProtocolPeerBrute() { myLogDebug("RX_SLEEP_TIME %f, timeOnAir %lu, nTimesToTx %lu", RX_SLEEP_TIME, TX_TIME, nTimesToTx); mIsTx = true; // default to TX } CmdResult CommProtocolPeerBrute::init() { CmdResult result; if (dot == NULL) { return cmdError; } result = readInfoFromNVM(); if (result != cmdSuccess) { myLogWarning("Reverting to protocol defaults NVM Read failed"); mMemObj.setDefaults(); writeInfoToNVM(); } result = configForSavedNetwork(); if (result != cmdSuccess) { myLogError("Init error during radio config"); return result; } resetCounters(); mPrevDownLinkCnt = dot->getDownLinkCounter(); return cmdSuccess; } CmdResult CommProtocolPeerBrute::configForSavedNetwork() { if (dot == NULL) { return cmdError; } // myLogInfo("defaulting Dot configuration"); // dot->resetConfig(); // dot->setWakePin(GPIO0); // Common Configuration dot->setAesEncryption(true); // Enable encryption dot->setTxWait(false); dot->setAck(0); // Disable Ack dot->setClass("C"); // Set class C dot->setTxPower(TX_PWR); dot->setPreserveSession(false); // TODO break out in a utility function // update configuration if necessary myLogDebug("Setting up peer to peer configuration"); if (dot->getJoinMode() != mDot::PEER_TO_PEER) { myLogDebug("changing network join mode to PEER_TO_PEER"); if (dot->setJoinMode(mDot::PEER_TO_PEER) != mDot::MDOT_OK) { myLogError("failed to set network join mode to PEER_TO_PEER"); } } uint8_t tx_power; uint8_t tx_datarate; uint32_t tx_frequency; uint8_t frequency_band = dot->getFrequencyBand(); switch (frequency_band) { case lora::ChannelPlan::EU868_OLD: case lora::ChannelPlan::EU868: // 250kHz channels achieve higher throughput // DR6 : SF7 @ 250kHz // DR0 - DR5 (125kHz channels) available but much slower tx_frequency = 869850000; tx_datarate = lora::DR_6; // the 869850000 frequency is 100% duty cycle if the total power is under 7 dBm - tx power 4 + antenna gain 3 = 7 tx_power = 4; break; case lora::ChannelPlan::US915_OLD: case lora::ChannelPlan::US915: case lora::ChannelPlan::AU915_OLD: case lora::ChannelPlan::AU915: // 500kHz channels achieve highest throughput // DR8 : SF12 @ 500kHz // DR9 : SF11 @ 500kHz // DR10 : SF10 @ 500kHz // DR11 : SF9 @ 500kHz // DR12 : SF8 @ 500kHz // DR13 : SF7 @ 500kHz // DR0 - DR3 (125kHz channels) available but much slower tx_frequency = 915500000; tx_datarate = lora::DR_13; // 915 bands have no duty cycle restrictions, set tx power to max tx_power = 20; break; default: logError("ChannelPlan Error!!!"); return cmdError; } // in PEER_TO_PEER mode there is no join request/response transaction // as long as both Dots are configured correctly, they should be able to communicate update_peer_to_peer_config(mMemObj.mNetworkAddr, mMemObj.mNetworkSessionKey, mMemObj.mDataSessionKey, tx_frequency, tx_datarate, tx_power); dot->saveConfig(); return cmdSuccess; } CmdResult CommProtocolPeerBrute::configForPairingNetwork() { if (dot == NULL) { return cmdError; } myLogInfo("defaulting Dot configuration"); // TEST dot->resetConfig(); dot->setWakePin(GPIO0); // Common Configuration dot->setAesEncryption(true); // Enable encryption dot->setTxWait(false); dot->setAck(0); // Disable Ack dot->setClass("C"); // Set class C dot->setTxPower(TX_PWR); dot->setPreserveSession(false); // TODO break out in a utility function // update configuration if necessary myLogDebug("Setting up peer to peer configuration"); if (dot->getJoinMode() != mDot::PEER_TO_PEER) { myLogDebug("changing network join mode to PEER_TO_PEER"); if (dot->setJoinMode(mDot::PEER_TO_PEER) != mDot::MDOT_OK) { myLogError("failed to set network join mode to PEER_TO_PEER"); } } uint8_t tx_power; uint8_t tx_datarate; uint32_t tx_frequency; uint8_t frequency_band = dot->getFrequencyBand(); switch (frequency_band) { case lora::ChannelPlan::EU868_OLD: case lora::ChannelPlan::EU868: // 250kHz channels achieve higher throughput // DR6 : SF7 @ 250kHz // DR0 - DR5 (125kHz channels) available but much slower tx_frequency = 869850000; tx_datarate = lora::DR_6; // the 869850000 frequency is 100% duty cycle if the total power is under 7 dBm - tx power 4 + antenna gain 3 = 7 tx_power = 4; break; case lora::ChannelPlan::US915_OLD: case lora::ChannelPlan::US915: case lora::ChannelPlan::AU915_OLD: case lora::ChannelPlan::AU915: // 500kHz channels achieve highest throughput // DR8 : SF12 @ 500kHz // DR9 : SF11 @ 500kHz // DR10 : SF10 @ 500kHz // DR11 : SF9 @ 500kHz // DR12 : SF8 @ 500kHz // DR13 : SF7 @ 500kHz // DR0 - DR3 (125kHz channels) available but much slower tx_frequency = 915500000; tx_datarate = lora::DR_13; // 915 bands have no duty cycle restrictions, set tx power to max tx_power = 20; break; default: logError("ChannelPlan Error!!!"); return cmdError; } update_peer_to_peer_config(pair_network_address, pair_network_session_key, pair_data_session_key, tx_frequency, tx_datarate, tx_power); dot->saveConfig(); // This is required for network settings to apply return cmdSuccess; } void CommProtocolPeerBrute::setTx(bool isTx) { mIsTx = isTx; } bool CommProtocolPeerBrute::isTx() { return mIsTx; } CmdResult CommProtocolPeerBrute::clearPair() { CmdResult result; // TODO generate possibly random channel for new pair std::vector<uint8_t> key; key.reserve(16); result = genEncypKey(key, 4, false); if (result != cmdSuccess) { myLogError("Error generating network address."); return cmdError; } mMemObj.setNetworkAddr(key); result = genEncypKey(key, 16); if (result != cmdSuccess) { myLogError("Error generating network encryption keys."); return cmdError; } mMemObj.setNetworkSessionKey(key); result = genEncypKey(key, 16); if (result != cmdSuccess) { myLogError("Error generating data session encryption keys."); return cmdError; } mMemObj.setDataSessionKey(key); configForSavedNetwork(); writeInfoToNVM(); return cmdSuccess; } // TX focused uint32_t CommProtocolPeerBrute::getSeqNum() { return mMemObj.getLastMsgSeq(); } CmdResult CommProtocolPeerBrute::send (const std::vector<uint8_t> &msg) { if (!dot->getNetworkJoinStatus()) { join_network(); } myLogDebug("Starting TX. Time: %07lu", us_ticker_read()); for(uint8_t i=0;i<nTimesToTx;++i) { dot->send(msg); } myLogDebug("Finished TX. Time: %07lu", us_ticker_read()); return cmdError; } CmdResult CommProtocolPeerBrute::sendAlert(uint16_t data) { if (!dot->getNetworkJoinStatus()) { join_network(); } // Request Message std::vector<uint8_t> msg; msg.reserve(16); // Flag 2 Bytes msg.push_back(0xEF); msg.push_back(0x10); // EUI 8 Bytes std::vector<uint8_t> eui(dot->getDeviceId()); msg.insert(msg.end(), eui.begin(), eui.end()); // Data 2 Bytes appendUint16ToVector(msg, data); // SeqNum 4 Bytes appendUint32ToVector(msg, mMemObj.getLastMsgSeq()); mMemObj.incLastMsgSeq(); return send(msg); } CmdResult CommProtocolPeerBrute::sendPairReq() { if (!dot->getNetworkJoinStatus()) { join_network(); } // Request Message std::vector<uint8_t> msg; msg.reserve(16); // Flag 2 Bytes msg.push_back(0xFE); msg.push_back(0x01); // EUI 8 Bytes std::vector<uint8_t> eui(dot->getDeviceId()); msg.insert(msg.end(), eui.begin(), eui.end()); // Reserved 6 Bytes for (uint8_t i=0;i<6;i++) { msg.push_back(0x00); } dot->send(msg); // Can just send once since the RX should be always listening return cmdSuccess; } // RX focused CmdResult CommProtocolPeerBrute::listen (bool &msgPending) { if (!dot->getNetworkJoinStatus()) { join_network(); } // uint32_t cDwnLink = dot->getDownLinkCounter(); wait(TX_TIME/1000.0); // Wait TX_TIME mPrevDownLinkCnt = 0; // XXX improve how we keep track of new messages. Maybe use lib callbacks. if (mPrevDownLinkCnt < dot->getDownLinkCounter()) { msgPending = true; } else { msgPending = false; } mPrevDownLinkCnt = dot->getDownLinkCounter(); return cmdSuccess; // Maybe add timeout as a possible return value } CmdResult CommProtocolPeerBrute::recv (std::vector<uint8_t> &msg) { dot->recv(msg); return cmdSuccess; } CmdResult CommProtocolPeerBrute::recvAlert (std::vector<uint8_t> &eui, uint16_t &data, uint32_t &seqNum) { std::vector<uint8_t> alertMsg; dot->recv(alertMsg); if (alertMsg.size() < 16) { myLogError("Alert message too short"); return cmdError; } if (alertMsg[0] != 0xEF || alertMsg[1] != 0x10) { myLogError("Invalid alert message flag."); return cmdError; } eui.clear(); eui.assign(alertMsg.begin()+2, alertMsg.begin()+2+8); data = (alertMsg[10] << 8) + alertMsg[11]; seqNum = alertMsg[12] << 24; seqNum += alertMsg[13] << 16; seqNum += alertMsg[14] << 8; seqNum += alertMsg[15]; return cmdSuccess; } CmdResult CommProtocolPeerBrute::waitForPairing(float waitTime) { float t = 0.0; bool msgPending; bool validPairReq = false; std::vector<uint8_t> pairMsg; do { listen(msgPending); t += TX_TIME/1000.0; if (msgPending) { pairMsg.clear(); dot->recv(pairMsg); if (pairMsg[0] == 0xFE && pairMsg[1] == 0x01) { validPairReq = true; } else { myLogWarning("Invalid pair message message flag received ."); } } } while (t < waitTime && !validPairReq); if (!msgPending) { return cmdTimeout; } wait(1.0); // Wait just a little so it is clear for requester that it is a pair message return sendPairAccepted(); } CmdResult CommProtocolPeerBrute::sendPairAccepted() { bool sendResult; // Request Message std::vector<uint8_t> *msg = new std::vector<uint8_t>; msg->reserve(34); // Flag msg->push_back(0xFD); msg->push_back(0x02); myLogDebug("flag msg size %d", msg->size()); // EUI std::vector<uint8_t> *eui = new std::vector<uint8_t>(dot->getDeviceId()); msg->insert(msg->end(),eui->begin(), eui->end()); delete eui; myLogDebug("eui msg size %d", msg->size()); // Reserved for Freq for(uint8_t i=0;i<4;i++) { msg->push_back(0x00); } myLogDebug("freq msg size %d", msg->size()); // Network Address std::vector<uint8_t> *networkAddr = new std::vector<uint8_t>; mMemObj.getNetworkAddr(*networkAddr); msg->insert(msg->end(),networkAddr->begin(), networkAddr->end()); delete networkAddr; myLogDebug("netAddr msg size %d", msg->size()); // Network session key std::vector<uint8_t> *networkSessionKey = new std::vector<uint8_t>; mMemObj.getNetworkSessionKey(*networkSessionKey); msg->insert(msg->end(),networkSessionKey->begin(), networkSessionKey->end()); delete networkSessionKey; myLogDebug("netSessionKey msg size %d", msg->size()); // Data session key std::vector<uint8_t> *dataSessionKey = new std::vector<uint8_t>; mMemObj.getDataSessionKey(*dataSessionKey); msg->insert(msg->end(),dataSessionKey->begin(), dataSessionKey->end()); delete dataSessionKey; myLogDebug("msg size %d", msg->size()); // Only send once since requester should be listening always sendResult = mDot::MDOT_OK == dot->send(*msg); delete msg; if (sendResult) return cmdSuccess; else return cmdError; } CmdResult CommProtocolPeerBrute::waitForAccept(float waitTime) { float t = 0.0; bool msgPending = false; do { listen(msgPending); t += TX_TIME/1000.0; } while (t < waitTime && !msgPending); if (!msgPending) { return cmdTimeout; } std::vector<uint8_t> acceptMsg; dot->recv(acceptMsg); if (acceptMsg[0] != 0xFD || acceptMsg[1] != 0x02) { myLogError("Invalid accept message flag."); return cmdError; } std::vector<uint8_t> *netAddr = new std::vector<uint8_t>(acceptMsg.begin()+0x0E, acceptMsg.begin()+0x12); mMemObj.setNetworkAddr(*netAddr); delete netAddr; std::vector<uint8_t> *netSessionKey = new std::vector<uint8_t>(acceptMsg.begin()+0x12, acceptMsg.begin()+0x22); mMemObj.setNetworkSessionKey(*netSessionKey); delete netSessionKey; std::vector<uint8_t> *dataSessionKey = new std::vector<uint8_t>(acceptMsg.begin()+0x22, acceptMsg.begin()+0x32); mMemObj.setDataSessionKey(*dataSessionKey); delete dataSessionKey; writeInfoToNVM(); return cmdSuccess; } // xDot Peer to Peer Specific uint32_t CommProtocolPeerBrute::getDLC() { return dot->getDownLinkCounter(); } uint32_t CommProtocolPeerBrute::getULC() { return dot->getUpLinkCounter(); } // private: CmdResult CommProtocolPeerBrute::readInfoFromNVM() { bool nvmReadResult; uint8_t *data = new uint8_t [PROTOCOL_NVM_SIZE]; nvmReadResult = dot->nvmRead(PROTOCOL_NVM_START_ADDR, data, PROTOCOL_NVM_SIZE); if (!nvmReadResult) { delete [] data; return cmdError; } mMemObj.fromBytes(data, PROTOCOL_NVM_SIZE); delete [] data; if (!mMemObj.validProtocolFlag()) { myLogWarning("Invalid Protocol Flag. Using default values."); mMemObj.setDefaults(); return cmdError; } else if (!mMemObj.validProtocolRev()) { myLogWarning("Invalid Protocol Rev. Using default values."); mMemObj.setDefaults(); return cmdError; } return cmdSuccess; } CmdResult CommProtocolPeerBrute::writeInfoToNVM() { uint8_t *data = new uint8_t [PROTOCOL_NVM_SIZE]; uint8_t size = PROTOCOL_NVM_SIZE; mMemObj.toBytes(data, size); dot->nvmWrite(PROTOCOL_NVM_START_ADDR, data, PROTOCOL_NVM_SIZE); delete [] data; return cmdSuccess; } CmdResult CommProtocolPeerBrute::resetCounters() { dot->setDownLinkCounter(0); dot->setUpLinkCounter(1); return cmdSuccess; } CmdResult CommProtocolPeerBrute::genEncypKey(std::vector<uint8_t> &newKey, uint8_t keySize) { return genEncypKey(newKey, keySize, true); // Default allow zero } CmdResult CommProtocolPeerBrute::genEncypKey(std::vector<uint8_t> &newKey, uint8_t keySize, bool allowZero) { newKey.clear(); for (uint8_t i=0;i<keySize; i++){ if (allowZero) { newKey.push_back(dot->getRadioRandom() & 0xFF); } else { newKey.push_back((dot->getRadioRandom() % 254) + 1); } } return cmdSuccess; } void CommProtocolPeerBrute::printDotConfig() { // display configuration and library version information myLogInfo("====================="); myLogInfo("general configuration"); myLogInfo("====================="); myLogInfo("version ------------------ %s", dot->getId().c_str()); myLogInfo("device ID/EUI ------------ %s", mts::Text::bin2hexString(dot->getDeviceId()).c_str()); myLogInfo("frequency band ----------- %s", mDot::FrequencyBandStr(dot->getFrequencyBand()).c_str()); if ((dot->getFrequencySubBand() != lora::ChannelPlan::EU868_OLD) || (dot->getFrequencySubBand() != lora::ChannelPlan::EU868)) { myLogInfo("frequency sub band ------- %u", dot->getFrequencySubBand()); } myLogInfo("public network ----------- %s", dot->getPublicNetwork() ? "on" : "off"); myLogInfo("========================="); myLogInfo("credentials configuration"); myLogInfo("========================="); myLogInfo("device class ------------- %s", dot->getClass().c_str()); myLogInfo("network join mode -------- %s", mDot::JoinModeStr(dot->getJoinMode()).c_str()); if (dot->getJoinMode() == mDot::MANUAL || dot->getJoinMode() == mDot::PEER_TO_PEER) { myLogInfo("network address ---------- %s", mts::Text::bin2hexString(dot->getNetworkAddress()).c_str()); #if SHOW_SECRETS myLogInfo("network session key------- %s", mts::Text::bin2hexString(dot->getNetworkSessionKey()).c_str()); myLogInfo("data session key---------- %s", mts::Text::bin2hexString(dot->getDataSessionKey()).c_str()); #endif } else { myLogInfo("network name ------------- %s", dot->getNetworkName().c_str()); myLogInfo("network phrase ----------- %s", dot->getNetworkPassphrase().c_str()); #if SHOW_SECRETS myLogInfo("network EUI -------------- %s", mts::Text::bin2hexString(dot->getNetworkId()).c_str()); myLogInfo("network KEY -------------- %s", mts::Text::bin2hexString(dot->getNetworkKey()).c_str()); #endif } myLogInfo("========================"); myLogInfo("communication parameters"); myLogInfo("========================"); if (dot->getJoinMode() == mDot::PEER_TO_PEER) { myLogInfo("TX frequency ------------- %lu", dot->getTxFrequency()); } else { myLogInfo("acks --------------------- %s, %u attempts", dot->getAck() > 0 ? "on" : "off", dot->getAck()); } myLogInfo("TX datarate -------------- %s", mDot::DataRateStr(dot->getTxDataRate()).c_str()); myLogInfo("TX power ----------------- %lu dBm", dot->getTxPower()); myLogInfo("antenna gain ------------- %u dBm", dot->getAntennaGain()); } // NvmProtocolObj NvmProtocolObj::NvmProtocolObj() { setDefaults(); } void NvmProtocolObj::setDefaults() { mProtocolFlag = PROTOCOL_FLAG; mProtocolRev = PROTOCOL_REV; mFreq = 915500000; std::memset(mNetworkAddr, 0x00, sizeof(mNetworkAddr)); std::memset(mNetworkSessionKey, 0x00, sizeof(mNetworkSessionKey)); std::memset(mDataSessionKey, 0x00, sizeof(mDataSessionKey)); mLogicalAddr = 0x00000000; mSeqNum = 0x00000000; } CmdResult NvmProtocolObj::fromBytes(uint8_t *data, uint8_t size) { if (size != PROTOCOL_NVM_SIZE) { return cmdError; } mProtocolFlag = *((uint16_t *) (data)); mProtocolRev = *((uint16_t *) (data+0x02)); mFreq = *((uint32_t *) (data+0x04)); std::memcpy(&mNetworkAddr, data+0x08, 4); std::memcpy(&mNetworkSessionKey, data+0x10, 16); std::memcpy(&mDataSessionKey, data+0x20, 16); mLogicalAddr = *((uint32_t *) (data+0x30)); mSeqNum = *((uint32_t *) (data+0x32)); return cmdSuccess; } CmdResult NvmProtocolObj::toBytes(uint8_t *data, uint8_t &size) { // TODO check data size *((uint16_t *) (data)) = mProtocolFlag; *((uint16_t *) (data+2)) = mProtocolRev; *((uint32_t *) (data+0x04)) = mFreq; std::memcpy(data+0x08, &mNetworkAddr, 4); std::memcpy(data+0x10, &mNetworkSessionKey, 16); std::memcpy(data+0x20, &mDataSessionKey, 16); *((uint32_t *) (data+0x30)) = mLogicalAddr; *((uint32_t *) (data+0x32)) = mSeqNum; size = PROTOCOL_NVM_SIZE; return cmdSuccess; } uint16_t NvmProtocolObj::getProtocolFlag() { return mProtocolFlag; } bool NvmProtocolObj::validProtocolFlag() { return mProtocolFlag == PROTOCOL_FLAG; } uint16_t NvmProtocolObj::getProtocolRev() { return mProtocolRev; } bool NvmProtocolObj::validProtocolRev() { return mProtocolRev == PROTOCOL_REV; } void NvmProtocolObj::getNetworkAddr(std::vector<uint8_t> &addr) { addr.clear(); addr.assign(mNetworkAddr, mNetworkAddr+sizeof(mNetworkAddr)); } void NvmProtocolObj::setNetworkAddr(const std::vector<uint8_t> &addr) { if (addr.size() > sizeof(mNetworkAddr)) { myLogError("Network address too long. Value not stored."); return; } for (uint8_t i=0; i < sizeof(mNetworkAddr); i++) { mNetworkAddr[i] = addr[i]; } } void NvmProtocolObj::getNetworkSessionKey(std::vector<uint8_t> &key) { key.clear(); key.assign(mNetworkSessionKey, mNetworkSessionKey+sizeof(mNetworkSessionKey)); } void NvmProtocolObj::setNetworkSessionKey(const std::vector<uint8_t> &key) { if (key.size() > sizeof(mNetworkSessionKey)) { myLogError("Network session key too long. Value not stored."); return; } for (uint8_t i=0; i < sizeof(mNetworkSessionKey); i++) { mNetworkSessionKey[i] = key[i]; } } void NvmProtocolObj::getDataSessionKey(std::vector<uint8_t> &key) { key.clear(); key.assign(mDataSessionKey, mDataSessionKey+sizeof(mDataSessionKey)); } void NvmProtocolObj::setDataSessionKey(const std::vector<uint8_t> &key) { if (key.size() > sizeof(mDataSessionKey)) { myLogError("Data session key too long. Value not stored."); return; } for (uint8_t i=0; i < sizeof(mDataSessionKey); i++) { mDataSessionKey[i] = key[i]; } } uint16_t NvmProtocolObj::getLogicalAddr() { return mLogicalAddr; } void NvmProtocolObj::setLogicalAddr(uint16_t in) { mLogicalAddr= in; } uint32_t NvmProtocolObj::getLastMsgSeq() { return mSeqNum; } void NvmProtocolObj::incLastMsgSeq() { mSeqNum++; }