LoRa_Miun_Lib

Dependents:   Smart_Miun

Revision:
4:522bba1c5fa1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MIUN.LoRa.cpp	Wed Oct 11 10:28:46 2017 +0000
@@ -0,0 +1,627 @@
+#include "MIUN.LoRa.h"
+#include "mbed.h"
+#include "mDot.h"
+#include "MacEvents.h"
+#include "MTSLog.h"
+#include "MTSText.h"
+#include <vector>
+#include <string>
+
+
+MIUN::LoRa::LoRa():macCommandEvent(*this)
+{
+
+    //1. Set dot
+    dot = mDot::getInstance();
+    
+    //2. Register Event
+     dot->setEvents(&macCommandEvent);
+     
+    //3. getDefaultSleepTime
+    //defaultSleepTime = readSleepTime();
+    defaultSleepTime = 30; //seconds
+
+    //4. set batteryLevel
+    batteryLevel = 255;
+    
+    //5. Print Version
+    logInfo("Library Version: %s", dot->getId().c_str());
+
+    
+}
+
+void MIUN::LoRa::reset()
+{
+    // start from a well-known state
+    logInfo("defaulting Dot configuration");
+    dot->resetConfig();
+    dot->resetNetworkSession();
+}
+
+
+/*** public method ***/
+
+std::string MIUN::LoRa::receive(int* port)
+{
+    int32_t ret;
+    vector<uint8_t> receive_data;
+     if ((ret = dot->recv(receive_data)) != mDot::MDOT_OK) 
+    {
+            logError("failed to recv: [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
+            return "";
+    } 
+    else 
+    {
+            //1. Set Receive Payload
+            string str(receive_data.begin(),receive_data.end());
+            //2. Set Receive Port
+            *port = receivePort;
+            receivePort = -1;
+            return str;
+    }           
+}
+
+
+bool MIUN::LoRa::send_basic(std::string input_data)
+{
+    int32_t ret;
+    vector<uint8_t> sent_data;
+     logInfo("Send with %s", dot->getDateRateDetails(dot->getTxDataRate()).c_str());
+    for (std::string::iterator it = input_data.begin(); it != input_data.end(); it++)
+    {
+        sent_data.push_back((uint8_t) *it);   
+    }
+     std::vector<uint8_t> sendData;
+        sendData.push_back(0x80); 
+    /*
+    for (int i=0;i<commandLength;i++)
+    {
+        sendData.push_back(command[i]);   
+    }
+    */
+    if (dot->injectMacCommand(sendData) != mDot::MDOT_OK) 
+    {
+        logError("failed to injectMacCommand");
+    }
+    else
+    {
+        logInfo("injectMacCommand Successful");
+    }
+    if ((ret = dot->send(sent_data)) != mDot::MDOT_OK) 
+    {
+        logError("failed to send", ret, mDot::getReturnCodeString(ret).c_str());
+        return false;
+    } 
+    else 
+    {
+        logInfo("successfully sent data to gateway");
+        return true;
+    }
+
+}
+
+std::string  MIUN::LoRa::sendReceive(std::string payload, int port, int* receivePort)
+{
+    if(send(payload,port))
+    {
+        return receive(receivePort);
+    }
+    else
+    {
+        return "";
+    }
+}
+
+
+void MIUN::LoRa::sleep(const uint32_t& interval_s)
+{
+    uint32_t sleep_time = std::max(interval_s*1000, (uint32_t)dot->getNextTxMs()) / 1000;
+        logInfo("sleep %u seconds until next free channel",sleep_time);
+    dot->sleep(sleep_time, mDot::RTC_ALARM, true);
+}
+
+void MIUN::LoRa::sleepWaitingNextFreeChannel()
+{
+    uint32_t sleep_time =std::max((uint32_t)10*1000, (uint32_t)dot->getNextTxMs()) / 1000;
+        logInfo("sleep %u seconds until next free channel",sleep_time);
+    dot->sleep(sleep_time, mDot::RTC_ALARM, false);
+}
+
+void MIUN::LoRa::sleep()
+{
+    if(sleepTime!=0)
+    {
+        sleep(sleepTime);
+    }
+}
+
+bool MIUN::LoRa::joinNetwork ()
+{
+    if (!dot->getNetworkJoinStatus()) 
+    {
+        //1. Try Connect
+       if(tryConnectNet() == false)
+       {
+           return false;
+       }
+        //2. reset SF
+        if(dot->getAdr() == true)
+        {
+            resetSF();
+        }
+    }  
+    return true;
+}
+
+
+
+
+
+ void MIUN::LoRa::networkConfig(std::string network_name, 
+                                std::string network_passphrase, 
+                                uint8_t     retransTimes,
+                                uint8_t     joinDelay,
+                                bool        ADR,
+                                uint8_t     sf)
+{
+    //1. Reset
+    reset();
+    
+    //2.  make sure library logging is turned on
+    dot->setLogLevel(mts::MTSLog::INFO_LEVEL);
+    
+    //3. Change mode to AUTO_OTA
+    changeModeToAUTO_OTA();
+    
+
+    //4. Change network name
+    changeNetworkName(network_name);
+    
+    //5. Change Password
+    changePassword(network_passphrase);
+    
+    //6. Change Ack
+    changeAck(retransTimes);
+    
+    //7. Public Network
+    changePublicNetwork(true);
+    
+    //8. Change Join Delay
+    changeJoinDelay(joinDelay);
+    
+    //9. Set Adapt Datarate
+    changeAdaptSF(ADR);
+    
+    //9. Change sf
+    changeSF(ADR);
+    
+    //10. Save Default Time
+    //saveSleepTime(defaultSleepTime);
+
+    //10. Save Setting
+    saveSetting();
+    
+    
+}
+
+
+/*
+void MIUN::LoRa::saveSleepTime(uint32_t sleepTime)
+{
+     dot->saveUserFile("sleepTm",(void*)&sleepTime,4);
+}
+
+uint32_t MIUN::LoRa::readSleepTime()
+{
+    uint8_t intBuffer[4];
+    dot->readUserFile("sleepTm",intBuffer,4);
+    return sleepTime = (((uint32_t)intBuffer[3])<<24)+
+                         (((uint32_t)intBuffer[2])<<16)+
+                         (((uint32_t)intBuffer[1])<<8)+
+                         intBuffer[0];
+}
+*/
+
+bool MIUN::LoRa::checkSleepTime(uint32_t sleepTime)
+{
+    if(sleepTime<60*60*24)
+    {
+        return true;
+    }
+    logError("Wrong Sleep Time");
+    return false;
+}  
+
+
+    
+void MIUN::LoRa::setFPending(bool isPending)
+{
+     uint8_t macArray[50]={'\0'};
+     memcpy(macArray,dot->_mote.GetMac(),50);
+     for(int i=0;i<50;i++)
+     {
+         logError("mac: %.2x", macArray[i]);
+
+     }
+
+}
+
+void MIUN::LoRa::setSleepTime(uint32_t inSleepTime)
+{
+    if(checkSleepTime(inSleepTime)==true)
+    {
+        sleepTime = inSleepTime;
+        logInfo("SetSleepTimeTo: %u", inSleepTime);
+    }
+    
+}
+
+void MIUN::LoRa::changeSF(const uint8_t& sf)
+{
+    uint8_t current_SF = dot->getTxDataRate();
+    if (current_SF != sf) 
+    {
+        logInfo("changing spreading factor from %s to %s", dot->getDateRateDetails(current_SF).c_str(), dot->getDateRateDetails(sf).c_str());
+        if (dot->setTxDataRate(sf)!= mDot::MDOT_OK) {
+            logError("failed to change SF to %s", dot->getDateRateDetails(sf).c_str());
+        }
+    }
+}
+
+void MIUN::LoRa::changeAdaptSF(bool adaptSF)
+{
+    bool current_adaptSF = dot->getAdr();
+    if (current_adaptSF != adaptSF) 
+    {
+        logInfo("changing AdaptSF from %s to %s", current_adaptSF ? "on" : "off", adaptSF ? "on" : "off");
+        if (dot->setAdr(adaptSF) != mDot::MDOT_OK) {
+            logError("failed to set AdaptSF to %s", adaptSF ? "on" : "off");
+        }
+    }
+}
+
+void MIUN::LoRa::changePublicNetwork(bool public_network)
+{
+    bool current_public_network = dot->getPublicNetwork();
+    if (current_public_network != public_network) 
+    {
+        logInfo("changing public network from %s to %s", current_public_network ? "on" : "off", public_network ? "on" : "off");
+        if (dot->setPublicNetwork(public_network) != mDot::MDOT_OK) {
+            logError("failed to set public network to %s", public_network ? "on" : "off");
+        }
+    }
+}
+
+void MIUN::LoRa::changeModeToAUTO_OTA()
+{
+    if (dot->getJoinMode() != mDot::AUTO_OTA) 
+    {
+        logInfo("changing network join mode to AUTO_OTA");
+        if (dot->setJoinMode(mDot::AUTO_OTA) != mDot::MDOT_OK) 
+        {
+            logError("failed to set network join mode to AUTO_OTA");
+        }
+    }
+}
+
+void MIUN::LoRa::changePassword(const std::string& network_passphrase)
+{
+    std::string current_network_passphrase = dot->getNetworkPassphrase();
+    if (current_network_passphrase != network_passphrase) 
+    {
+        logInfo("changing network passphrase from \"%s\" to \"%s\"", current_network_passphrase.c_str(), network_passphrase.c_str());
+        if (dot->setNetworkPassphrase(network_passphrase) != mDot::MDOT_OK) 
+        {
+            logError("failed to set network passphrase to \"%s\"", network_passphrase.c_str());
+        }
+    }
+}
+
+void MIUN::LoRa::changeNetworkName(const std::string& network_name)
+{
+    std::string current_network_name = dot->getNetworkName();
+    if (current_network_name != network_name) 
+    {
+        if (current_network_name != network_name) 
+        {
+            logInfo("changing network name from \"%s\" to \"%s\"", current_network_name.c_str(), network_name.c_str());
+            if (dot->setNetworkName(network_name) != mDot::MDOT_OK) {
+                logError("failed to set network name to \"%s\"", network_name.c_str());
+            }
+        }
+    }
+}
+
+void MIUN::LoRa::changeJoinDelay(uint8_t joinDelay)
+{
+    logInfo("changing join delay");
+    if (dot->setJoinDelay(joinDelay) != mDot::MDOT_OK) 
+    {
+        logError("failed to set join delay to %u", joinDelay);
+    }
+}
+
+void MIUN::LoRa::changeAck(const uint8_t& retries)
+{
+    logInfo("Set Ack to %u", retries);
+    if (dot->setAck(retries) != mDot::MDOT_OK) {
+        logError("failed to set  Ack to %u", retries);
+    }
+}
+
+
+
+void MIUN::LoRa::saveSetting()
+{
+    logInfo("saving configuration");
+    if (!dot->saveConfig()) 
+    {
+        logError("failed to save configuration");
+    }
+}
+
+void MIUN::LoRa::showInfo()
+{
+        // display configuration and library version information
+    logInfo("=====================");
+    logInfo("general configuration");
+    logInfo("=====================");
+    logInfo("version ------------------ %s", dot->getId().c_str());
+    logInfo("device ID/EUI ------------ %s", mts::Text::bin2hexString(dot->getDeviceId()).c_str());
+    logInfo("frequency band ----------- %s", mDot::FrequencyBandStr(dot->getFrequencyBand()).c_str());
+    if (dot->getFrequencySubBand() != mDot::FB_EU868) {
+        logInfo("frequency sub band ------- %u", dot->getFrequencySubBand());
+    }
+    logInfo("public network ----------- %s", dot->getPublicNetwork() ? "on" : "off");
+    logInfo("=========================");
+    logInfo("credentials configuration");
+    logInfo("=========================");
+    logInfo("device class ------------- %s", dot->getClass().c_str());
+    logInfo("network join mode -------- %s", mDot::JoinModeStr(dot->getJoinMode()).c_str());
+    if (dot->getJoinMode() == mDot::MANUAL || dot->getJoinMode() == mDot::PEER_TO_PEER) {
+    logInfo("network address ---------- %s", mts::Text::bin2hexString(dot->getNetworkAddress()).c_str());
+    logInfo("network session key------- %s", mts::Text::bin2hexString(dot->getNetworkSessionKey()).c_str());
+    logInfo("data session key---------- %s", mts::Text::bin2hexString(dot->getDataSessionKey()).c_str());
+    } else {
+    logInfo("network name ------------- %s", dot->getNetworkName().c_str());
+    logInfo("network phrase ----------- %s", dot->getNetworkPassphrase().c_str());
+    logInfo("network EUI -------------- %s", mts::Text::bin2hexString(dot->getNetworkId()).c_str());
+    logInfo("network KEY -------------- %s", mts::Text::bin2hexString(dot->getNetworkKey()).c_str());
+    
+    logInfo("session NWK KEY -------------- %s", mts::Text::bin2hexString(dot->getNetworkSessionKey()).c_str());
+    logInfo("session APP KEY -------------- %s", mts::Text::bin2hexString(dot->getDataSessionKey()).c_str());
+    }
+    logInfo("========================");
+    logInfo("communication parameters");
+    logInfo("========================");
+    if (dot->getJoinMode() == mDot::PEER_TO_PEER) {
+    logInfo("TX frequency ------------- %lu", dot->getTxFrequency());
+    } else {
+    logInfo("acks --------------------- %s, %u attempts", dot->getAck() > 0 ? "on" : "off", dot->getAck());
+    }
+    logInfo("TX datarate -------------- %s", mDot::DataRateStr(dot->getTxDataRate()).c_str());
+    logInfo("TX power ----------------- %lu dBm", dot->getTxPower());
+    logInfo("atnenna gain ------------- %u dBm", dot->getAntennaGain());
+    logInfo("channels -------------");
+    std::vector<uint32_t>::iterator channelItreator;
+    uint32_t i=0;
+    for(channelItreator = dot->getChannels().begin();channelItreator!=dot->getChannels().end();channelItreator++)
+    {
+        logInfo("channel(%u) ------------- %u Hz",i++,*channelItreator);
+    }
+}
+
+
+
+
+
+mDot& MIUN::LoRa::getHandler()
+{
+    return *dot;
+}
+
+/*** private function  ***/
+
+bool MIUN::LoRa::tryConnectNet()
+{
+    int32_t j_attempts = 0;
+    int32_t ret = mDot::MDOT_ERROR;
+    
+    // attempt to join the network
+    while (ret != mDot::MDOT_OK) 
+    {
+        logInfo("attempt %d to join network", ++j_attempts);
+        ret = dot->joinNetwork();
+        if (ret != mDot::MDOT_OK) {
+            logError("failed to join network %d:%s It will retry...", ret, mDot::getReturnCodeString(ret).c_str());
+            // in some frequency bands we need to wait until another channel is available before transmitting again
+            uint32_t delay_s = (dot->getNextTxMs() / 1000) + 1;
+            if (delay_s < 2) 
+            {
+                logInfo("waiting %lu s until next free channel", delay_s);
+                wait(delay_s);
+            } else {
+                logInfo("sleeping %lu s until next free channel", delay_s);
+                sleep(delay_s);
+            }
+        }
+        
+        if(j_attempts >3)
+        {
+            logError("failed to join network %d:%s, give up.", ret, mDot::getReturnCodeString(ret).c_str());
+            return false;
+        }
+    }
+    return true;
+}
+
+
+
+bool MIUN::LoRa::send(std::string input_data, int port)
+{
+    //1. Set Port
+    dot->setAppPort(port);
+    //1. if it use ADR
+    if(dot->getAdr() == true)
+    {
+        int i=0;
+        while(!send_basic(input_data))
+        {
+            i++;
+            if(i>3)
+            {
+                // 1. increase SF
+                if(increaseSF()==false)
+                {
+                    //1. Clean Network Session
+                    dot->resetNetworkSession();
+                    //2. Reset SF
+                    resetSF();
+                    tryConnectNet();
+                    return false;
+                }
+            }
+            sleepWaitingNextFreeChannel();      
+        }
+            
+    }
+    else
+    {
+        return send_basic(input_data);
+    }
+    return true;
+}
+
+
+bool MIUN::LoRa::increaseSF()
+{
+    uint8_t current_SF = dot->getTxDataRate();
+    if(current_SF>0)
+    {
+        changeSF(--current_SF);
+        return true;
+    }
+    return false;
+}
+
+bool MIUN::LoRa::decreaseSF()
+{
+    uint8_t current_SF = dot->getTxDataRate();
+    if(current_SF<5)
+    {
+        changeSF(++current_SF);
+        return true;
+    }
+    return false;
+}
+
+void MIUN::LoRa::resetSF()
+{
+    changeSF(5);
+}
+
+
+void MIUN::LoRa::setBatteryLevel(uint8_t batteryLevelValue)
+{
+    batteryLevel = batteryLevelValue;
+}
+
+
+
+
+
+
+
+
+MIUN::MacCommandEvent::MacCommandEvent(LoRa& loraHandle):loraHandle(loraHandle)
+{
+}
+
+void MIUN::MacCommandEvent::RxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr, lora::DownlinkControl ctrl, uint8_t slot)
+{
+    /*
+    for(int i=0;i<20;i++)
+    {
+          logInfo("Payload %.2x", payload[i]);
+    }
+    */
+    if(payload[0] == 0xa0 || payload[0] == 0x60)
+    {
+        //1. Process Mac Command        
+        int macCommandLength =  payload[5] & 0x0f;
+        if(macCommandLength>0)
+        {
+            uint8_t macCommand[macCommandLength];
+            memcpy(macCommand,payload+8,macCommandLength);
+            
+            for(int i=0;i<macCommandLength;i++)
+            {
+                logInfo("Mac Command: %.2x", macCommand[i]);
+            }
+
+            switch(macCommand[0])
+            {
+            case decreaseSF:
+            if(macCommandLength == decreaseSF_length)
+            {
+                 processSFDecrease(macCommand);
+            }
+            break;
+            
+            case increaseSF:
+            if(macCommandLength == increaseSF_length)
+            {
+                processSFIncrease(macCommand);
+            }
+            break;
+            
+            case changeSleepTime:
+            if(macCommandLength == changeSleepTime_length)
+            {
+                processChangeSleepTm(macCommand);
+            }
+            break;
+                   
+            }
+        }
+        
+        //2. Receive Port
+        if((size-12-macCommandLength)>0)
+        {
+            loraHandle.receivePort = payload[8+macCommandLength];
+        }
+        else
+        {
+            loraHandle.receivePort = -1;
+        }
+    }
+}
+
+void MIUN::MacCommandEvent::processChangeSleepTm(uint8_t *macCommand)
+{
+        
+        uint32_t sleepTime_s = (((uint32_t)macCommand[4])<<24)+
+                               (((uint32_t)macCommand[3])<<16)+
+                               (((uint32_t)macCommand[2])<<8)+
+                                macCommand[1];
+        logInfo("Change Sleep Time: %u", sleepTime_s);
+        loraHandle.setSleepTime(sleepTime_s);
+        
+}
+
+void MIUN::MacCommandEvent::processSFDecrease(uint8_t *payload)
+{
+    loraHandle.decreaseSF();
+}
+
+void MIUN::MacCommandEvent::processSFIncrease(uint8_t *payload)
+{
+    loraHandle.increaseSF();
+}
+
+uint8_t MIUN::MacCommandEvent::MeasureBattery() 
+{
+     return loraHandle.batteryLevel;
+}
+
+