├── .gitattributes ├── .gitignore └── Nodes ├── Dragino └── HelloWorld │ └── HelloWorld.ino └── TTN-Tester └── TTN-Tester.ino /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /Nodes/Dragino/HelloWorld/HelloWorld.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | // MIT License 4 | // https://github.com/gonzalocasas/arduino-uno-dragino-lorawan/blob/master/LICENSE 5 | // Based on examples from https://github.com/matthijskooijman/arduino-lmic 6 | // Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman 7 | 8 | // Adaptions: Andreas Spiess 9 | 10 | #include 11 | #include 12 | //#include 13 | 14 | #ifdef CREDENTIALS 15 | static const u1_t NWKSKEY[16] = NWKSKEY1; 16 | static const u1_t APPSKEY[16] = APPSKEY1; 17 | static const u4_t DEVADDR = DEVADDR1; 18 | #else 19 | static const u1_t NWKSKEY[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; 20 | static const u1_t APPSKEY[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; 21 | static const u4_t DEVADDR = 0x00000000; 22 | #endif 23 | 24 | // These callbacks are only used in over-the-air activation, so they are 25 | // left empty here (we cannot leave them out completely unless 26 | // DISABLE_JOIN is set in config.h, otherwise the linker will complain). 27 | void os_getArtEui (u1_t* buf) { } 28 | void os_getDevEui (u1_t* buf) { } 29 | void os_getDevKey (u1_t* buf) { } 30 | 31 | static osjob_t sendjob; 32 | 33 | // Schedule TX every this many seconds (might become longer due to duty 34 | // cycle limitations). 35 | const unsigned TX_INTERVAL = 20; 36 | 37 | // Pin mapping Dragino Shield 38 | const lmic_pinmap lmic_pins = { 39 | .nss = 10, 40 | .rxtx = LMIC_UNUSED_PIN, 41 | .rst = 9, 42 | .dio = {2, 6, 7}, 43 | }; 44 | void onEvent (ev_t ev) { 45 | if (ev == EV_TXCOMPLETE) { 46 | Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); 47 | // Schedule next transmission 48 | os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send); 49 | } 50 | } 51 | 52 | void do_send(osjob_t* j){ 53 | // Payload to send (uplink) 54 | static uint8_t message[] = "hi"; 55 | 56 | // Check if there is not a current TX/RX job running 57 | if (LMIC.opmode & OP_TXRXPEND) { 58 | Serial.println(F("OP_TXRXPEND, not sending")); 59 | } else { 60 | // Prepare upstream data transmission at the next possible time. 61 | LMIC_setTxData2(1, message, sizeof(message)-1, 0); 62 | Serial.println(F("Sending uplink packet...")); 63 | } 64 | // Next TX is scheduled after TX_COMPLETE event. 65 | } 66 | 67 | void setup() { 68 | Serial.begin(115200); 69 | Serial.println(F("Starting...")); 70 | 71 | // LMIC init 72 | os_init(); 73 | 74 | // Reset the MAC state. Session and pending data transfers will be discarded. 75 | LMIC_reset(); 76 | 77 | // Set static session parameters. 78 | LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY); 79 | 80 | // Disable link check validation 81 | LMIC_setLinkCheckMode(0); 82 | 83 | // TTN uses SF9 for its RX2 window. 84 | LMIC.dn2Dr = DR_SF9; 85 | 86 | // Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library) 87 | LMIC_setDrTxpow(DR_SF12,14); 88 | 89 | // Start job 90 | do_send(&sendjob); 91 | } 92 | 93 | void loop() { 94 | os_runloop_once(); 95 | } 96 | -------------------------------------------------------------------------------- /Nodes/TTN-Tester/TTN-Tester.ino: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman 3 | 4 | Permission is hereby granted, free of charge, to anyone 5 | obtaining a copy of this document and accompanying files, 6 | to do whatever they want with them without any restriction, 7 | including, but not limited to, copying, modification and redistribution. 8 | NO WARRANTY OF ANY KIND IS PROVIDED. 9 | 10 | This example sends a valid LoRaWAN packet with payload "Hello, 11 | world!", using frequency and encryption settings matching those of 12 | the The Things Network. 13 | 14 | This uses ABP (Activation-by-personalisation), where a DevAddr and 15 | Session keys are preconfigured (unlike OTAA, where a DevEUI and 16 | application key is configured, while the DevAddr and session keys are 17 | assigned/generated in the over-the-air-activation procedure). 18 | 19 | Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in 20 | g1, 0.1% in g2), but not the TTN fair usage policy (which is probably 21 | violated by this sketch when left running for longer)! 22 | 23 | To use this sketch, first register your application and device with 24 | the things network, to set or generate a DevAddr, NwkSKey and 25 | AppSKey. Each device should have their own unique values for these 26 | fields. 27 | 28 | Do not forget to define the radio type correctly in config.h. 29 | 30 | This is the software of teh small TTN Tester in the 3-D box 31 | 32 | *******************************************************************************/ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #define CFG_eu868 40 | 41 | // LoRaWAN NwkSKey, network session key 42 | // This is the default Semtech key, which is used by the early prototype TTN 43 | // network. 44 | 45 | #ifdef CREDENTIALS 46 | static const PROGMEM u1_t NWKSKEY[16] = NWKSKEY1; 47 | static const PROGMEM u1_t APPSKEY[16] = APPSKEY1; 48 | static const PROGMEM u4_t DEVADDR = DEVADDR1; 49 | #else 50 | static const PROGMEM u1_t NWKSKEY[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 51 | static const PROGMEM u1_t APPSKEY[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 52 | static const PROGMEM u4_t DEVADDR = 0x00000000; 53 | #endif 54 | 55 | unsigned long entry = millis(); 56 | 57 | #define GREENLED 3 58 | #define REDLED 8 59 | #define SFSWITCH 4 60 | #define RUNPIN 5 61 | 62 | // These callbacks are only used in over-the-air activation, so they are 63 | // left empty here (we cannot leave them out completely unless 64 | // DISABLE_JOIN is set in config.h, otherwise the linker will complain). 65 | void os_getArtEui (u1_t* buf) { } 66 | void os_getDevEui (u1_t* buf) { } 67 | void os_getDevKey (u1_t* buf) { } 68 | 69 | byte counter = 0; 70 | static osjob_t sendjob; 71 | bool switchState = true, oldSwitchState = false; 72 | 73 | // Schedule TX every this many seconds (might become longer due to duty 74 | // cycle limitations). 75 | const unsigned TX_INTERVAL = 60; 76 | 77 | // Pin mapping 78 | const lmic_pinmap lmic_pins = { 79 | .nss = 10, 80 | .rxtx = LMIC_UNUSED_PIN, 81 | .rst = 9, 82 | .dio = {2, 6, 7}, 83 | }; 84 | 85 | void onEvent (ev_t ev) { 86 | Serial.print(os_getTime()); 87 | Serial.print(": "); 88 | switch (ev) { 89 | case EV_SCAN_TIMEOUT: 90 | Serial.println(F("EV_SCAN_TIMEOUT")); 91 | break; 92 | case EV_BEACON_FOUND: 93 | Serial.println(F("EV_BEACON_FOUND")); 94 | break; 95 | case EV_BEACON_MISSED: 96 | Serial.println(F("EV_BEACON_MISSED")); 97 | break; 98 | case EV_BEACON_TRACKED: 99 | Serial.println(F("EV_BEACON_TRACKED")); 100 | break; 101 | case EV_JOINING: 102 | Serial.println(F("EV_JOINING")); 103 | break; 104 | case EV_JOINED: 105 | Serial.println(F("EV_JOINED")); 106 | break; 107 | case EV_RFU1: 108 | Serial.println(F("EV_RFU1")); 109 | break; 110 | case EV_JOIN_FAILED: 111 | Serial.println(F("EV_JOIN_FAILED")); 112 | break; 113 | case EV_REJOIN_FAILED: 114 | Serial.println(F("EV_REJOIN_FAILED")); 115 | break; 116 | 117 | case EV_TXCOMPLETE: 118 | Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); 119 | Serial.println(LMIC.dataLen); 120 | if (LMIC.dataLen) { 121 | // data received in rx slot after tx 122 | uint8_t downlink[LMIC.dataLen]; 123 | memcpy(&downlink, &(LMIC.frame + LMIC.dataBeg)[0], LMIC.dataLen); 124 | // Turn on/off fan if we get the magic number 125 | if ( downlink[0] == 0x31 ) { 126 | // digitalWrite(FanPin, HIGH); 127 | } 128 | else { 129 | // digitalWrite(FanPin, LOW); 130 | } 131 | 132 | Serial.print(F("Data Received: ")); 133 | Serial.write(LMIC.frame + LMIC.dataBeg, LMIC.dataLen); 134 | Serial.println(); 135 | 136 | } 137 | // Schedule next transmission 138 | os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send); 139 | digitalWrite(REDLED, HIGH); 140 | break; 141 | /* 142 | case EV_TXCOMPLETE: 143 | Serial.print((millis() - entry) / 1000); Serial.print(" "); 144 | entry = millis(); 145 | Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); 146 | if (LMIC.txrxFlags & TXRX_ACK) 147 | Serial.println(F("Received ack")); 148 | if (LMIC.dataLen) { 149 | Serial.println(F("Received ")); 150 | Serial.println(LMIC.dataLen); 151 | Serial.println(F(" bytes of payload")); 152 | } 153 | // Schedule next transmission 154 | os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send); 155 | digitalWrite(REDLED, HIGH); 156 | break; 157 | */ 158 | case EV_LOST_TSYNC: 159 | Serial.println(F("EV_LOST_TSYNC")); 160 | break; 161 | case EV_RESET: 162 | Serial.println(F("EV_RESET")); 163 | break; 164 | case EV_RXCOMPLETE: 165 | // data received in ping slot 166 | Serial.println(F("EV_RXCOMPLETE")); 167 | break; 168 | case EV_LINK_DEAD: 169 | Serial.println(F("EV_LINK_DEAD")); 170 | break; 171 | case EV_LINK_ALIVE: 172 | Serial.println(F("EV_LINK_ALIVE")); 173 | break; 174 | default: 175 | Serial.println(F("Unknown event")); 176 | break; 177 | } 178 | } 179 | 180 | void do_send(osjob_t* j) { 181 | byte buffer[32]; 182 | // Check if there is not a current TX/RX job running 183 | if (LMIC.opmode & OP_TXRXPEND) { 184 | Serial.println(F("OP_TXRXPEND, not sending")); 185 | } else { 186 | // Prepare upstream data transmission at the next possible time. 187 | String message = "" + String(counter); 188 | message.getBytes(buffer, message.length() + 1); 189 | counter++; 190 | Serial.println("Sending: " + message); 191 | LMIC_setTxData2(1, (uint8_t*) buffer, message.length() , 0); 192 | Serial.println(F(" Packet queued")); 193 | digitalWrite(REDLED, LOW); 194 | } 195 | // Next TX is scheduled after TX_COMPLETE event. 196 | } 197 | 198 | void setup() { 199 | Serial.begin(115200); 200 | Serial.println(F("Starting")); 201 | 202 | pinMode(GREENLED, OUTPUT); 203 | pinMode(REDLED, OUTPUT); 204 | pinMode(SFSWITCH, INPUT_PULLUP); 205 | pinMode(RUNPIN, INPUT_PULLUP); 206 | digitalWrite(REDLED, HIGH); 207 | digitalWrite(GREENLED, HIGH); 208 | 209 | #ifdef VCC_ENABLE 210 | // For Pinoccio Scout boards 211 | pinMode(VCC_ENABLE, OUTPUT); 212 | digitalWrite(VCC_ENABLE, HIGH); 213 | delay(1000); 214 | #endif 215 | 216 | // LMIC init 217 | os_init(); 218 | // Reset the MAC state. Session and pending data transfers will be discarded. 219 | LMIC_reset(); 220 | 221 | // Set static session parameters. Instead of dynamically establishing a session 222 | // by joining the network, precomputed session parameters are be provided. 223 | #ifdef PROGMEM 224 | // On AVR, these values are stored in flash and only copied to RAM 225 | // once. Copy them to a temporary buffer here, LMIC_setSession will 226 | // copy them into a buffer of its own again. 227 | uint8_t appskey[sizeof(APPSKEY)]; 228 | uint8_t nwkskey[sizeof(NWKSKEY)]; 229 | memcpy_P(appskey, APPSKEY, sizeof(APPSKEY)); 230 | memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY)); 231 | LMIC_setSession (0x1, DEVADDR, nwkskey, appskey); 232 | #else 233 | // If not running an AVR with PROGMEM, just use the arrays directly 234 | LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY); 235 | #endif 236 | 237 | #if defined(CFG_eu868) 238 | Serial.println("European Channels"); 239 | for (int i = 1; i <= 8; i++) LMIC_disableChannel(i); 240 | #elif defined(CFG_us915) 241 | // NA-US channels 0-71 are configured automatically 242 | // but only one group of 8 should (a subband) should be active 243 | // TTN recommends the second sub band, 1 in a zero based count. 244 | // https://github.com/TheThingsNetwork/gateway-conf/blob/master/US-global_conf.json 245 | LMIC_selectSubBand(1); 246 | #endif 247 | 248 | // Disable link check validation 249 | LMIC_setLinkCheckMode(0); 250 | 251 | // TTN uses SF9 for its RX2 window. 252 | LMIC.dn2Dr = DR_SF9; 253 | 254 | // Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library) 255 | if (digitalRead(SFSWITCH) == HIGH) { 256 | Serial.println("SF7"); 257 | LMIC_setDrTxpow(DR_SF7, 14); 258 | } 259 | else { 260 | Serial.println("SF12"); 261 | LMIC_setDrTxpow(DR_SF12, 14); 262 | } 263 | 264 | // Start job 265 | do_send(&sendjob); 266 | } 267 | 268 | void loop() { 269 | while (digitalRead(RUNPIN) == HIGH) { 270 | digitalWrite(GREENLED, HIGH); 271 | delay(10); 272 | } 273 | switchState = digitalRead(SFSWITCH); 274 | if (switchState != oldSwitchState) { 275 | delay(100); 276 | // Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library) 277 | if (digitalRead(SFSWITCH) == HIGH) { 278 | Serial.println("SF7"); 279 | LMIC_setDrTxpow(DR_SF7, 14); 280 | } 281 | else { 282 | Serial.println("SF12"); 283 | LMIC_setDrTxpow(DR_SF12, 14); 284 | } 285 | oldSwitchState = switchState; 286 | } 287 | digitalWrite(GREENLED, LOW); 288 | os_runloop_once(); 289 | 290 | } 291 | --------------------------------------------------------------------------------