arm studio build

Dependencies:   libxDot-mbed5

src/main.cpp

Committer:
alan1974
Date:
2020-07-29
Revision:
31:4539c212ecaa
Parent:
29:b3e9a0477d96

File content as of revision 31:4539c212ecaa:

#include "mbed.h"
#include "global.h"
#include "commI2C.h"
#include "dot_util.h"
#include "wbit_util.h"
#include "multicast.h"
#include "mDot.h"
#include "RadioEvent.h"
#include "ChannelPlans.h"
#include "Lora.h"

bool        verbose =  true;
bool        bRxDone = false;              //true if callback function RxDone() triggered
bool        bDownLinkCntrFail = false;    //true if callback function RxDone() triggered and bad downlink frame count
bool        bListen4Multicast = false;
uint16_t    maxMulticastSessionTime = 0;
//nvm storage params
nvm         nvmData;
nvm         *pNvmData = &nvmData;



//=======================================================================================================
// enable GPIO for scope trigger
//=======================================================================================================
//#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, 0x04 };  //api-level, determines if xdot code works with proc code
uint8_t ver_level[4] = { 0x00, 0x00, 0x00, 0x0B };  //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";  //not used
static std::string network_passphrase = "zxcvasdf"; //not used


#ifdef MT_PRIVATE_NETWORK
static uint8_t frequency_sub_band = 4;
static bool public_network = false;
static uint8_t ack = 1; //0;
#else
uint8_t frequency_sub_band = 1;
bool public_network = true; //false
uint8_t ack = 1; //0;
uint8_t link_check_treshold = 100; //5;
#endif

bool adr = false;    //set adaptive data rate
//=======================================================================================================
// -need to add a delay between exiting i2c read->proc and before putting xdot to sleep to allow for final
//  xfr of bytes in i2c buffer to be xfrd to proc. If log output enabled then it causes enough delay when
//  it prints status info to make the delay ok. For now add this delay when both log enabled and disabled.
int16_t wait_before_sleep_usec =  10000;
//=======================================================================================================
// deepsleep consumes slightly less current than sleep
// sleep mode:     IO state is maintained, RAM is retained, and application will resume after waking up
// 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
// asb:
//  no longer use deepsleep since we want to retain state
//  sleep uses only 1uA more current than deepsleep
//=======================================================================================================
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
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

//==================================================================================
//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) {
        if(verbose)pc.printf("no configuration change needed subband the same");
        if ((public_network ==bPublic) && (frequency_sub_band ==sub_band))return true;
    }
    if(verbose)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");
    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(nvmData.key_AppEUI,nvmData.key_AppKey, 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 check count
// declares the Dot disconnected if no acks received within link_check_treshold transmits
    //update_network_link_check_config(3, 5);
    dot->setLinkCheckThreshold(link_check_treshold);
    return true;
}
//=================================================================================================
//main()
// main() runs in its own thread in the OS
// (note the calls to wait below for delays)
//=================================================================================================
int main()
{
    uint8_t i;
    RadioEvent events;  //class to return info on rx pkts
    mDotEvent  mdotevent;   //used to get ping info????
    //plan = new lora::ChannelPlan_US915();
    static lora::ChannelPlan_US915 plan;
#ifdef GPIO_ENABLE
    gpio1.output();
    gpio1 =0;
#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");
    //assert(plan);
    //dot = mDot::getInstance(plan);
    dot = mDot::getInstance(&plan);
    //assert(dot);

    dot->setEvents(&events);



    nvmRead(pNvmData);

    if (pNvmData->bLogOutputOn == 0) {
        pc.printf("\r\nDISABLING TERMINAL OUTPUT\r\n");
        dot->setLogLevel(mts::MTSLog::NONE_LEVEL);         //doesn't work
        verbose = false;
    } else {
        printNmvData(pNvmData);
        //dot->setLogLevel((verbose) ? mts::MTSLog::TRACE_LEVEL : mts::MTSLog::TRACE_LEVEL);  // TRACE_LEVEL        , INFO_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 => power-up/reset which should always be the case at this point
//        logInfo("mbed-os library version: %d", MBED_LIBRARY_VERSION);  //  MBED_LIBRARY_VERSION no longer declared?
        frequency_sub_band = dot->getFrequencySubBand();
        printRadioCfg();
        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 check count
// declares the Dot disconnected if no acks received within link_check_treshold transmits
    //update_network_link_check_config(3, 5);
    dot->setLinkCheckThreshold(link_check_treshold);
//----------------------------------------------------------------------------------------------------------------------------------------------
    eui = mts::Text::bin2hexString(dot->getDeviceId()).c_str();
    //if(verbose)pc.printf("\r\nEUI: %s\r\n",eui);
    bool joined = false;

    i2c_proc_init();  //init i2c comm

    sleep_wake_interrupt_only(deep_sleep); //goto sleep;wake on next rising edge of lora_wake
    if(verbose)pc.printf("\n\r lora wake detected -> monitoring i2c bus\n\r ");

//scope test
#ifdef GPIO_ENABLE
    gpio1 =1;
#endif
//==============================================================================
//  -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
//==============================================================================
//==============================================================================
//  -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;
    string sLoraVersion;
    
    while(1) {
        if(verbose)pc.printf("\n\r***************************** ");

        switch (i2c_proc_comm(buf_xmt,buf_rcv,BUFFER_SIZE_I2C)) {
            case I2C_WRITE:                 //xdot ack ->proc
                if(verbose)pc.printf("\n\r xdot ack -> proc done,going to sleep\n\r ");
                bPulseLoraWake = false;
                #ifdef GPIO_ENABLE
                    gpio1 =0;
                #endif
                wait_us(wait_before_sleep_usec);         //wait for i2c to complete data transfer before sleeping
                if (bListen4Multicast) {                //in ClassC and receiving multicst pkt, stay here until timeout or bListen4Multicast false
                    if(verbose)pc.printf("\n\r changed to class C\r\n");
                    while(bListen4Multicast) { //stay in mcast bListen4Mutlicast =0, xdot exits -> classA when terminating mcast frag# received else psoc resets xdot
                        wait_us(1000*1000);
                    }
                }
                sleep_wake_interrupt_only(deep_sleep);   //sleep until rising edge of wake signal from proc
                #ifdef GPIO_ENABLE
                    gpio1 =1;
                #endif
                if(verbose)pc.printf("\n\r lora wake detected -> monitoring i2c bus\n\r ");
                break;
            case I2C_READ:      //psoc -> xdot i2c write            
                bPulseLoraWake = true;
                switch (buf_rcv[0]) {               //switch on command #
                    case XDOT_CMD_XMIT_PKT:         //transmit data pkt                 
                    case XDOT_CMD_GET_GPS:          //get gps time stamp                      //GPS TIME !!!!!!!!!!!!!  
                    {
                        bool bGpsTimeRequest     = false;                                              
                        bool bOk2XmitFullPayload = true;  //if false we only transmit the mac data
                        pkt_upstrm  *pUp= (pkt_upstrm*)&buf_rcv[0];            //psoc i2c pkt
                        for (i=0; i < sizeof(buf_xmt); i++)buf_xmt[i] = 0xff;  //xdot i2c bfr fill
                        pkt_ack *pAck = (pkt_ack*)&buf_xmt[0];                 //cast to xdot i2c bfr
                        pAck->ack = I2C_ACK_PROC;                              //write ack to i2c xdot bfr
                        
                        uint8_t chksum = chksum_proc(buf_rcv);                  //i2c pkt chksum from psoc ok?
                        if(verbose)
                            pc.printf("\r\nI2C chksum rcvd/computed: %d/%d ",pUp->chksum,chksum);
                        pAck->bXmitAttempted = 1;
                        pAck->chksum_err = 0;
                        if(pUp->chksum != chksum) 
                        {
                            if(verbose)pc.printf(" chksum err, aborting xmit");
                            pAck->bXmitAttempted = 0;
                            pAck->mdot_ret = XDOT_ERR_I2C_CHKSUM;
                            pAck->chksum_err = 1;
                            break;
                        }
                        
                        if (buf_rcv[0] == XDOT_CMD_GET_GPS)         //GPS TIME !!!!!!!!!!!!!                        
                        {                                                        
                            bGpsTimeRequest = true;
                            pAck->cmd = XDOT_CMD_GET_GPS;
                            string sLoraVersion =  dot->getMtsLoraId(); //LoraVersion: 3.2.1-mbed51101
                                                   
                        }
                        else
                        {
                            pAck->cmd = XDOT_CMD_XMIT_PKT;  //sendint normal data pkt                     
                            pAck->dataLen = pUp->dataLen;   //data len of xmitted pkt                        
                            if(verbose)pc.printf("\r\ndatalen of pkt to xmit: %d",pAck->dataLen);
                            //if next tx pkt includes mac data then xmit mac data and abort psoc payload
                            uint8_t maxPayLoad = dot->getMaxPacketLength();
                            uint8_t maxSizeNxtTxPkt = dot->getNextTxMaxSize();  //max payload available to transmit in next pkt
                            if(verbose)pc.printf("\r\nmax datalen of next pkt: %d",maxSizeNxtTxPkt);
                            if (maxSizeNxtTxPkt < maxPayLoad)
                            {
                                if(verbose)pc.printf("\r\n can't fit payload in next pkt,xmit only mac data\r\n");
                                bOk2XmitFullPayload = false;
                            }
                            else 
                            {
                                if(verbose)pc.printf("\r\nok to xmit full payload");
                            }                          
                            if(verbose)pc.printf("\r\nsetting application port %d ",pUp->appPort);  
                            dot->setAppPort(pUp->appPort);
                            uint8_t linkThresholdCnt =  pUp->linkThreshCnt;
                            if(verbose)pc.printf("\r\nlinkThreshCnt %d\r\n",linkThresholdCnt);
                            dot->setLinkCheckThreshold(linkThresholdCnt);
                            if (pUp->dataLen ==  0) 
                            { 
                                pAck->bXmitAttempted = 0;
                                break;
                            }                            
                            upstream_packet.clear();    //clear the xmit payload array
                            if(bOk2XmitFullPayload)     //if no mac data to xmit, xfr data from incoming bfr to xmit bfr
                                for (i=0; i< pUp->dataLen; i++) upstream_packet.push_back(pUp->txData[i]);
                            if(verbose)
                            {
                                pc.printf("\r\n[TEST],Upstream Packet Received");
                                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.
                            }                                                    
                        }                                                
                        joined = dot->getNetworkJoinStatus();   //are we joined to Lorawan?
                        if(verbose)pc.printf("\r\njoin status on entry: %d\r\n",joined);
                        pAck->joinAttempts = 0;                 //no attempts made yet to join
                        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 -- 8 bit rssi, deprecated, keep for compatbility
                        pAck->rssi2 = 0;                        //16 bit rssi
                        pAck->snr  = 0;                         //if not rx1/rx2 then no SNR value
                        pAck->snr2 = 0;                         //16 bit snr
                        if(!joined)                             //if not previously joined, then need to join now
                        {                           
                            pAck->bJoined = 0;
                            if(verbose)pc.printf("\r\n----------- NETWORK NOT JOINED YET, WILL TRY TO JOIN %d TIMES\r\n",pUp->joinAttemps);
                            joined = join_network_wbit(pUp->joinAttemps);      //try joinAttemps times to join network
                            pAck->joinAttempts = join_network_attempts_wbit(); //# of join attemps made
                            if(verbose)pc.printf("\r\njoin status after join attempt: %d\r\n",joined);
                            if (joined)                     //are we now joined?    
                            {                   
                                dot->saveNetworkSession();  //save OTAA keys and session info on new join success
                                save_OTAA_session_keys();   //used for multicast
                            } else 
                                if(verbose)pc.printf("\r\n----------- FAILED TO JOIN...GIVING UP\r\n"); // join network if not joined                                                                                 }
                        }
                        if (joined)                       //we are joined to the network
                        {                     
                            pAck->bJoined = 1;
                            packets_sent++;
                            bRxDone = false;              //true if callback function RxDone() triggered
                            bDownLinkCntrFail = false;    //true if callback function RxDone() triggered and bad downlink frame count                          
                            plan.SetRx2DatarateIndex(8);  //LORIOT FIX FOR RX2 & OTA 
                            
                            if (bGpsTimeRequest)  
                            {            
                                uint64_t gpsTime = dot->getGPSTime();
                                pAck->rxLen      = 8;
                                pAck->bAck       = true;
                                pAck->bAckdata   = true;
                                if(verbose)
                                {
                                    pc.printf("\r\n gps data: ");
                                   // uint32_t lwr32 = gpsTime &0xffffffff;
                                   // uint32_t upr32 = (gpsTime >> 32);
                                   // pc.printf("lwr32 %0x\r\n",lwr32);
                                   // pc.printf("upr32 %0x\r\n",upr32);
                                    pc.printf("\r\n gps data bytes: ");
                                    
                                    
                                    for (i=0; i< 8; i++)
                                    {                                        
                                        pAck->rxData[i]= (gpsTime>>(8*(7-i))) & 0xff;
                                        pc.printf(" %02x",pAck->rxData[i]);
                                    }
                                    pc.printf("\r\n");                                    
                                }    
                                break;
                             }   
                            
                            if(bOk2XmitFullPayload)       //send normal payload, no mac data to send
                            { 
                                pAck->mdot_ret = dot->send(upstream_packet);  //xmit the pkt
                                if (verbose)printf("\n\rdata->send() return code: %d\r\n",pAck->mdot_ret);
                            }
                            else  //just xmit mac payload without psoc payload, return errcode for max payload exceeded
                            { 
                                dot->send(upstream_packet);  //xmit the pkt in blocking mode, return false if no ack
                                pAck->mdot_ret = XDOT_ERR_MAX_PAYLOAD;
                                pAck->bXmitAttempted = 0;
                            }
                            if (pAck->mdot_ret == mDot::MDOT_OK) //ack rcvd?
                            {
                                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;                //deprecated later!
                                pAck->rssi2 = (int16_t)rssiStats.last;
                                mDot::snr_stats snrStats = dot->getSnrStats();      //snr stat
                                pAck->snr = (int8_t)snrStats.last;                  //deprecate later
                                pAck->snr2 = (int16_t)snrStats.last;
                                if (verbose)printf("\n\rdata->send()=true; ack:%d, rssi:%d snr:%d\r\n",pAck->bAck,pAck->rssi,pAck->snr);
                                if (events.is_packet_received())                    //downstream data from the Rx1/Rx2 pkt?
                                {
                                    if (verbose)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();
                                    pAck->appPort = events.port;
                                    if (pAck->rxLen > I2C_MAX_ACK_DATA) {
                                        if(verbose)pc.printf("\r\n got ack with pkt data too large.. rejected\r\n");
                                        break;
                                    }
                                    if(verbose)
                                    {
                                        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]);
                                        }
                                    }
                                } 
                                else 
                                {                                              //no downstream data
                                    if (verbose)printf("\n\r ack rcvd without data\r\n");
                                } 
                            } 
                            else
                            {
                                if (verbose)printf("\n\r no ack rcvd \r\n");     //could be some other error
                                if ((pAck->mdot_ret != 0)  && bRxDone)           //chk if callback function triggered
                                { 
                                    if (bDownLinkCntrFail)pAck->mdot_ret = XDOT_ERR_FRAME_CNT; //bad downlink frame count return err code
                                }
                            }
                        }//if joined
                        break;
                    }    
                    case XDOT_CMD_SET_RADIO:
                    {
                        if(verbose)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) {
                            if(verbose)pc.printf("\n\r setting radio params");
                            if(verbose)pc.printf("\n\r setting adr to %d ",pUpRadio->params.aDR);
                            if (pUpRadio->params.aDR == 1) dot->setAdr(true);   //test for adr problem
                            else                           dot->setAdr(false);
                            dot->setAdr((uint8_t)pUpRadio->params.aDR);  // enable or disable Adaptive Data Rate
                            if(verbose)pc.printf("\n\r setting subband to %d ",pUpRadio->params.sub_band);
                            cfg_network(false,true,(uint8_t)pUpRadio->params.sub_band);

                            if(verbose)pc.printf("\n\r setting public/private network to %d ",pUpRadio->params.public_network);
                            //public_network = (bool)pUpRadio->params.public_network;
                            dot->setPublicNetwork((bool)pUpRadio->params.public_network);

                            if(verbose)pc.printf("\n\r setting antenna gain to %d ",pUpRadio->params.antennaGaindBi);
                            dot->setAntennaGain(pUpRadio->params.antennaGaindBi);
                            if(verbose)pc.printf("\n\r setting radio tx power to %d ",pUpRadio->params.txPower);
                            dot->setTxPower(pUpRadio->params.txPower);
                            if(verbose)pc.printf("\n\r setting tx datarate to %d ",pUpRadio->params.dataRate);
                            dot->setTxDataRate(pUpRadio->params.dataRate);
//deprecated                     if(verbose)pc.printf("\n\r setting tx inverted to %d ",(bool)pUpRadio->params.txInverted);
//deprecated                     dot->setTxInverted((bool)pUpRadio->params.txInverted);
//deprecated                     if(verbose)pc.printf("\n\r setting rx inverted to %d ",(bool)pUpRadio->params.rxInverted);
//deprecated                     dot->setRxInverted((bool)pUpRadio->params.rxInverted);
                            if(verbose)pc.printf("\n\r setting rx delay to %d ",pUpRadio->params.rxDelay);
                            dot->setRxDelay(pUpRadio->params.rxDelay);
                            if(verbose)pc.printf("\n\r setting join delay to %d ",pUpRadio->params.join_delay);
                            dot->setJoinDelay(pUpRadio->params.join_delay);
                            if(verbose)pc.printf("\n\r saving configuration");
                            if (!dot->saveConfig())logError("failed to save configuration");

                            display_config();
                        }
                        if(verbose)pc.printf("\n\r reading radio params");
                        pDwnRadio->params.public_network = public_network;
                        pDwnRadio->params.sub_band = dot->getFrequencySubBand();
                        pDwnRadio->params.join_delay = dot->getJoinDelay();
//deprecated             pDwnRadio->params.txInverted = dot->getTxInverted();
//deprecated             pDwnRadio->params.rxInverted = dot->getRxInverted();
                        pDwnRadio->params.txInverted = false;  //not used anymorer
                        pDwnRadio->params.rxInverted = false;  //not used anymorer
                        pDwnRadio->params.rxDelay = dot->getRxDelay();
                        pDwnRadio->params.maxDataLen = dot->getMaxPacketLength();
                        pDwnRadio->params.maxTxPowerdBm = dot->getMaxTxPower();
                        pDwnRadio->params.minTxPowerdBm = dot->getMinTxPower();
                        pDwnRadio->params.aDR = dot->getAdr();
                        pDwnRadio->params.antennaGaindBi = dot->getAntennaGain();
                        pDwnRadio->params.txPower = dot->getTxPower();    //programmed tx power (non-adr)
                        pDwnRadio->params.dataRate = dot->getTxDataRate();   //programmed data rate (non-adr)
                        pDwnRadio->params.dataRateCurrent = dot->getSettings()->Session.TxDatarate;  //presently used data rate (adr can change this);see Lora.h
                        pDwnRadio->params.txPowerCurrent = dot->getSettings()->Session.TxPower;//presently used tx power  (adr can change this);see Lora.h
                        pDwnRadio->params.rx1DelayCurrent = dot->getSettings()->Session.RxDelay;//presently used rx1_delay;see Lora.h
                        break;
                    }    
                    case XDOT_CMD_GET_EUI:   //0307: modified to include radio parameter settings
                    {
                        if(verbose)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
                        if(verbose)pc.printf("\n\r eui data length: %d",peui->dataLen);
                        break;
                    }    
                    case XDOT_CMD_GET_LORAN_VER:
                    {
                        if(verbose)pc.printf("\n\r proc cmd: get lorawan version");                        
                        sLoraVersion =  dot->getMtsLoraId();                        
                        //if(verbose)printf("\r\nLoraVersion: %s\r\n",sLoraVersion);         
                        pkt_eui *plorawan = (pkt_eui*)&buf_xmt[0];
                        plorawan->ack = I2C_ACK_PROC;
                        plorawan->cmd = XDOT_CMD_GET_LORAN_VER;
                        i = 0;
                        while (i < 16)
                        {                        
                            plorawan->euiData[i] = sLoraVersion[i];                        
                            if( sLoraVersion[i] == 0) break;
                            i++;
                        }
                        plorawan->euiData[i] = 0;    
                        break; 
                    }       
                    case XDOT_CMD_NVM:
                    {
                        if(verbose)pc.printf("\n\r proc cmd: NVM OTAA");
                        pkt_setnvmup  *pUpNvm = (pkt_setnvmup*)&buf_rcv[0];
                        pkt_setnvmdwn *pDwnNvm= (pkt_setnvmdwn*)&buf_xmt[0];
                        pDwnNvm->ack = I2C_ACK_PROC;
                        pDwnNvm->cmd = XDOT_CMD_NVM;
                        pDwnNvm->dataLen = sizeof(nvm)-2;
                        if (pUpNvm->nvm_option == XDOT_NVM_SET)     nvmWrite(&pUpNvm->nvmData);
                        if (pUpNvm->nvm_option == XDOT_NVM_RESTORE) nvmRestore(&pUpNvm->nvmData);

                        pDwnNvm->bChkSumOK = 0;
                        if (nvmRead(&pDwnNvm->nvmData))
                            pDwnNvm->bChkSumOK = 1;
                        printNmvData(&pDwnNvm->nvmData);
                        break;
                    }    
                    case XDOT_CMD_RESTORE_SESSION:  //restore OTAA session
                    {
                        dot->restoreNetworkSession();
                        dot->setDownLinkCounter(0); //reset frame counters
                        dot->setUpLinkCounter(0);
                        pkt_ntwrk  *pDwnRstSession = (pkt_ntwrk*)&buf_xmt[0];
                        pDwnRstSession->ack = I2C_ACK_PROC;
                        pDwnRstSession->cmd = XDOT_CMD_RESTORE_SESSION;
                        pDwnRstSession->bSetNetwrk = 1;
                        pDwnRstSession->dataLen = sizeof(pkt_ntwrk)-2;
                        if(verbose)pc.printf("\n\r OTAA network session restored\r\n");
                        wait_us(1000*I2C_MIN_WAIT_DELAY);
                        break;
                    }    
                    case XDOT_CMD_SET_RADIO_CLASS:  //multicast_change_class A or C (change only after a join!)
                    {
                        if(verbose)pc.printf("\n\r proc cmd: change radio class\r\n");
                        pkt_setClassUp  *pUpSetClass =  (pkt_setClassUp*)&buf_rcv[0];
                        pkt_setClassDwn *pDwnSetClass = (pkt_setClassDwn*)&buf_xmt[0];
                        pDwnSetClass->ack = I2C_ACK_PROC;
                        pDwnSetClass->cmd = XDOT_CMD_SET_RADIO_CLASS;
                        pDwnSetClass->dataLen = sizeof(class_switch)-2;
                        bool bOk = multicast_change_class(&pUpSetClass->classData);
                        if (bOk && pUpSetClass->classData.bListen4Multicast) { //go into listen only mode for multicast pkts?
                            bListen4Multicast = true;;
                            maxMulticastSessionTime = pUpSetClass->classData.maxMulticastSessionTime;
                        }
                        pDwnSetClass->bSwitched = bOk;
                        break;
                    }

                    case XDOT_CMD_SET_NTWKSESS:  //read or write network session to xdot flash
                    {
                        bool bWriteSession = (bool)buf_rcv[1];
                        if (bWriteSession) {
                            if(verbose)pc.printf("\n\r proc cmd writing network sesion to flash");
                            dot->saveNetworkSession();
                        } else {
                            if(verbose)pc.printf("\n\r reading network session from flash");
                            dot->restoreNetworkSession();
                        }
                        pkt_ntwrk *pktwrk = (pkt_ntwrk*)&buf_xmt[0];
                        pktwrk->ack = I2C_ACK_PROC;
                        pktwrk->cmd = XDOT_CMD_SET_NTWKSESS;
                        pktwrk->bSetNetwrk = (uint8_t)bWriteSession;
                        break;
                    }    
                    /*
                                        case XDOT_CMD_SET_KEY_X:
                                            if(verbose)pc.printf("\n\r proc cmd: this command not used\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:
                    {
                        if(verbose)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
                        if(verbose)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)
                            if(verbose)pc.printf("\r\n----------- GATEWAY PING SUCCEEDED \r\n");
                        else
                             if(verbose)pc.printf("\r\n----------- GATEWAY PING FAIL \r\n");
                        break;                        
                    }    
                    default:
                    {
                        if(verbose)pc.printf("\n\r proc cmd not recognized:%x",buf_rcv[0]);
                        wait_us(1000*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