sends analog data over TTN

Fork of mbed-rtos by mbed official

Files at this revision

API Documentation at this revision

Comitter:
DanL
Date:
Sat Feb 11 17:38:44 2017 +0000
Parent:
96:6d90423c236e
Commit message:
working code for analog temp sensor

Changed in this revision

working_code_before_cleanup.txt Show annotated file Show diff for this revision Revisions of this file
diff -r 6d90423c236e -r e39e0bd6eec5 working_code_before_cleanup.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/working_code_before_cleanup.txt	Sat Feb 11 17:38:44 2017 +0000
@@ -0,0 +1,630 @@
+/** mDot_TTN_DL1
+*
+ * Demo of use of an analog sensor
+ *  Based on is a rough demo of mDot+DHT11 on The Things Network.
+ *  
+ *  As with the original, this code is not indended as a reference design.
+ *  In particular, it lacks:
+ *   (1) power management
+ *   (2) reasonable transmission period 
+ *   (3) adaptive data rate
+ * 
+ * Uses MultiTech mDot developer board http://www.multitech.com/models/94558010LF
+ * Requires a MultiTech MultiConnect Conduit http://www.multitech.com/models/94557203LF
+ * http://www.multitech.net/developer/software/lora/conduit-mlinux-convert-to-basic-packet-forwarder/
+ * http://forum.thethingsnetwork.org/t/setting-up-multitech-conduit-gateway-for-ttn/216/35
+ *
+ * To receive and visualize this data,
+ *  consider using InitialState and the bridge code here:
+ * https://github.com/things-nyc/initial-state-example
+ */
+
+//DL variation -- code compiles before DL work
+
+//DL addition
+#define RBUFFER_LEN 8  //number of stored readings
+#define INIT_BYTE 250;  //first byte of payload
+#define PAYLOAD_LEN   (RBUFFER_LEN + 2)
+//end addition
+
+
+#include "mbed.h"
+#include "mDot.h"
+#include "MTSLog.h"
+#include "MTSText.h"
+#include <string>
+#include <vector>
+
+using namespace mts;
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+
+/** ABP
+ * Register your device and update these values:  --done  dl-mdot-001
+ * https://account.thethingsnetwork.org/
+ */
+uint8_t AppSKey[16]= { 0x98, 0x29, 0xC2, 0xF2, 0xA9, 0x95, 0xD7, 0x6B, 0x3A, 0xDD, 0x66, 0xBB, 0x5C, 0x1C, 0x65, 0xFD };
+uint8_t NwkSKey[16]= { 0xCB, 0xDC, 0x14, 0xE0, 0x79, 0xF4, 0x83, 0x10, 0x09, 0x99, 0x2D, 0x87, 0xCF, 0x1D, 0x9A, 0xD9 };
+uint8_t NetworkAddr[4]= { 0x26, 0x02, 0x19, 0x70 };
+
+//DL additions to globals
+uint8_t readings[RBUFFER_LEN]; // storage for readings
+uint8_t head = 0;  //next place to store a reading (better code possible)
+uint8_t payload[PAYLOAD_LEN]; // this will eventually be mydata[]
+//end of additions
+
+
+// Serial via USB for debugging only  DL relocated here from just before main()
+Serial pc(USBTX,USBRX);
+
+//DL additions to functions
+
+AnalogIn pot_val(PB_1);
+
+char readTemp(void)
+{
+    unsigned short int reading;
+    reading = pot_val.read_u16();  // returns 0 - 0xFFFF in decimal  16 bit read  
+    reading /= 69;  // now in range 0 - 237
+    return reading;
+}
+
+void dataToBuffer (uint8_t newdata) {
+  uint8_t index;
+  readings[head] = newdata;
+  
+  //data is now in readings buffer in order received
+  //insert data in payload current byte first
+  index = head;
+  for (uint8_t i = 0 ; i < RBUFFER_LEN  ; i++) {  // do once for each entry in readings
+    payload[i + 1] = readings[index];  //start insert with second byte
+        if (index == 0) index = RBUFFER_LEN ;
+    index--;
+      }
+      head++;  //set up for next data byte
+  if (head > (RBUFFER_LEN - 1)) head = 0;
+    //insert battery condition byte here -- payload[PAYLOAD_LEN -1] = batt cond  last byte
+     payload[PAYLOAD_LEN -1] = 100;
+  }
+  
+
+
+float decodeTempC(uint8_t c4) { //input is celsius
+  float output;
+  float input = c4;
+  if (c4 <= 240) output =  (float(input / 4) - 10); //temperature in range
+  if (c4 == 241) {
+    pc.printf("below range\n");
+    output =  255;
+  }
+  if (c4 == 242) {
+    pc.printf("above range\n");
+    output =  255;
+  }
+  if (c4 == 243) {
+    pc.printf("no sensor\n");
+    output =  255;
+  }
+  if (c4 == 244) {
+    pc.printf("bad CRC\n");
+    output =  255;
+  }
+  if (c4 >= 245) {
+    pc.printf("unknown code\n");
+    output = 255;
+  }
+  return output;
+}
+
+float decodeTempF(uint8_t c4) { //input is farenheight
+  float output;
+  float input = c4;
+  if (c4 <= 240) output =  (((input / 4) - 10) * 1.8 + 32); //temperature in range
+  if (c4 == 241) {
+    pc.printf("below range\n");
+    output =  255;
+  }
+  if (c4 == 242) {
+    pc.printf("above range\n");
+    output =  255;
+  }
+  if (c4 == 243) {
+    pc.printf("no sensor\n");
+    output =  255;
+  }
+  if (c4 == 244) {
+    pc.printf("bad CRC\n");
+    output =  255;
+  }
+  if (c4 >= 245) {
+    pc.printf("unknown code\n");
+    output = 255;
+  }
+  return output;
+}
+
+//end of DL additions to functions
+
+
+// Some defines for the LoRa configuration
+#define LORA_SF mDot::SF_7
+#define LORA_ACK 0
+#define LORA_TXPOWER 20
+static uint8_t config_frequency_sub_band = 2;
+
+// functions for ensuring network endianness (little-endian)
+uint16_t hton16(const uint16_t x)
+{
+  uint16_t t = x;
+  uint8_t * a = (uint8_t*)&t;
+  a[0] = x>>(8*1);
+  a[1] = x>>(8*0);
+  return t;
+}
+void hton16(uint16_t * x)
+{
+  *x = hton16(*x);
+}
+
+
+/*
+// build a transmit buffer (from https://raw.githubusercontent.com/mcci-catena/Catena4410-Sketches/master/catena4410_sensor1/catena4410_sensor1.ino)
+class TxBuffer_t
+        {
+public:
+        uint8_t buf[32];   // this sets the largest buffer size
+        uint8_t *p;
+
+        TxBuffer_t() : p(buf) {};
+        void begin()
+                {
+                p = buf;
+                }
+        void put(uint8_t c)
+                {
+                if (p < buf + sizeof(buf))
+                        *p++ = c;
+                }
+        void put1u(int32_t v)
+                {
+                if (v > 0xFF)
+                        v = 0xFF;
+                else if (v < 0)
+                        v = 0;
+                put((uint8_t) v);
+                }
+        void put2(uint32_t v)
+                {
+                if (v > 0xFFFF)
+                        v = 0xFFFF;
+
+                put((uint8_t) (v >> 8));
+                put((uint8_t) v);
+                }
+        void put2(int32_t v)
+                {
+                if (v < -0x8000)
+                        v = -0x8000;
+                else if (v > 0x7FFF)
+                        v = 0x7FFF;
+
+                put2((uint32_t) v);
+                }
+        void put3(uint32_t v)
+                {
+                if (v > 0xFFFFFF)
+                        v = 0xFFFFFF;
+
+                put((uint8_t) (v >> 16));
+                put((uint8_t) (v >> 8));
+                put((uint8_t) v);
+                }
+        void put2u(int32_t v)
+                {
+                if (v < 0)
+                        v = 0;
+                else if (v > 0xFFFF)
+                        v = 0xFFFF;
+                put2((uint32_t) v);
+                }
+        void put3(int32_t v)
+                {
+                if (v < -0x800000)
+                        v = -0x800000;
+                else if (v > 0x7FFFFF)
+                        v = 0x7FFFFF;
+                put3((uint32_t) v);
+                }
+        uint8_t *getp(void)
+                {
+                return p;
+                }
+        size_t getn(void)
+                {
+                return p - buf;
+                }
+        uint8_t *getbase(void)
+                {
+                return buf;
+                }
+        void put2sf(float v)
+                {
+                int32_t iv;
+
+                if (v > 32766.5f)
+                        iv = 0x7fff;
+                else if (v < -32767.5f)
+                        iv = -0x8000;
+                else
+                        iv = (int32_t)(v + 0.5f);
+
+                put2(iv);
+                }
+        void put2uf(float v)
+                {
+                uint32_t iv;
+
+                if (v > 65535.5f)
+                        iv = 0xffff;
+                else if (v < 0.5f)
+                        iv = 0;
+                else
+                        iv = (uint32_t)(v + 0.5f);
+
+                put2(iv);
+                }
+        void put1uf(float v)
+                {
+                uint8_t c;
+
+                if (v > 254.5)
+                        c = 0xFF;
+                else if (v < 0.5)
+                        c = 0;
+                else
+                        c = (uint8_t) v;
+
+                put(c);
+                }
+        void putT(float T)
+                {
+                put2sf(T * 256.0f + 0.5f);                
+                }
+        void putRH(float RH)
+                {
+                put1uf((RH / 0.390625f) + 0.5f);
+                }
+        void putV(float V)
+                {
+                put2sf(V * 4096.0f + 0.5f);
+                }
+        void putP(float P)
+                {
+                put2uf(P / 4.0f + 0.5f);
+                }
+        void putLux(float Lux)
+                {
+                put2uf(Lux);
+                }
+        };    */
+
+/* the magic byte at the front of the buffer */
+enum    {
+        FormatSensor1 = 0x11,
+        };
+
+/* the flags for the second byte of the buffer */
+enum    {
+        FlagVbat = 1 << 0,
+        FlagVcc = 1 << 1,
+        FlagTPH = 1 << 2,
+        FlagLux = 1 << 3,
+        FlagWater = 1 << 4,
+        FlagSoilTH = 1 << 5,
+        };
+
+
+// Temperature sensor object
+//#define DHT_PIN PB_1
+//DHT11 dht(DHT_PIN);
+
+
+int main()
+{
+   // TxBuffer_t b;
+    
+    int32_t ret;
+    mDot* dot;
+    std::vector<uint8_t> send_data;
+    std::vector<uint8_t> recv_data;
+    std::vector<uint8_t> nwkSKey;
+    std::vector<uint8_t> appSKey;
+    std::vector<uint8_t> nodeAddr;
+    std::vector<uint8_t> networkAddr;
+
+  //  float temperature = 0.0;
+    uint8_t currentTemp;   //DP
+    payload[0] = INIT_BYTE;  // DL set up initial byte
+
+    pc.baud(115200);
+    pc.printf("TTN mDot LoRa Temperature  & Humidity Sensor\n\r");
+
+    // get a mDot handle
+    dot = mDot::getInstance();
+
+//  dot->setLogLevel(MTSLog::WARNING_LEVEL);
+    dot->setLogLevel(MTSLog::TRACE_LEVEL);
+
+    logInfo("Checking Config");
+
+    // Test if we've already saved the config
+    std::string configNetworkName = dot->getNetworkName();
+
+    uint8_t *it = NwkSKey;
+    for (uint8_t i = 0; i<16; i++)
+        nwkSKey.push_back((uint8_t) *it++);
+        
+    it = AppSKey;
+    for (uint8_t i = 0; i<16; i++)
+        appSKey.push_back((uint8_t) *it++);
+
+    it = NetworkAddr;
+    for (uint8_t i = 0; i<4; i++)
+        networkAddr.push_back((uint8_t) *it++);
+
+    logInfo("Resetting Config");
+    // reset to default config so we know what state we're in
+    dot->resetConfig();
+
+    // Set byte order - AEP less than 1.0.30
+//    dot->setJoinByteOrder(mDot::LSB);
+    dot->setJoinByteOrder(mDot::MSB);       // This is default for > 1.0.30 Conduit
+
+
+
+    logInfo("Set TxPower");
+    if((ret = dot->setTxPower( LORA_TXPOWER )) != mDot::MDOT_OK) {
+        logError("Failed to set Tx Power %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
+    }
+
+    logInfo("Set Public mode");
+    if((ret = dot->setPublicNetwork(true)) != mDot::MDOT_OK) {
+        logError("failed to set Public Mode %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
+    }
+
+    logInfo("Set MANUAL Join mode");
+    if((ret = dot->setJoinMode(mDot::MANUAL)) != mDot::MDOT_OK) {
+        logError("Failed to set MANUAL Join Mode %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
+    }
+
+    logInfo("Set Ack");
+    // 1 retries on Ack, 0 to disable
+    if((ret = dot->setAck( LORA_ACK)) != mDot::MDOT_OK) {
+        logError("Failed to set Ack %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
+    }
+
+    //Not applicable for 868MHz in EU
+    if ((ret = dot->setFrequencySubBand(config_frequency_sub_band)) != mDot::MDOT_OK) {
+        logError("failed to set frequency sub band", ret);
+    }
+
+    logInfo("Set Network Address");
+    if ((ret = dot->setNetworkAddress(networkAddr)) != mDot::MDOT_OK) {
+        logError("Failed to set Network Address %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
+    }
+
+    logInfo("Set Data Session Key");
+    if ((ret = dot->setDataSessionKey(appSKey)) != mDot::MDOT_OK) {
+        logError("Failed to set Data Session Key %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
+    }
+
+    logInfo("Set Network Session Key");
+    if ((ret = dot->setNetworkSessionKey(nwkSKey)) != mDot::MDOT_OK) {
+        logError("Failed to set Network Session Key %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
+    }
+
+    logInfo("Saving Config");
+    // Save config
+    if (! dot->saveConfig()) {
+        logError("failed to save configuration");
+    }
+
+    // Display what is set
+    std::vector<uint8_t> tmp = dot->getNetworkSessionKey();
+    pc.printf("Network Session Key: ");
+    pc.printf("%s\r\n", mts::Text::bin2hexString(tmp, " ").c_str());
+
+    tmp = dot->getDataSessionKey();
+    pc.printf("Data Session Key: ");
+    pc.printf("%s\r\n", mts::Text::bin2hexString(tmp, " ").c_str());
+
+    pc.printf("Device ID ");
+    std::vector<uint8_t> deviceId;
+    deviceId = dot->getDeviceId();
+    for (std::vector<uint8_t>::iterator it = deviceId.begin() ; it != deviceId.end(); ++it)
+        pc.printf("%2.2x",*it );
+    pc.printf("\r\n");
+
+    std::vector<uint8_t> netAddress;
+
+    pc.printf("Network Address ");
+    netAddress = dot->getNetworkAddress();
+    for (std::vector<uint8_t>::iterator it = netAddress.begin() ; it != netAddress.end(); ++it)
+        pc.printf("%2.2x",*it );
+
+    pc.printf("\r\n");
+
+    // Display LoRa parameters
+    // Display label and values in different colours, show pretty values not numeric values where applicable
+    pc.printf("Public Network: %s\r\n", (char*)(dot->getPublicNetwork() ? "Yes" : "No") );
+    pc.printf("Frequency: %s\r\n", (char*)mDot::FrequencyBandStr(dot->getFrequencyBand()).c_str() );
+    pc.printf("Sub Band: %s\r\n", (char*)mDot::FrequencySubBandStr(dot->getFrequencySubBand()).c_str() );
+    pc.printf("Join Mode: %s\r\n", (char*)mDot::JoinModeStr(dot->getJoinMode()).c_str() );
+    pc.printf("Join Retries: %d\r\n", dot->getJoinRetries() );
+    pc.printf("Join Byte Order: %s\r\n", (char*)(dot->getJoinByteOrder() == 0 ? "LSB" : "MSB") );
+    pc.printf("Link Check Count: %d\r\n", dot->getLinkCheckCount() );
+    pc.printf("Link Check Thold: %d\r\n", dot->getLinkCheckThreshold() );
+    pc.printf("Tx Data Rate: %s\r\n", (char*)mDot::DataRateStr(dot->getTxDataRate()).c_str() );
+    pc.printf("Tx Power: %d\r\n", dot->getTxPower() );
+    pc.printf("TxWait: %s, ", (dot->getTxWait() ? "Y" : "N" ));
+    pc.printf("CRC: %s, ", (dot->getCrc() ? "Y" : "N") );
+    pc.printf("Ack: %s\r\n", (dot->getAck() ? "Y" : "N")  );
+
+    logInfo("Joining Network");
+
+    while ((ret = dot->joinNetwork()) != mDot::MDOT_OK) {
+        logError("failed to join network [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
+        wait_ms(dot->getNextTxMs() + 1);
+    }
+
+    logInfo("Joined Network");
+
+  //  char dataBuf[50];
+    uint16_t seq = 0;
+    char * sf_str;
+    while( 1 ) {
+        
+        /* cycle through spreading factors */
+        uint8_t sf;
+        switch (seq % 4) {
+            case 0:
+                sf = mDot::SF_7;
+                sf_str = "SF7";
+                break;
+            case 1:
+                sf = mDot::SF_8;
+                sf_str = "SF8";
+                break;
+            case 2:
+                sf = mDot::SF_9;
+                sf_str = "SF9";
+                break;
+            case 3:
+                sf = mDot::SF_10;
+                sf_str = "SF10";
+                break;
+        }        
+        // Set Spreading Factor, higher is lower data rate, smaller packets but longer range
+        // Lower is higher data rate, larger packets and shorter range.
+        logInfo("Set SF: %s",sf_str);
+        if((ret = dot->setTxDataRate( sf )) != mDot::MDOT_OK) {
+            logError("Failed to set SF %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
+        }
+        
+        /* set default data values */
+      //  int temp = 0;
+    //    int humid = -1;
+        
+        /* read from sensor */
+    /*    int r = dht.readData();
+        switch (r) {
+            case DHT11::OK:
+            {
+                temp = dht.readTemperature();
+                humid = dht.readHumidity();
+                pc.printf("[DHT] T %d degC   H %d %%\r\n",temp,humid);
+                break;
+            }
+            default:
+            {
+                pc.printf("[DHT] ERROR %d\r\n",r);
+                break;
+            }
+        };  */
+        
+        /* build packet */
+    /*    b.begin();
+        uint8_t flag = 0;
+        b.put(FormatSensor1);
+        uint8_t * const pFlag = b.getp(); // save pointer to flag location
+        b.put(0x00); // placeholder for flags
+     */   
+   /*     // TODO: read battery voltage 
+        b.putV(13.8);
+        flag |= FlagVbat;
+        
+        // TODO: read from Bme280 sensor:
+        b.putT(27.0); // air temp
+        b.putP(1010.0); // air pressure
+        b.putRH(66.0); // air humidity
+        flag |= FlagTPH;
+        
+        // TODO: read from light sensor
+        b.putLux(1234); // ambient light
+        flag |= FlagLux;
+        
+        // TODO: read water temperature
+        b.putT(22.0); // water temperature
+        flag |= FlagWater;
+        
+        // TODO: read soil sensor
+        b.putT(25.2); // soil temperature
+        b.putRH(82.0); // soil humidity
+        flag |= FlagSoilTH;
+        
+        // write flag byte
+        *pFlag = flag;
+        
+        */
+        //DL stuff added
+        
+  //DL additions
+  
+  currentTemp = readTemp();
+   pc.printf(" %.2f \n", decodeTempC(currentTemp));   //for debugging- returns degrees  celsius as a float
+  pc.printf(" %.2f \n", decodeTempF(currentTemp));  //for debugging- returns degrees  farenheight as a float
+  //put recent readings into a buffer with most recent data first
+ dataToBuffer (currentTemp); //adds data to buffer and payload
+ 
+ //print payload for debugging
+ pc.printf(" %d \n", currentTemp);                                            
+ pc.printf("Payload    ");
+ for (uint8_t i = 0 ; i < PAYLOAD_LEN  ; i++){
+    pc.printf("%d ",payload[i]);                                
+        pc.printf("  ");
+       }
+ pc.printf("\n");
+//end of payload printout
+
+  //wait_ms(1500);
+        
+        //end of DL adds
+        
+        
+        /* load vector */
+       /* send_data.clear();
+    /    uint8_t c;
+        int n = b.getn();
+        for( int i=0; i< n; i++ ) {
+            c = b.buf[i];
+            send_data.push_back( c );
+        }*/
+        
+        
+        //DL Load Veector from HS Payload
+        send_data.clear();
+        uint8_t c;
+         for( int i=0; i< PAYLOAD_LEN ; i++ ) {
+            c = payload[i];
+            send_data.push_back( c );
+        }
+
+        /* send packet */
+        if ((ret = dot->send(send_data)) != mDot::MDOT_OK) {
+            logError("failed to send: [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
+        } else {
+            logInfo("data len: %d,  send data: %s", PAYLOAD_LEN, Text::bin2hexString(send_data).c_str());  //PAYLOAD_LEN constant instead of b length variable
+        }
+
+        /* sleep */
+        uint32_t sleep_time = MAX((dot->getNextTxMs() / 1000), 10 /* use 6000 for 10min */);
+        logInfo("going to sleep for %d seconds", sleep_time);
+        wait_ms(10*1000);
+        
+        seq++;
+    }
+
+    return 0;
+}