sends analog data over TTN
Fork of mbed-rtos by
Revision 124:e39e0bd6eec5, committed 2017-02-11
- 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; +}