![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
arm studio build
Diff: src/main.cpp
- Revision:
- 0:a91cd1b08360
- Child:
- 1:0d25d9ddbe9f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.cpp Mon Jun 18 17:31:35 2018 +0000 @@ -0,0 +1,477 @@ +#include "mbed.h" +#include "commI2C.h" +#include "dot_util.h" +#include "wbit_util.h" +#include "mDot.h" +#include "RadioEvent.h" +#include "Lora.h" + +//======================================================================================================= +// enable some GPIO for scope trigger or led +//======================================================================================================= +//#define GPIO_ENABLE +//======================================================================================================= +// configure for either private (test only) or public network (standard) +//======================================================================================================= +//#define MT_PRIVATE_NETWORK //ENABLE THIS FOR PRIVATE NETWORK + +//======================================================================================================= +//code api level and version +//api_level: proc code will not run if api level (last two bytess) greater than what it expects +//======================================================================================================= +uint8_t api_level[4] = { 0x00, 0x00, 0x00, 0x03 }; //api-level, determines if xdot code works with proc code +uint8_t ver_level[4] = { 0x00, 0x00, 0x00, 0x07 }; //updated for every code check-in + +//======================================================================================================= +//configuring mbed pinsa; https://docs.mbed.com/docs/mbed-os-api-reference/en/latest/APIs/io/DigitalInOut/ +// * these options must match the settings on your gateway // +// * edit their values to match your configuration // +// * frequency sub band is only relevant for the 915 bands // +// * either the network name and passphrase can be used or // +// the network ID (8 bytes) and KEY (16 bytes) // +//======================================================================================================= +static std::string network_name = "asdfqwer"; +static std::string network_passphrase = "zxcvasdf"; + +static uint8_t network_id[] = { 0x90, 0xF1, 0x47, 0x90, 0x6C, 0x48, 0x1D, 0x29 }; //static id not used anymore but don't comment out +static uint8_t network_key[] = { 0x0F, 0xF9, 0xA2, 0x90, 0x2E, 0xAA, 0x6B, 0x8C, 0x6A, 0x4E, 0xFD, 0x67, 0xF9, 0xA6, 0xF3, 0xD3 }; + + +#ifdef MT_PRIVATE_NETWORK +static uint8_t frequency_sub_band = 4; +static bool public_network = false; +static uint8_t ack = 1; //0; +#else +static uint8_t frequency_sub_band = 1; +static bool public_network = true; //false +static uint8_t ack = 1; //0; +#endif + +static bool adr = false; //set adaptive data rate + +//======================================================================================================= +// deepsleep consumes slightly less current than sleep +// in sleep mode, IO state is maintained, RAM is retained, and application will resume after waking up +// in deepsleep mode, IOs float, RAM is lost, and application will start from beginning after waking up +// if deep_sleep == true, device will enter deepsleep mode +//======================================================================================================= +static bool deep_sleep = false; //false; + +uint32_t packets_sent = 0; +uint32_t acks_rcvd = 0; +int8_t rssi =0; //rssi of last rcvd rx1/rx2 +std::string eui = " "; +static bool led_enabled = false; //true; //false; +mDot* dot = NULL; +lora::ChannelPlan* plan = NULL; +uint8_t buf_xmt[BUFFER_SIZE_I2C]; //outgoing data +uint8_t buf_rcv[BUFFER_SIZE_I2C]; //incoming data +std::vector<uint8_t> upstream_packet; + +#ifdef GPIO_ENABLE +DigitalOut led1(PB_0); //LED1); +DigitalInOut gpio1(PA_5); //scope debug PA-5 is connected to SW1 pads on Loren v04 and can be used for scope debug +#endif + +Serial pc(USBTX, USBRX); //serial port output + +//================================================================================================= +//LED_test +//================================================================================================= +void LED_test(int num) +{ + #ifdef GPIO_ENABLE + if (led_enabled) + { + pc.printf("LED_test()\r\n"); + int test; + for (test=0; test<num; test++) + { + led1 = 0; + wait_ms(500); + led1 = 1; + wait_ms(500); + } + } + #endif +} +//================================================================================== +//chksum +//compute checksum over i2c buffer except for last byte (chksum byte) +//================================================================================== +uint8_t chksum_proc(uint8_t *bfr_xdot){ + uint8_t i; + uint8_t chksum = 0; + for (i=0; i < BUFFER_SIZE_I2C-1;i++)chksum += bfr_xdot[i];//good code + return chksum; +} +//================================================================================================= +//cfg_network: +// configure the network public/private and sub-band +// bForceCfg : true => force a network cfg +// false => only change if bPublic or sub_band have changed +// bPublic : true if network is public, else private +// sub_band: sub band number (1..8) + +// NOTE: THIS ONLY WORKS WHEN THE XDOT BOOTS UP. IT DOES NOT WORK WHEN TRYING TO CHANGE AFTER. +// NOT SURE WHY...WHEN THE XDOT REJOINS IT SHOULD USE NEW SESSION SETTINGS... asb +// +//asb:dec 2017: try this later and see if it works:mdot.h: +// int32_t setPublicNetwork(const bool& on); +// bool getPublicNetwork(); +// int32_t setFrequencySubBand(const uint8_t& band); +//================================================================================================= +bool cfg_network(bool bForceCfg,bool bPublic,uint8_t sub_band){ +// if bForceCfg false and network parameters haven't changed then just exit + if (!bForceCfg){ + pc.printf("no configuration change needed subband the same"); + if ((public_network ==bPublic) && (frequency_sub_band ==sub_band))return true; + } + pc.printf("changing to subband: %d\r\n",sub_band); +// update network settings + public_network = bPublic; + frequency_sub_band =sub_band; +// start from a well-known state + logInfo("defaulting Dot configuration"); + //dot->resetConfig(); //reset config to factory default not used for v0307 + dot->resetNetworkSession(); //Reset current network session, essentially disconnecting from the network + + if (dot->getJoinMode() != mDot::OTA) { // update configuration if necessary + logInfo("changing network join mode to OTA"); + if (dot->setJoinMode(mDot::OTA) != mDot::MDOT_OK) { + logError("failed to set network join mode to OTA"); + return false; + } + } +// in OTA and AUTO_OTA join modes, the credentials can be passed to the library as a name and passphrase or an ID and KEY +// only one method or the other should be used! + if (public_network){ + update_ota_config_id_key(network_id, network_key, frequency_sub_band, public_network, ack); + logInfo("-------------- network configured for public access -----------------------------"); + } + else{ + update_ota_config_name_phrase(network_name, network_passphrase, frequency_sub_band, public_network, ack); + logInfo("-------------- network configured for private access -------------------------------"); + } + +// configure network link checks +// network link checks are a good alternative to requiring the gateway to ACK every packet and should allow a single gateway to handle more Dots +// check the link every count packets +// declare the Dot disconnected after threshold failed link checks +// for count = 3 and threshold = 5, the Dot will ask for a link check response every 5 packets and will consider the connection lost if it fails to receive 3 responses in a row + update_network_link_check_config(3, 5); + +/* done thru radio cmds +// save changes to configuration + logInfo("saving configuration"); + if (!dot->saveConfig()) { + logError("failed to save configuration"); + return false; + } + display_config(); +*/ + return true; +} + +//================================================================================================= +//main() +// main() runs in its own thread in the OS +// (note the calls to wait below for delays) +//================================================================================================= +int main() { + RadioEvent events; + + mDotEvent mdotevent; //used to get ping info???? + plan = new lora::ChannelPlan_US915(); +#ifdef GPIO_ENABLE + gpio1.output(); + gpio1 =0; + led1 = 1; +#endif + pc.baud(115200); + pc.printf("\r\n**********************************************************\r\n"); + pc.printf("\r\n XDOT BOOT\r\n"); + pc.printf("COMM api_level = <HEX> %x.%x.%x.%x\r\n",api_level[0],api_level[1],api_level[2],api_level[3]); + pc.printf("COMM version = %x.%x.%x.%x\r\n",ver_level[0],ver_level[1],ver_level[2],ver_level[3]); + pc.printf("**********************************************************\r\n"); +// LED_test(2); + assert(plan); + dot = mDot::getInstance(plan); + assert(dot); + + //static bool deploy_mode = true; + //dot->setLogLevel((deploy_mode) ? mts::MTSLog::INFO_LEVEL : mts::MTSLog::TRACE_LEVEL); // TRACE_LEVEL , INFO_LEVEL + dot->setLogLevel((true) ? mts::MTSLog::TRACE_LEVEL : mts::MTSLog::TRACE_LEVEL); // TRACE_LEVEL , INFO_LEVEL + dot->setEvents(&events); + +//new !! + // make sure library logging is turned on + //dot->setLogLevel(mts::MTSLog::TRACE_LEVEL); + + +// getStandbyFlag() should return the state of the standby flag directly from the processor +// Standby flag: This bit is set by hardware and cleared only by a POR/PDR (power on reset/power down reset) or by setting the CSBF bit in the PWR power control register (PWR_CR) +// 0: Device has not been in Standby mode +// 1: Device has been in Standby mode +// The xDot should enter standby mode when deep sleep in invoked. So you should see the standby flag set if it came out of deep sleep. + if (!dot->getStandbyFlag()) { //if 0 the power-up/reset which should always be the case at this point + logInfo("mbed-os library version: %d", MBED_LIBRARY_VERSION); + + pc.printf("\r\n saved configuration: "); + frequency_sub_band = dot->getFrequencySubBand(); + pc.printf("\r\n subband: %d ",frequency_sub_band); + pc.printf("\r\n ADR: %d ",dot->getAdr()); + pc.printf("\r\n antenna gain: %d ",dot->getAntennaGain()); + pc.printf("\r\n transmit max pwr: %d ",dot->getMaxTxPower()); + pc.printf("\r\n transmit min pwr: %d ",dot->getMinTxPower()); + pc.printf("\r\n transmit pwr: %d ",dot->getTxPower()); + pc.printf("\r\n TxDataRate: %d ",dot->getTxDataRate()); + pc.printf("\r\n maxPktLen: %d ",dot->getMaxPacketLength()); + pc.printf("\r\n port nmb: %d ",dot->getAppPort()); + + cfg_network(true,public_network,frequency_sub_band); //force network cfg, + + } else { + // restore the saved session (join OTAA info) if the dot woke from deepsleep mode + // useful to use with deepsleep because session info is otherwise lost when the dot enters deepsleep + logInfo("restoring network session from NVM"); + dot->restoreNetworkSession(); + } +//-------------------------------------------------------------------------------------------------------------------------------------------- +// configure network link checks +// network link checks are a good alternative to requiring the gateway to ACK every packet and should allow a single gateway to handle more Dots +//asb: not sure this is correct +// check the link every count packets +// declare the Dot disconnected after threshold failed link checks +// for count = 3 and threshold = 5, the Dot will be considered disconnected after 15 missed packets in a row +// asb: i think this is correct: +// : see mdot.h -> setLinkCheckCount(const uint8_t& count); +// : LinkCounts only used if ACKs disabled +// only LinkCountThreshold is used => rejoin after LinkCountThreshold acks have been missed + update_network_link_check_config(3, 5); +//---------------------------------------------------------------------------------------------------------------------------------------------- + +// save changes to configuration +// logInfo("saving configuration"); + + eui = mts::Text::bin2hexString(dot->getDeviceId()).c_str(); + pc.printf("\r\nEUI: %s",eui); + + bool joined = false; + // std::vector<uint8_t> upstream_packet; + uint8_t i; + + i2c_proc_init(); //init i2c comm + pc.printf("\r\nGoing to sleep\r\n"); //3.00 fails on startup to respond,move code further down + sleep_wake_interrupt_only(deep_sleep); + +//scope test +// gpio1 =1; + + +//============================================================================== +// -loop here forever +// -sleep until LORA_WAKE goes hi => proc ready to send i2c cmd +// -start polling incoming i2c bus for proc cmd +// -execute cmd +// -take control of LORA_WAKE and toggle it hi to signal proc that xdot +// ready to send i2c ack message +// -go back to sleep +//============================================================================== + bool bPulseLoraWake = false; + while(1) + { + pc.printf("\n\r ***************************** "); + + switch (i2c_proc_comm()){ + case I2C_WRITE: //xdot ack ->proc + pc.printf("\n\r xdot ack -> proc done,going to sleep\n\r "); + bPulseLoraWake = false; +// gpio1 =0; + sleep_wake_interrupt_only(deep_sleep); //wait for wake +// gpio1 =1; + pc.printf("\n\r lora wake detected -> monitoring i2c bus\n\r "); + break; + case I2C_READ: //xdot <- proc + bPulseLoraWake = true; + switch (buf_rcv[0]) + { + case XDOT_CMD_XMIT_PKT: + pkt_upstrm *pUp= (pkt_upstrm*)&buf_rcv[0]; + pkt_ack *pAck = (pkt_ack*)&buf_xmt[0]; + pAck->ack = I2C_ACK_PROC; + pAck->cmd = XDOT_CMD_XMIT_PKT; + //pAck->dataLen = buf_rcv[1]; + pAck->dataLen = pUp->dataLen; //data len of xmitted pkt + pc.printf("\r\npkt to xmit data len: %d\r\n",pAck->dataLen); + uint8_t chksum = chksum_proc(buf_rcv); + //pc.printf("\r\chksum rcvd: %d, chksum computed: %d\r\n",chksum,pkt_upstrm->chksum); + pc.printf("\r\nI2C chksum rcvd: %d",chksum); + pc.printf(" chksum computed: %d",pUp->chksum); + pAck->bXmitAttempted = 1; + pAck->chksum_err = 0; + if(pUp->chksum != chksum){ + pc.printf(" chksum err, aborting xmit"); + pAck->bXmitAttempted = 0; + pAck->mdot_ret = -2048; //wbit rtn code? + pAck->chksum_err = 1; + break; + } + if (pUp->dataLen == 0){ //datalen non zero? + pAck->bXmitAttempted = 0; + break; + } + upstream_packet.clear(); //xfr data from incoming bfr to xmit bfr + for (i=0; i< pUp->dataLen;i++) upstream_packet.push_back(pUp->txData[i]); + pc.printf("\r\n[TEST],Upstream Packet Received"); // no \r\n because it comes below + for(std::vector<uint8_t>::iterator it = upstream_packet.begin(); it != upstream_packet.end(); ++it) pc.printf(",0x%x", *it); + pc.printf("\r\n"); // see i told you. + +//not done here, done thru radio commands + // cfg_network(false,pUp->bPublicNetwork,pUp->subBand); //chk for change in network cfg + // dot->setAdr(pUp->bSetAdr); // enable or disable Adaptive Data Rate + + joined = dot->getNetworkJoinStatus(); //are we joined to Lorawan? + pAck->joinAttempts = 0; //no attempts made yet to join + if(!joined) { //if not previously joined, then need to join now + pAck->bJoined = 0; + pc.printf("\r\n----------- NETWORK NOT JOINED YET, WILL TRY TO JOIN %d TIMES\r\n",pUp->joinAttemps); + joined = join_network_wbit(pUp->joinAttemps); + pAck->joinAttempts = join_network_attempts_wbit(); + if (!joined)pc.printf("\r\n----------- FAILED TO JOIN...GIVING UP\r\n"); // join network if not joined + } + if (joined){ + pAck->bJoined = 1; //we are joined to the network + pAck->bAck = 0; //won't know if we receive a lorawan ack until after xmit + pAck->bAckdata = 0; //won't know if we receive a lorawan ack downstream data until after xmit + pAck->rssi = 0; //if not rx1/rx2 then no RSSI value + packets_sent++; + //send packet + //return code indicates results, send return code back to proc Dec14,2017 + pAck->mdot_ret = dot->send(upstream_packet); + printf("\n\rdata->send() return code: %d\r\n",pAck->mdot_ret); + if (pAck->mdot_ret == mDot::MDOT_OK){ //xmit the pkt in blocking mode, return false if no ack + //if (dot->send(upstream_packet) == mDot::MDOT_OK){ //xmit the pkt in blocking mode, return false if no ack + acks_rcvd++; + pAck->bAck = 1; //we got a Rx1 or Rx2 ack + mDot::rssi_stats rssiStats = dot->getRssiStats(); //rssi stat + pAck->rssi = (int8_t)rssiStats.last; + printf("\n\rdata->send()= true => ack rcvd :ack=: %d, rssi=: %d\r\n",pAck->bAck,pAck->rssi); + +//test for subband change +// pc.printf("\r\n----------- CHANGING SUBBANDS-------------------------------------\r\n"); +// cfg_network(false,pUp->bPublicNetwork,2); //chk for change in network cfg + + if (events.is_packet_received()){ //any downstream data from the Rx1/Rx2 pkt? + printf("\n\revents.is_packet_received = true\r\n"); + pAck->bAckdata = 1; + upstream_packet.clear(); + upstream_packet = events.get_downstream_packet(); + pAck->rxLen = upstream_packet.size(); + if (pAck->rxLen > I2C_MAX_ACK_DATA){ + pc.printf("\r\n got ack with pkt data too large.. rejected\r\n"); + break; + } + pc.printf("\r\n pkt data: "); + for (i=0; i< pAck->rxLen;i++) { + pAck->rxData[i]= upstream_packet[i]; + pc.printf(" %x",pAck->rxData[i]); + } + } //if downstream data rcvd + else{ + printf("\n\revents.is_packet_received ()= false => ack rcvd but no data\r\n"); + } + } //send() returns K + else{ + printf("\n\rdata->send()= false => no ack\r\n"); //could be some other error + } + }//if joined + break; + case XDOT_CMD_SET_RADIO: + pc.printf("\n\r proc cmd: CMD_SET_RADIO"); + pkt_setradiodwn *pDwnRadio= (pkt_setradiodwn*)&buf_xmt[0]; + pkt_setradioup *pUpRadio = (pkt_setradioup*)&buf_rcv[0]; + pDwnRadio->ack = I2C_ACK_PROC; + pDwnRadio->cmd = XDOT_CMD_SET_RADIO; + + if (pUpRadio->bSetParams){ + pc.printf("\n\r setting subband to %d ",pUpRadio->sub_band); + cfg_network(false,true,(uint8_t)pUpRadio->sub_band); + pc.printf("\n\r setting adr to %d ",pUpRadio->aDR); + dot->setAdr((uint8_t)pUpRadio->aDR); // enable or disable Adaptive Data Rate + pc.printf("\n\r setting antenna gain to %d ",pUpRadio->antennaGaindBi); + dot->setAntennaGain(pUpRadio->antennaGaindBi); + pc.printf("\n\r setting radio tx power to %d ",pUpRadio->txPowerdBm); + dot->setTxPower(pUpRadio->txPowerdBm); + pc.printf("\n\r setting tx datarate to %d ",pUpRadio->dataRate); + dot->setTxDataRate(pUpRadio->dataRate); + pc.printf("\n\r setting application port %d ",pUpRadio->appPort); + dot->setAppPort(pUpRadio->appPort); + pc.printf("\n\r saving configuration"); + if (!dot->saveConfig())logError("failed to save configuration"); + display_config(); + } + + pDwnRadio->public_network = public_network; + pDwnRadio->sub_band = dot->getFrequencySubBand(); + pDwnRadio->maxDataLen = dot->getMaxPacketLength(); + pDwnRadio->maxTxPowerdBm = dot->getMaxTxPower(); + pDwnRadio->minTxPowerdBm = dot->getMinTxPower(); + pDwnRadio->aDR = dot->getAdr(); + pDwnRadio->antennaGaindBi = dot->getAntennaGain(); + pDwnRadio->txPowerdBm = dot->getTxPower(); + pDwnRadio->dataRate = dot->getTxDataRate(); + pDwnRadio->appPort = dot->getAppPort(); + break; + + case XDOT_CMD_GET_EUI: //0307: modified to include radio parameter settings + pc.printf("\n\r proc cmd: get EUI"); + pkt_eui *peui = (pkt_eui*)&buf_xmt[0]; + peui->ack = I2C_ACK_PROC; + peui->cmd = XDOT_CMD_GET_EUI; + upstream_packet.clear(); + upstream_packet = dot->getDeviceId(); + peui->dataLen = upstream_packet.size(); + for (i=0; i< peui->dataLen;i++) peui->euiData[i] = upstream_packet[i]; + for (i=0; i< 4;i++) peui->apiLvlData[i] = api_level[i]; + for (i=0; i< 4;i++) peui->verLvlData[i] = ver_level[i]; + peui->dataLen = sizeof(pkt_eui)-3; //size of struc minus first 3 bytes + pc.printf("\n\r eui data length: %d",peui->dataLen); + break; + case XDOT_CMD_SET_KEY_X: + pc.printf("\n\r proc cmd: set a key, simulating minm delay before wake pulse\r\n"); + wait_ms(I2C_MIN_WAIT_DELAY); + buf_xmt[0] = I2C_ACK_PROC; + buf_xmt[1] = XDOT_CMD_SET_KEY_X; + break; + case XDOT_CMD_GATEWAY_PING: + pc.printf("\n\r proc cmd: xmit gateway ping\r\n"); + pkt_ping *pPing = (pkt_ping*)&buf_xmt[0]; + pPing->ack = I2C_ACK_PROC; + pPing->cmd = XDOT_CMD_GATEWAY_PING; + pPing->dataLen = 3; //only 3 bytes returned + pc.printf("\r\n----------- SENDING GATEWAY PING \r\n"); + mDot::ping_response ping_res; + ping_res = dot->ping(); + pPing->status = (int8_t)ping_res.status; + pPing->rssi = (int8_t)ping_res.rssi; + pPing->snr = (int8_t)ping_res.snr; + if (ping_res.status == 0) + pc.printf("\r\n----------- GATEWAY PING SUCCEEDED \r\n"); + else + pc.printf("\r\n----------- GATEWAY PING FAIL \r\n"); + break; + default: + pc.printf("\n\r proc cmd not recognized:%x",buf_rcv[0]); + wait_ms(I2C_MIN_WAIT_DELAY); + buf_xmt[0] = I2C_ACK_PROC; + buf_xmt[1] = XDOT_CMD_UNDEFINED; + } //switch buf_rcv[0] + //gpio1 =1; //test + if (bPulseLoraWake) i2c_pulse_wake(); //pulse wake-up lo->hi->lo to signal proc that xdot ready to send ack + + } //switch i2c_proc_comm + } //while + +} //main +