Two way data over LoRaWAN using Multitech mDot

Dependencies:   libmDot-mbed5

This is example firmware for the Multitech mDot. It demonstrates how to:

  • Do two-way data.
  • Sleep aggressively and only wake up when the wake-up pin is triggered.
  • Handle errors, retries and duty cycle errors.
  • Cache data in non-volatile storage.

Based on mbed OS 5.1, hard faults against mbed OS 5.3 unfortunately. Can be compiled with GCC and ARMCC (but not IAR).

To do a new transmission, short pin D6 / PA_1.

Committer:
Jan Jongboom
Date:
Tue Jan 03 16:05:47 2017 +0000
Revision:
2:ff17ce021cfb
Parent:
0:20fbd6f66b11
Child:
3:ac5101a47080
Switch to OTA

Who changed what in which revision?

UserRevisionLine numberNew contents of line
janjongboom 0:20fbd6f66b11 1 #include "mbed.h"
janjongboom 0:20fbd6f66b11 2 #include "mDot.h"
janjongboom 0:20fbd6f66b11 3 #include "MTSLog.h"
janjongboom 0:20fbd6f66b11 4 #include <string>
janjongboom 0:20fbd6f66b11 5 #include <vector>
janjongboom 0:20fbd6f66b11 6 #include <algorithm>
janjongboom 0:20fbd6f66b11 7 #include "mbed.h"
janjongboom 0:20fbd6f66b11 8 #include "parse_keys.h"
janjongboom 0:20fbd6f66b11 9
janjongboom 0:20fbd6f66b11 10 #define BUILTIN_LED_ON 0
janjongboom 0:20fbd6f66b11 11 #define BUILTIN_LED_OFF 1
janjongboom 0:20fbd6f66b11 12
Jan Jongboom 2:ff17ce021cfb 13 static const char APP_EUI[] = "BE7A000000000393";
Jan Jongboom 2:ff17ce021cfb 14 static const char APP_KEY[] = "CF977DE56163FB1055A530CF7B82A56A";
janjongboom 0:20fbd6f66b11 15
janjongboom 0:20fbd6f66b11 16 static mDot* dot;
janjongboom 0:20fbd6f66b11 17
janjongboom 0:20fbd6f66b11 18 // so we have some state
janjongboom 0:20fbd6f66b11 19 static uint16_t counter = 0; // always persisted to non-volatile mem
janjongboom 0:20fbd6f66b11 20
janjongboom 0:20fbd6f66b11 21 static bool woke_from_interrupt = false;
janjongboom 0:20fbd6f66b11 22
janjongboom 0:20fbd6f66b11 23 static InterruptIn btn(PA_1); /* D6 */
janjongboom 0:20fbd6f66b11 24 static DigitalOut led(PC_13, BUILTIN_LED_OFF); /* D2 */
janjongboom 0:20fbd6f66b11 25
janjongboom 0:20fbd6f66b11 26 static void read_counter() {
janjongboom 0:20fbd6f66b11 27 char buffer[2];
janjongboom 0:20fbd6f66b11 28 bool res = dot->readUserFile("counter", &buffer, 2);
janjongboom 0:20fbd6f66b11 29 if (res) {
janjongboom 0:20fbd6f66b11 30 counter = (buffer[0] << 8) + buffer[1];
janjongboom 0:20fbd6f66b11 31 }
janjongboom 0:20fbd6f66b11 32 else {
janjongboom 0:20fbd6f66b11 33 counter = 0;
janjongboom 0:20fbd6f66b11 34 }
janjongboom 0:20fbd6f66b11 35 }
janjongboom 0:20fbd6f66b11 36
janjongboom 0:20fbd6f66b11 37 static void up_counter() {
janjongboom 0:20fbd6f66b11 38 logInfo("up counter");
janjongboom 0:20fbd6f66b11 39
janjongboom 0:20fbd6f66b11 40 read_counter();
janjongboom 0:20fbd6f66b11 41
janjongboom 0:20fbd6f66b11 42 counter++;
janjongboom 0:20fbd6f66b11 43
janjongboom 0:20fbd6f66b11 44 char buffer[2];
janjongboom 0:20fbd6f66b11 45 buffer[0] = counter >> 8 & 0xff;
janjongboom 0:20fbd6f66b11 46 buffer[1] = counter & 0xff;
janjongboom 0:20fbd6f66b11 47
janjongboom 0:20fbd6f66b11 48 logInfo("new counter value is: %d", counter);
janjongboom 0:20fbd6f66b11 49
janjongboom 0:20fbd6f66b11 50 dot->saveUserFile("counter", &buffer, 2);
janjongboom 0:20fbd6f66b11 51 }
janjongboom 0:20fbd6f66b11 52
janjongboom 0:20fbd6f66b11 53 static void btn_rise() {
janjongboom 0:20fbd6f66b11 54 woke_from_interrupt = true; // will be woken by STM32
janjongboom 0:20fbd6f66b11 55 }
janjongboom 0:20fbd6f66b11 56
janjongboom 0:20fbd6f66b11 57 static bool send_data(void) {
janjongboom 0:20fbd6f66b11 58 int32_t ret;
janjongboom 0:20fbd6f66b11 59
janjongboom 0:20fbd6f66b11 60 std::vector<uint8_t> data;
janjongboom 0:20fbd6f66b11 61 data.push_back(counter >> 8 & 0xff);
janjongboom 0:20fbd6f66b11 62 data.push_back(counter & 0xff);
janjongboom 0:20fbd6f66b11 63
janjongboom 0:20fbd6f66b11 64 logInfo("sending %d bytes", data.size());
janjongboom 0:20fbd6f66b11 65 if ((ret = dot->send(data)) != mDot::MDOT_OK) {
janjongboom 0:20fbd6f66b11 66 logError("failed to send %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
janjongboom 0:20fbd6f66b11 67 return false;
janjongboom 0:20fbd6f66b11 68 } else {
janjongboom 0:20fbd6f66b11 69 logInfo("successfully sent data to gateway");
janjongboom 0:20fbd6f66b11 70
janjongboom 0:20fbd6f66b11 71 std::vector<uint8_t> recv_data;
janjongboom 0:20fbd6f66b11 72 if ((ret = dot->recv(recv_data)) != mDot::MDOT_OK) {
janjongboom 0:20fbd6f66b11 73 logError("failed to recv %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
janjongboom 0:20fbd6f66b11 74 return true; // sending succeeded, just recv failed
janjongboom 0:20fbd6f66b11 75 }
Jan Jongboom 2:ff17ce021cfb 76
janjongboom 0:20fbd6f66b11 77 if (recv_data.size() > 0) {
janjongboom 0:20fbd6f66b11 78 printf("[INFO] received %d bytes:", recv_data.size());
janjongboom 0:20fbd6f66b11 79 for (size_t ix = 0; ix < recv_data.size(); ix++) {
janjongboom 0:20fbd6f66b11 80 printf(" %02x", recv_data[ix]);
janjongboom 0:20fbd6f66b11 81 }
janjongboom 0:20fbd6f66b11 82 printf("\r\n");
Jan Jongboom 2:ff17ce021cfb 83
janjongboom 0:20fbd6f66b11 84 if (recv_data[0] == 1) {
janjongboom 0:20fbd6f66b11 85 led = BUILTIN_LED_ON;
janjongboom 0:20fbd6f66b11 86 }
janjongboom 0:20fbd6f66b11 87 else {
janjongboom 0:20fbd6f66b11 88 led = BUILTIN_LED_OFF;
janjongboom 0:20fbd6f66b11 89 }
janjongboom 0:20fbd6f66b11 90 }
Jan Jongboom 2:ff17ce021cfb 91
janjongboom 0:20fbd6f66b11 92 return true;
janjongboom 0:20fbd6f66b11 93 }
janjongboom 0:20fbd6f66b11 94 }
janjongboom 0:20fbd6f66b11 95
janjongboom 0:20fbd6f66b11 96 static void wakeUpCallback() {
janjongboom 0:20fbd6f66b11 97 logInfo("woke up, fromInterrupt=%d", woke_from_interrupt);
Jan Jongboom 2:ff17ce021cfb 98
janjongboom 0:20fbd6f66b11 99 bool wfi = woke_from_interrupt;
Jan Jongboom 2:ff17ce021cfb 100
janjongboom 0:20fbd6f66b11 101 // if we were woken up by RTC_ALARM, first up the counter
janjongboom 0:20fbd6f66b11 102 if (wfi) {
janjongboom 0:20fbd6f66b11 103 // reset the interrupt var
janjongboom 0:20fbd6f66b11 104 woke_from_interrupt = false;
janjongboom 0:20fbd6f66b11 105
janjongboom 0:20fbd6f66b11 106 up_counter();
janjongboom 0:20fbd6f66b11 107 }
Jan Jongboom 2:ff17ce021cfb 108
janjongboom 0:20fbd6f66b11 109
janjongboom 0:20fbd6f66b11 110 bool sent = send_data();
janjongboom 0:20fbd6f66b11 111 // not sent? try again in 5 minutes...
janjongboom 0:20fbd6f66b11 112 if (!sent) {
janjongboom 0:20fbd6f66b11 113 uint32_t sleep_time = 5 * 60;
Jan Jongboom 2:ff17ce021cfb 114
janjongboom 0:20fbd6f66b11 115 // if woke from button press, check duty cycle first...
janjongboom 0:20fbd6f66b11 116 if (wfi) {
janjongboom 0:20fbd6f66b11 117 // hmm.. something went wrong. Probably duty cycle, see next Tx frame
janjongboom 0:20fbd6f66b11 118 // get the next transmission frame (in whole seconds)
janjongboom 0:20fbd6f66b11 119 sleep_time = ceil(static_cast<float>(dot->getNextTxMs()) / 1000.0f);
Jan Jongboom 2:ff17ce021cfb 120
janjongboom 0:20fbd6f66b11 121 // Tx window open, but no success? Try again in 30s.
janjongboom 0:20fbd6f66b11 122 if (sleep_time == 0) sleep_time = 30;
janjongboom 0:20fbd6f66b11 123 }
Jan Jongboom 2:ff17ce021cfb 124
janjongboom 0:20fbd6f66b11 125 logInfo("Going back to sleep (RTC_ALARM), time=%d", sleep_time);
janjongboom 0:20fbd6f66b11 126 dot->sleep(sleep_time, mDot::RTC_ALARM, false);
janjongboom 0:20fbd6f66b11 127 }
janjongboom 0:20fbd6f66b11 128 else {
janjongboom 0:20fbd6f66b11 129 logInfo("Going back to sleep (INTERRUPT)");
janjongboom 0:20fbd6f66b11 130
janjongboom 0:20fbd6f66b11 131 // go back to sleep (wait for an interrupt to happen)
janjongboom 0:20fbd6f66b11 132 dot->sleep(0, mDot::INTERRUPT, false);
janjongboom 0:20fbd6f66b11 133 }
janjongboom 0:20fbd6f66b11 134 }
janjongboom 0:20fbd6f66b11 135
janjongboom 0:20fbd6f66b11 136
janjongboom 0:20fbd6f66b11 137 int main() {
janjongboom 0:20fbd6f66b11 138 int32_t ret;
janjongboom 0:20fbd6f66b11 139 printf("Entering main()\r\n");
janjongboom 0:20fbd6f66b11 140
janjongboom 0:20fbd6f66b11 141 btn.rise(&btn_rise);
janjongboom 0:20fbd6f66b11 142
janjongboom 0:20fbd6f66b11 143 // get a mDot handle
janjongboom 0:20fbd6f66b11 144 dot = mDot::getInstance();
janjongboom 0:20fbd6f66b11 145
janjongboom 0:20fbd6f66b11 146 dot->setLogLevel(mts::MTSLog::DEBUG_LEVEL);
janjongboom 0:20fbd6f66b11 147
janjongboom 0:20fbd6f66b11 148 // print library version information
janjongboom 0:20fbd6f66b11 149 logInfo("version: %s", dot->getId().c_str());
janjongboom 0:20fbd6f66b11 150
Jan Jongboom 2:ff17ce021cfb 151 std::vector<uint8_t> devEui = dot->getDeviceId();
Jan Jongboom 2:ff17ce021cfb 152 logInfo("device eui: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
Jan Jongboom 2:ff17ce021cfb 153 devEui[0], devEui[1], devEui[2], devEui[3], devEui[4], devEui[5], devEui[6], devEui[7]);
Jan Jongboom 2:ff17ce021cfb 154
janjongboom 0:20fbd6f66b11 155 //*******************************************
janjongboom 0:20fbd6f66b11 156 // configuration
janjongboom 0:20fbd6f66b11 157 //*******************************************
janjongboom 0:20fbd6f66b11 158 // reset to default config so we know what state we're in
janjongboom 0:20fbd6f66b11 159 dot->resetConfig();
janjongboom 0:20fbd6f66b11 160
janjongboom 0:20fbd6f66b11 161 logInfo("frequencyBand: %d", dot->getFrequencyBand());
janjongboom 0:20fbd6f66b11 162
janjongboom 0:20fbd6f66b11 163 // set up the mDot with our network information: frequency sub band, network name, and network password
janjongboom 0:20fbd6f66b11 164 // these can all be saved in NVM so they don't need to be set every time - see mDot::saveConfig()
janjongboom 0:20fbd6f66b11 165
janjongboom 0:20fbd6f66b11 166 logInfo("setting public network");
janjongboom 0:20fbd6f66b11 167 if ((ret = dot->setPublicNetwork(true)) != mDot::MDOT_OK) {
janjongboom 0:20fbd6f66b11 168 logError("failed to set public network %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
janjongboom 0:20fbd6f66b11 169 }
janjongboom 0:20fbd6f66b11 170
janjongboom 0:20fbd6f66b11 171 logInfo("setting tx power to 20");
janjongboom 0:20fbd6f66b11 172 if ((ret = dot->setTxPower(18)) != mDot::MDOT_OK) {
janjongboom 0:20fbd6f66b11 173 logError("failed to set tx power %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
janjongboom 0:20fbd6f66b11 174 }
janjongboom 0:20fbd6f66b11 175
janjongboom 0:20fbd6f66b11 176 // set up the network keys
Jan Jongboom 2:ff17ce021cfb 177 ParseKeys::initializeOta(dot, APP_EUI, APP_KEY);
janjongboom 0:20fbd6f66b11 178
janjongboom 0:20fbd6f66b11 179 // a higher spreading factor allows for longer range but lower throughput
janjongboom 0:20fbd6f66b11 180 // in the 915 (US) frequency band, spreading factors 7 - 10 are available
janjongboom 0:20fbd6f66b11 181 // in the 868 (EU) frequency band, spreading factors 7 - 12 are available
janjongboom 0:20fbd6f66b11 182 logInfo("setting TX spreading factor");
janjongboom 0:20fbd6f66b11 183 if ((ret = dot->setTxDataRate(mDot::SF_9)) != mDot::MDOT_OK) {
janjongboom 0:20fbd6f66b11 184 logError("failed to set TX datarate %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
janjongboom 0:20fbd6f66b11 185 }
janjongboom 0:20fbd6f66b11 186
janjongboom 0:20fbd6f66b11 187 // request receive confirmation of packets from the gateway
janjongboom 0:20fbd6f66b11 188 logInfo("enabling ACKs");
janjongboom 0:20fbd6f66b11 189 if ((ret = dot->setAck(1)) != mDot::MDOT_OK) {
janjongboom 0:20fbd6f66b11 190 logError("failed to enable ACKs %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
janjongboom 0:20fbd6f66b11 191 }
janjongboom 0:20fbd6f66b11 192
janjongboom 0:20fbd6f66b11 193 logInfo("enabling ADR");
janjongboom 0:20fbd6f66b11 194 if ((ret = dot->setAdr(1)) != mDot::MDOT_OK) {
janjongboom 0:20fbd6f66b11 195 logError("failed to enable ADR %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
janjongboom 0:20fbd6f66b11 196 }
janjongboom 0:20fbd6f66b11 197
janjongboom 0:20fbd6f66b11 198 // save this configuration to the mDot's NVM
janjongboom 0:20fbd6f66b11 199 logInfo("saving config");
janjongboom 0:20fbd6f66b11 200 if (! dot->saveConfig()) {
janjongboom 0:20fbd6f66b11 201 logError("failed to save configuration");
janjongboom 0:20fbd6f66b11 202 }
janjongboom 0:20fbd6f66b11 203
Jan Jongboom 2:ff17ce021cfb 204 // OTA JOIN sequence, remove when using personalized mode
Jan Jongboom 2:ff17ce021cfb 205 logInfo("joining network");
Jan Jongboom 2:ff17ce021cfb 206 if ((ret = dot->joinNetwork()) != mDot::MDOT_OK ) {
Jan Jongboom 2:ff17ce021cfb 207 logError("failed to join network %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
Jan Jongboom 2:ff17ce021cfb 208 return false;
Jan Jongboom 2:ff17ce021cfb 209 }
Jan Jongboom 2:ff17ce021cfb 210 logInfo("joined network successfully");
Jan Jongboom 2:ff17ce021cfb 211
janjongboom 0:20fbd6f66b11 212 //*******************************************
janjongboom 0:20fbd6f66b11 213 // end of configuration
janjongboom 0:20fbd6f66b11 214 //*******************************************
janjongboom 0:20fbd6f66b11 215
janjongboom 0:20fbd6f66b11 216 read_counter();
janjongboom 0:20fbd6f66b11 217
janjongboom 0:20fbd6f66b11 218 dot->setWakeupCallback(&wakeUpCallback);
janjongboom 0:20fbd6f66b11 219
janjongboom 0:20fbd6f66b11 220 dot->sleep(0, mDot::INTERRUPT, false);
janjongboom 0:20fbd6f66b11 221
janjongboom 0:20fbd6f66b11 222 while (true) {
janjongboom 0:20fbd6f66b11 223 wait_ms(1000);
janjongboom 0:20fbd6f66b11 224 }
janjongboom 0:20fbd6f66b11 225 }