Browse Source
add lora-gps sketch
add lora-gps sketch
GPS tracked SDS011 sensor, transmitting data via Lora through TTN to opensensemap.org based on Arduino Megamaster

1003 changed files with 201049 additions and 0 deletions
-
295libraries/HDC100X/HDC100X.cpp
-
89libraries/HDC100X/HDC100X.h
-
52libraries/HDC100X/KEYWORDS.txt
-
22libraries/HDC100X/examples/readTempHumi/readTempHumi.ino
-
25libraries/HDC100X/examples/test/test.ino
-
22libraries/HDC100X/keywords.txt
-
365libraries/IBM_LMIC_framework/README.md
-
BINlibraries/IBM_LMIC_framework/doc/LMiC-v1.5.pdf
-
4libraries/IBM_LMIC_framework/doc/README.txt
-
28libraries/IBM_LMIC_framework/doc/release-notes.txt
-
162libraries/IBM_LMIC_framework/examples/raw/raw.ino
-
226libraries/IBM_LMIC_framework/examples/ttn-abp/ttn-abp.ino
-
173libraries/IBM_LMIC_framework/examples/ttn-otaa/ttn-otaa.ino
-
207libraries/IBM_LMIC_framework/examples/ttn/ttn.ino
-
9libraries/IBM_LMIC_framework/library.properties
-
342libraries/IBM_LMIC_framework/src/aes/ideetron/AES-128_V10.cpp
-
370libraries/IBM_LMIC_framework/src/aes/lmic.c
-
127libraries/IBM_LMIC_framework/src/aes/other.c
-
253libraries/IBM_LMIC_framework/src/hal/hal.cpp
-
28libraries/IBM_LMIC_framework/src/hal/hal.h
-
9libraries/IBM_LMIC_framework/src/lmic.h
-
367libraries/IBM_LMIC_framework/src/lmic/aes.c
-
83libraries/IBM_LMIC_framework/src/lmic/config.h
-
91libraries/IBM_LMIC_framework/src/lmic/hal.h
-
2382libraries/IBM_LMIC_framework/src/lmic/lmic.c
-
320libraries/IBM_LMIC_framework/src/lmic/lmic.h
-
391libraries/IBM_LMIC_framework/src/lmic/lorabase.h
-
129libraries/IBM_LMIC_framework/src/lmic/oslmic.c
-
288libraries/IBM_LMIC_framework/src/lmic/oslmic.h
-
851libraries/IBM_LMIC_framework/src/lmic/radio.c
-
1libraries/Lora_Serialization/Brewfile
-
21libraries/Lora_Serialization/LICENSE
-
307libraries/Lora_Serialization/README.md
-
17libraries/Lora_Serialization/example/.eslintrc
-
15libraries/Lora_Serialization/example/main_encoder.ino
-
13libraries/Lora_Serialization/example/main_encoder_LoraMessage.ino
-
11libraries/Lora_Serialization/example/ttn_decoder.js
-
8libraries/Lora_Serialization/example/ttn_encoder.js
-
8libraries/Lora_Serialization/example/ttn_encoder_LoraMessage.js
-
9libraries/Lora_Serialization/library.properties
-
54libraries/Lora_Serialization/package.json
-
99libraries/Lora_Serialization/src/LoraEncoder.cpp
-
52libraries/Lora_Serialization/src/LoraEncoder.h
-
72libraries/Lora_Serialization/src/LoraMessage.cpp
-
32libraries/Lora_Serialization/src/LoraMessage.h
-
70libraries/Lora_Serialization/src/LoraMessage.js
-
127libraries/Lora_Serialization/src/decoder.js
-
126libraries/Lora_Serialization/src/encoder.js
-
9libraries/Lora_Serialization/src/index.js
-
7libraries/Lora_Serialization/test/.eslintrc.js
-
37libraries/Lora_Serialization/test/LoraMessage.js
-
18libraries/Lora_Serialization/test/Makefile
-
39libraries/Lora_Serialization/test/base.js
-
20libraries/Lora_Serialization/test/decoder/bitmap.js
-
52libraries/Lora_Serialization/test/decoder/decode.js
-
18libraries/Lora_Serialization/test/decoder/humidity.js
-
18libraries/Lora_Serialization/test/decoder/latLng.js
-
23libraries/Lora_Serialization/test/decoder/temperature.js
-
18libraries/Lora_Serialization/test/decoder/uint16.js
-
18libraries/Lora_Serialization/test/decoder/uint8.js
-
18libraries/Lora_Serialization/test/decoder/unixtime.js
-
19libraries/Lora_Serialization/test/encoder/bitmap.js
-
48libraries/Lora_Serialization/test/encoder/encode.js
-
17libraries/Lora_Serialization/test/encoder/humidity.js
-
22libraries/Lora_Serialization/test/encoder/latLng.js
-
24libraries/Lora_Serialization/test/encoder/temperature.js
-
19libraries/Lora_Serialization/test/encoder/uint16.js
-
19libraries/Lora_Serialization/test/encoder/uint8.js
-
18libraries/Lora_Serialization/test/encoder/unixtime.js
-
12libraries/Lora_Serialization/test/helpers.cpp
-
11libraries/Lora_Serialization/test/lib/Catch/.gitattributes
-
29libraries/Lora_Serialization/test/lib/Catch/.github/issue_template.md
-
25libraries/Lora_Serialization/test/lib/Catch/.github/pull_request_template.md
-
29libraries/Lora_Serialization/test/lib/Catch/.gitignore
-
232libraries/Lora_Serialization/test/lib/Catch/.travis.yml
-
271libraries/Lora_Serialization/test/lib/Catch/CMakeLists.txt
-
23libraries/Lora_Serialization/test/lib/Catch/LICENSE_1_0.txt
-
23libraries/Lora_Serialization/test/lib/Catch/README.md
-
45libraries/Lora_Serialization/test/lib/Catch/appveyor.yml
-
BINlibraries/Lora_Serialization/test/lib/Catch/catch-hand-icon.png
-
BINlibraries/Lora_Serialization/test/lib/Catch/catch-icon-tiny.png
-
BINlibraries/Lora_Serialization/test/lib/Catch/catch-logo-small.png
-
23libraries/Lora_Serialization/test/lib/Catch/docs/Readme.md
-
136libraries/Lora_Serialization/test/lib/Catch/docs/assertions.md
-
95libraries/Lora_Serialization/test/lib/Catch/docs/build-systems.md
-
277libraries/Lora_Serialization/test/lib/Catch/docs/command-line.md
-
12libraries/Lora_Serialization/test/lib/Catch/docs/commercial-users.md
-
100libraries/Lora_Serialization/test/lib/Catch/docs/configuration.md
-
41libraries/Lora_Serialization/test/lib/Catch/docs/contributing.md
-
99libraries/Lora_Serialization/test/lib/Catch/docs/limitations.md
-
52libraries/Lora_Serialization/test/lib/Catch/docs/logging.md
-
103libraries/Lora_Serialization/test/lib/Catch/docs/matchers.md
-
59libraries/Lora_Serialization/test/lib/Catch/docs/opensource-users.md
-
72libraries/Lora_Serialization/test/lib/Catch/docs/own-main.md
-
150libraries/Lora_Serialization/test/lib/Catch/docs/release-notes.md
-
64libraries/Lora_Serialization/test/lib/Catch/docs/slow-compiles.md
-
88libraries/Lora_Serialization/test/lib/Catch/docs/test-cases-and-sections.md
-
32libraries/Lora_Serialization/test/lib/Catch/docs/test-fixtures.md
-
70libraries/Lora_Serialization/test/lib/Catch/docs/tostring.md
-
249libraries/Lora_Serialization/test/lib/Catch/docs/tutorial.md
@ -0,0 +1,295 @@ |
|||
/***********************
|
|||
|
|||
This library was written for the Texas Instruments |
|||
HDC100X temperature and humidity sensor. |
|||
It has been tested for the HDC1000 and the HDC1008 |
|||
Buy the HDC1008 breakout board at: https://www.tindie.com/stores/RFgermany
|
|||
This library is made by Florian Roesner. |
|||
Released under GNU GPL v2.0 license. |
|||
|
|||
*************************/ |
|||
//#include "Arduino.h"
|
|||
#include "HDC100X.h"
|
|||
//#include "Wire.h"
|
|||
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
//PUBLIC:
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
|
|||
HDC100X::HDC100X(){ |
|||
ownAddr = HDC100X_ADDR1; |
|||
dataReadyPin = -1; |
|||
} |
|||
//-----------------------------------------------------------------------
|
|||
HDC100X::HDC100X(uint8_t address){ |
|||
ownAddr = address; |
|||
//dataReadyPin = pin;
|
|||
} |
|||
//-----------------------------------------------------------------------
|
|||
HDC100X::HDC100X(bool addr0, bool addr1){ |
|||
// set the two bits the way you set the address jumpers
|
|||
ownAddr = 0b1000000 |(addr0|(addr1<<1)); |
|||
//dataReadyPin = pin;
|
|||
} |
|||
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
|
|||
uint8_t HDC100X::begin(uint8_t mode, uint8_t tempRes, uint8_t humiRes, bool heaterState){ |
|||
int i; |
|||
|
|||
/* sets the mode and resolution and the state of the heater element. care must be taken, because it will change the temperature reading
|
|||
** in: |
|||
** mode: HDC100X_TEMP_HUMI |
|||
** tempRes: HDC100X_11BIT/HDC100X_14BIT |
|||
** humiRes: HDC100X_8BIT/HDC100X_11BIT/HDC100X_14BIT |
|||
** heaterState: ENABLE/DISABLE |
|||
** out: |
|||
** high byte of the configuration register |
|||
*/ |
|||
Wire.begin(); |
|||
|
|||
// test I2C address
|
|||
Wire.beginTransmission(ownAddr); |
|||
i = Wire.endTransmission(); |
|||
if(i != 0) // error device not found
|
|||
{ |
|||
for(int tries=3; tries!=0; tries--) |
|||
{ |
|||
Wire.beginTransmission(HDC100X_ADDR1); |
|||
i = Wire.endTransmission(); |
|||
if(i == 0) |
|||
{ |
|||
ownAddr = HDC100X_ADDR1; |
|||
break; |
|||
} |
|||
delay(20); // wait 20ms
|
|||
Wire.beginTransmission(HDC100X_ADDR2); |
|||
i = Wire.endTransmission(); |
|||
if(i == 0) |
|||
{ |
|||
ownAddr = HDC100X_ADDR2; |
|||
break; |
|||
} |
|||
delay(20); // wait 20ms
|
|||
Wire.beginTransmission(HDC100X_ADDR3); |
|||
i = Wire.endTransmission(); |
|||
if(i == 0) |
|||
{ |
|||
ownAddr = HDC100X_ADDR3; |
|||
break; |
|||
} |
|||
delay(20); // wait 20ms
|
|||
Wire.beginTransmission(HDC100X_ADDR4); |
|||
i = Wire.endTransmission(); |
|||
if(i == 0) |
|||
{ |
|||
ownAddr = HDC100X_ADDR4; |
|||
break; |
|||
} |
|||
delay(20); // wait 20ms
|
|||
} |
|||
} |
|||
|
|||
HDCmode = mode; |
|||
return writeConfigData(mode|(tempRes<<2)|humiRes|(heaterState<<5)); |
|||
} |
|||
//-----------------------------------------------------------------------
|
|||
uint8_t HDC100X::begin(uint8_t mode, uint8_t resulution, bool heaterState){ |
|||
/* sets the mode, resolution and heaterState. Care must be taken, because it will change the temperature reading
|
|||
** in: |
|||
** mode: HDC100X_TEMP/HDC100X_HUMI |
|||
** resolution: HDC100X_8BIT(just for the humidity)/HDC100X_11BIT(both)/HDC100X_14BIT(both) |
|||
** heaterState: ENABLE/DISABLE |
|||
** out: |
|||
** high byte of the configuration register |
|||
*/ |
|||
Wire.begin(); |
|||
HDCmode = mode; |
|||
if(mode == HDC100X_HUMI) return writeConfigData(resulution|(heaterState<<5)); |
|||
else return writeConfigData((resulution<<2)|(heaterState<<5)); |
|||
} |
|||
|
|||
//######-----------------------------------------------------------------------
|
|||
|
|||
void HDC100X::setAddr(uint8_t address){ |
|||
/* sets the slave address
|
|||
** in: |
|||
** address: slave address byte |
|||
** out: |
|||
** none |
|||
*/ |
|||
ownAddr = address; |
|||
} |
|||
//-----------------------------------------------------------------------
|
|||
void HDC100X::setAddr(bool addr0, bool addr1){ |
|||
/* sets the slave address
|
|||
** in: |
|||
** addr0: true/false |
|||
** addr1: true/false |
|||
** out: |
|||
** none |
|||
*/ |
|||
ownAddr = 0b1000000 |(addr0|(addr1<<1)); |
|||
} |
|||
//-----------------------------------------------------------------------
|
|||
void HDC100X::setDrPin(int8_t pin){ |
|||
dataReadyPin = pin; |
|||
} |
|||
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
|
|||
uint8_t HDC100X::setMode(uint8_t mode, uint8_t tempRes, uint8_t humiRes){ |
|||
/* sets the mode and resolution
|
|||
** in: |
|||
** mode: HDC100X_TEMP_HUMI |
|||
** tempRes: HDC100X_11BIT/HDC100X_14BIT |
|||
** humiRes: HDC100X_8BIT/HDC100X_11BIT/HDC100X_14BIT |
|||
** out: |
|||
** high byte of the configuration register |
|||
*/ |
|||
uint8_t tempReg = getConfigReg() & 0xA0; |
|||
HDCmode = mode; |
|||
return writeConfigData(tempReg|mode|(tempRes<<2)|humiRes); |
|||
} |
|||
//-----------------------------------------------------------------------
|
|||
uint8_t HDC100X::setMode(uint8_t mode, uint8_t resolution){ |
|||
/* sets the mode and resolution
|
|||
** in: |
|||
** mode: HDC100X_TEMP/HDC100X_HUMI |
|||
** resolution: HDC100X_8BIT(just for the humidity)/HDC100X_11BIT(both)/HDC100X_14BIT(both) |
|||
** out: |
|||
** high byte of the configuration register |
|||
*/ |
|||
uint8_t tempReg = getConfigReg() & 0xA0; |
|||
HDCmode = mode; |
|||
if(mode == HDC100X_HUMI) return writeConfigData(tempReg|resolution); |
|||
return writeConfigData(tempReg|(resolution<<2)); |
|||
} |
|||
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
|
|||
uint8_t HDC100X::setHeater(bool state){ |
|||
/* turns on the heater to get rid of condensation. Care must be taken, because it will change the temperature reading
|
|||
** in: |
|||
** state: true/false |
|||
** out: |
|||
** high byte of the configuration register |
|||
*/ |
|||
uint8_t regData = getConfigReg() & 0x5F; |
|||
if(state) return writeConfigData(regData|(state<<5)); |
|||
return writeConfigData(regData); |
|||
} |
|||
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
|
|||
bool HDC100X::battLow(void){ |
|||
// returns a false if input voltage is higher than 2.8V and if lower a true
|
|||
|
|||
if(getConfigReg() & 0x08) return true; |
|||
return false; |
|||
} |
|||
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
|
|||
float HDC100X::getTemp(void){ |
|||
// returns the a float number of the temperature in degrees Celsius
|
|||
if(HDCmode == HDC100X_TEMP || HDCmode == HDC100X_TEMP_HUMI) |
|||
return ((float)getRawTemp()/65536.0*165.0-40.0); |
|||
|
|||
return 0.0; |
|||
} |
|||
//-----------------------------------------------------------------------
|
|||
float HDC100X::getHumi(void){ |
|||
// returns the a float number of the humidity in percent
|
|||
if(HDCmode == HDC100X_HUMI || HDCmode == HDC100X_TEMP_HUMI) |
|||
return ((float)getRawHumi()/65536.0*100.0); |
|||
|
|||
return 0.0; |
|||
} |
|||
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
|
|||
uint16_t HDC100X::getRawTemp(void){ |
|||
// returns the raw 16bit data of the temperature register
|
|||
if(HDCmode == HDC100X_TEMP || HDCmode == HDC100X_TEMP_HUMI) |
|||
return read2Byte(HDC100X_TEMP_REG); |
|||
|
|||
return 0; |
|||
} |
|||
//-----------------------------------------------------------------------
|
|||
uint16_t HDC100X::getRawHumi(void){ |
|||
// returns the raw 16bit data of the humidity register
|
|||
if(HDCmode == HDC100X_HUMI || HDCmode == HDC100X_TEMP_HUMI) |
|||
return read2Byte(HDC100X_HUMI_REG); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
|
|||
uint8_t HDC100X::getConfigReg(void){ |
|||
// returns the high byte of the configuration register
|
|||
return (read2Byte(HDC100X_CONFIG_REG)>>8); |
|||
} |
|||
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
|
|||
uint16_t HDC100X::read2Byte(uint8_t reg){ |
|||
/* reads two bytes from the defined register
|
|||
** in: |
|||
** reg: HDC100X_TEMP_REG/HDC100X_HUMI_REG/HDC100X_CONFIG_REG/HDC100X_ID1_REG/HDC100X_ID2_REG/HDC100X_ID3_REG |
|||
** out: |
|||
** two byte of data from the defined register |
|||
*/ |
|||
uint16_t data=0; |
|||
setRegister(reg); |
|||
Wire.requestFrom(ownAddr, 2U); |
|||
if(Wire.available()>=2){ |
|||
data = Wire.read()<<8; |
|||
data += Wire.read(); |
|||
} |
|||
return data; |
|||
} |
|||
|
|||
uint8_t HDC100X::writeConfigData(uint8_t config){ |
|||
/* writes the config byte to the configuration register
|
|||
** in: |
|||
** config: one byte |
|||
** out: |
|||
** one byte 0:success 1:data too long to fit in transmit buffer 2:received NACK on transmit of address 3:received NACK on transmit of data 4:other error |
|||
*/ |
|||
Wire.beginTransmission(ownAddr); |
|||
Wire.write(HDC100X_CONFIG_REG); |
|||
Wire.write(config); |
|||
Wire.write(0x00); //the last 8 bits are always 0
|
|||
return Wire.endTransmission(); |
|||
} |
|||
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
//PRIVATE:
|
|||
//######-----------------------------------------------------------------------
|
|||
//######-----------------------------------------------------------------------
|
|||
|
|||
void HDC100X::setRegister(uint8_t reg){ |
|||
/* set the register for the next read or write cycle
|
|||
** in: |
|||
** reg: HDC100X_TEMP_REG/HDC100X_HUMI_REG/HDC100X_CONFIG_REG/HDC100X_ID1_REG/HDC100X_ID2_REG/HDC100X_ID3_REG |
|||
** out: |
|||
** none |
|||
*/ |
|||
Wire.beginTransmission(ownAddr); |
|||
Wire.write(reg); |
|||
Wire.endTransmission(); |
|||
delay(10); // wait a little so that the sensor can set its register
|
|||
} |
@ -0,0 +1,89 @@ |
|||
/*********************** |
|||
|
|||
This library was written for the Texas Instruments |
|||
HDC100X temperature and humidity sensor. |
|||
It has been tested for the HDC1000 and the HDC1008 |
|||
Buy the HDC1008 breakout board at: https://www.tindie.com/stores/RFgermany |
|||
This library is made by Florian Roesner. |
|||
Released under GNU GPL v2.0 license. |
|||
|
|||
*************************/ |
|||
|
|||
#ifndef _HDC100X_H_ |
|||
#define _HDC100X_H_ |
|||
|
|||
#include <inttypes.h> |
|||
#include "Wire.h" |
|||
|
|||
#if (ARDUINO >= 100) |
|||
#include "Arduino.h" |
|||
#else |
|||
#include "WProgram.h" |
|||
#endif |
|||
|
|||
#define HDC100X_ADDR1 0x43 |
|||
#define HDC100X_ADDR2 0x40 |
|||
#define HDC100X_ADDR3 0x41 |
|||
#define HDC100X_ADDR4 0x42 |
|||
|
|||
#define HDC100X_TEMP_REG 0x00 |
|||
#define HDC100X_HUMI_REG 0x01 |
|||
#define HDC100X_CONFIG_REG 0x02 |
|||
#define HDC100X_ID1_REG 0xFB |
|||
#define HDC100X_ID2_REG 0xFC |
|||
#define HDC100X_ID3_REG 0xFD |
|||
|
|||
|
|||
#define HDC100X_RST 0x80 |
|||
#define HDC100X_TEMP_HUMI 0x16 |
|||
#define HDC100X_HUMI 1 |
|||
#define HDC100X_TEMP 0 |
|||
|
|||
#define HDC100X_14BIT 0x00 |
|||
#define HDC100X_11BIT 0x01 |
|||
#define HDC100X_8BIT 0x02 |
|||
|
|||
#define DISABLE 0 |
|||
#define ENABLE 1 |
|||
|
|||
|
|||
|
|||
class HDC100X{ |
|||
public: |
|||
HDC100X(); |
|||
HDC100X(uint8_t address); |
|||
HDC100X(bool addr0, bool addr1); |
|||
|
|||
uint8_t begin(uint8_t mode, uint8_t tempRes, uint8_t humiRes, bool heaterState); |
|||
uint8_t begin(uint8_t mode, uint8_t resulution, bool heaterState); |
|||
|
|||
void setAddr(bool addr0, bool addr1); |
|||
void setAddr(uint8_t address); |
|||
void setDrPin(int8_t pin); |
|||
|
|||
uint8_t setMode(uint8_t mode, uint8_t tempRes, uint8_t humiRes); |
|||
uint8_t setMode(uint8_t mode, uint8_t resolution); |
|||
|
|||
uint8_t setHeater(bool state); |
|||
bool battLow(void); |
|||
|
|||
float getTemp(void); |
|||
float getHumi(void); |
|||
|
|||
uint16_t getRawTemp(void); |
|||
uint16_t getRawHumi(void); |
|||
|
|||
uint8_t getConfigReg(void); |
|||
uint16_t read2Byte(uint8_t reg); |
|||
|
|||
uint8_t writeConfigData(uint8_t config); |
|||
|
|||
private: |
|||
uint8_t ownAddr; |
|||
uint8_t dataReadyPin; |
|||
uint8_t HDCmode; |
|||
void setRegister(uint8_t reg); |
|||
|
|||
}; |
|||
|
|||
#endif //_HDC100X_H_ |
@ -0,0 +1,52 @@ |
|||
####################################### |
|||
# Syntax Coloring Map |
|||
####################################### |
|||
|
|||
DISABLE KEYWORD2 |
|||
ENABLE KEYWORD2 |
|||
|
|||
|
|||
####################################### |
|||
# Datatypes (KEYWORD1) |
|||
####################################### |
|||
|
|||
HDC100X KEYWORD1 |
|||
|
|||
####################################### |
|||
# Methods and Functions (KEYWORD2) |
|||
####################################### |
|||
begin KEYWORD2 |
|||
setAddr KEYWORD2 |
|||
setDrPin KEYWORD2 |
|||
setMode KEYWORD2 |
|||
setHeater KEYWORD2 |
|||
battLow KEYWORD2 |
|||
getTemp KEYWORD2 |
|||
getHumi KEYWORD2 |
|||
getRawTemp KEYWORD2 |
|||
getRawHumi KEYWORD2 |
|||
getConfigReg KEYWORD2 |
|||
read2Byte KEYWORD2 |
|||
setRegister KEYWORD2 |
|||
writeConfigData KEYWORD2 |
|||
|
|||
|
|||
###################################### |
|||
# Constants (LITERAL1) |
|||
####################################### |
|||
HDC100X_DEFAULT_ADDR LITERAL1 |
|||
|
|||
HDC100X_TEMP_REG LITERAL1 |
|||
HDC100X_HUMI_REG LITERAL1 |
|||
HDC100X_CONFIG_REG LITERAL1 |
|||
HDC100X_ID1_REG LITERAL1 |
|||
HDC100X_ID2_REG LITERAL1 |
|||
HDC100X_ID3_REG LITERAL1 |
|||
|
|||
HDC100X_RST LITERAL1 |
|||
HDC100X_TEMP_HUMI LITERAL1 |
|||
HDC100X_HUMI LITERAL1 |
|||
HDC100X_TEMP LITERAL1 |
|||
HDC100X_14BIT LITERAL1 |
|||
HDC100X_11BIT LITERAL1 |
|||
HDC100X_8BIT LITERAL1 |
@ -0,0 +1,22 @@ |
|||
#include <Wire.h>
|
|||
#include <HDC100X.h>
|
|||
|
|||
HDC100X HDC1(0x43); |
|||
|
|||
|
|||
#define LED 13
|
|||
bool state = false; |
|||
|
|||
void setup(){ |
|||
Serial.begin(9600); |
|||
HDC1.begin(HDC100X_TEMP_HUMI,HDC100X_14BIT,HDC100X_14BIT,DISABLE); |
|||
} |
|||
|
|||
void loop(){ |
|||
Serial.print(" Humidity: "); |
|||
Serial.print(HDC1.getHumi()); |
|||
Serial.print("%, Temperature: "); |
|||
Serial.print(HDC1.getTemp()); |
|||
Serial.println("C"); |
|||
delay(500); |
|||
} |
@ -0,0 +1,25 @@ |
|||
#include <Wire.h>
|
|||
#include <HDC100X.h>
|
|||
|
|||
HDC100X hdc; |
|||
|
|||
#define LED 13
|
|||
bool state = false; |
|||
|
|||
void setup() |
|||
{ |
|||
Serial.begin(9600); |
|||
|
|||
hdc.begin(HDC100X_TEMP_HUMI,HDC100X_14BIT,HDC100X_14BIT,DISABLE); |
|||
} |
|||
|
|||
void loop() |
|||
{ |
|||
Serial.print(" Humidity: "); |
|||
Serial.print(hdc.getHumi()); |
|||
Serial.print("%, Temperature: "); |
|||
Serial.print(hdc.getTemp()); |
|||
Serial.println("C"); |
|||
|
|||
delay(500); |
|||
} |
@ -0,0 +1,22 @@ |
|||
####################################### |
|||
# Datatypes (KEYWORD1) |
|||
####################################### |
|||
|
|||
HDC100X KEYWORD1 |
|||
|
|||
####################################### |
|||
# Methods and Functions (KEYWORD2) |
|||
####################################### |
|||
begin KEYWORD2 |
|||
setAddr KEYWORD2 |
|||
setDrPin KEYWORD2 |
|||
setMode KEYWORD2 |
|||
setHeater KEYWORD2 |
|||
battLow KEYWORD2 |
|||
getTemp KEYWORD2 |
|||
getHumi KEYWORD2 |
|||
getRawTemp KEYWORD2 |
|||
getRawHumi KEYWORD2 |
|||
getConfigReg KEYWORD2 |
|||
read2Byte KEYWORD2 |
|||
writeConfigData KEYWORD2 |
@ -0,0 +1,365 @@ |
|||
Arduino-LMIC library |
|||
==================== |
|||
This repository contains the IBM LMIC (LoraMAC-in-C) library, slightly |
|||
modified to run in the Arduino environment, allowing using the SX1272, |
|||
SX1276 tranceivers and compatible modules (such as some HopeRF RFM9x |
|||
modules). |
|||
|
|||
This library mostly exposes the functions defined by LMIC, it makes no |
|||
attempt to wrap them in a higher level API that is more in the Arduino |
|||
style. To find out how to use the library itself, see the examples, or |
|||
see the PDF file in the doc subdirectory. |
|||
|
|||
This library requires Arduino IDE version 1.6.6 or above, since it |
|||
requires C99 mode to be enabled by default. |
|||
|
|||
Installing |
|||
---------- |
|||
To install this library: |
|||
|
|||
- install it using the Arduino Library manager ("Sketch" -> "Include |
|||
Library" -> "Manage Libraries..."), or |
|||
- download a zipfile from github using the "Download ZIP" button and |
|||
install it using the IDE ("Sketch" -> "Include Library" -> "Add .ZIP |
|||
Library..." |
|||
- clone this git repository into your sketchbook/libraries folder. |
|||
|
|||
For more info, see https://www.arduino.cc/en/Guide/Libraries |
|||
|
|||
Features |
|||
-------- |
|||
The LMIC library provides a fairly complete LoRaWAN Class A and Class B |
|||
implementation, supporting the EU-868 and US-915 bands. Only a limited |
|||
number of features was tested using this port on Arduino hardware, so be |
|||
careful when using any of the untested features. |
|||
|
|||
What certainly works: |
|||
- Sending packets uplink, taking into account duty cycling. |
|||
- Encryption and message integrity checking. |
|||
- Receiving downlink packets in the RX2 window. |
|||
- Custom frequencies and datarate settings. |
|||
- Over-the-air activation (OTAA / joining). |
|||
|
|||
What has not been tested: |
|||
- Receiving downlink packets in the RX1 window. |
|||
- Receiving and processing MAC commands. |
|||
- Class B operation. |
|||
|
|||
If you try one of these untested features and it works, be sure to let |
|||
us know (creating a github issue is probably the best way for that). |
|||
|
|||
Configuration |
|||
------------- |
|||
A number of features can be configured or disabled by editing the |
|||
`config.h` file in the library folder. Unfortunately the Arduino |
|||
environment does not offer any way to do this (compile-time) |
|||
configuration from the sketch, so be careful to recheck your |
|||
configuration when you switch between sketches or update the library. |
|||
|
|||
At the very least, you should set the right type of transceiver (SX1272 |
|||
vs SX1276) in config.h, most other values should be fine at their |
|||
defaults. |
|||
|
|||
Supported hardware |
|||
------------------ |
|||
This library is intended to be used with plain LoRa transceivers, |
|||
connecting to them using SPI. In particular, the SX1272 and SX1276 |
|||
families are supported (which should include SX1273, SX1277, SX1278 and |
|||
SX1279 which only differ in the available frequencies, bandwidths and |
|||
spreading factors). It has been tested with both SX1272 and SX1276 |
|||
chips, using the Semtech SX1272 evaluation board and the HopeRF RFM92 |
|||
and RFM95 boards (which supposedly contain an SX1272 and SX1276 chip |
|||
respectively). |
|||
|
|||
This library contains a full LoRaWAN stack and is intended to drive |
|||
these Transceivers directly. It is *not* intended to be used with |
|||
full-stack devices like the Microchip RN2483 and the Embit LR1272E. |
|||
These contain a transceiver and microcontroller that implements the |
|||
LoRaWAN stack and exposes a high-level serial interface instead of the |
|||
low-level SPI transceiver interface. |
|||
|
|||
This library is intended to be used inside the Arduino environment. It |
|||
should be architecture-independent, so it should run on "normal" AVR |
|||
arduinos, but also on the ARM-based ones, and some success has been seen |
|||
running on the ESP8266 board as well. It was tested on the Arduino Uno, |
|||
Pinoccio Scout, Teensy LC and 3.x, ESP8266, Arduino 101. |
|||
|
|||
This library an be quite heavy, especially if the fairly small ATmega |
|||
328p (such as in the Arduino Uno) is used. In the default configuration, |
|||
the available 32K flash space is nearly filled up (this includes some |
|||
debug output overhead, though). By disabling some features in `config.h` |
|||
(like beacon tracking and ping slots, which are not typically needed), |
|||
some space can be freed up. Some work is underway to replace the AES |
|||
encryption implementation, which should free up another 8K or so of |
|||
flash in the future, making this library feasible to run on a 328p |
|||
microcontroller. |
|||
|
|||
Connections |
|||
----------- |
|||
To make this library work, your Arduino (or whatever Arduino-compatible |
|||
board you are using) should be connected to the transceiver. The exact |
|||
connections are a bit dependent on the transceiver board and Arduino |
|||
used, so this section tries to explain what each connection is for and |
|||
in what cases it is (not) required. |
|||
|
|||
Note that the SX1272 module runs at 3.3V and likely does not like 5V on |
|||
its pins (though the datasheet is not say anything about this, and my |
|||
transceiver did not obviously break after accidentally using 5V I/O for |
|||
a few hours). To be safe, make sure to use a level shifter, or an |
|||
Arduino running at 3.3V. The Semtech evaluation board has 100 ohm resistors in |
|||
series with all data lines that might prevent damage, but I would not |
|||
count on that. |
|||
|
|||
### Power |
|||
The SX127x transceivers need a supply voltage between 1.8V and 3.9V. |
|||
Using a 3.3V supply is typical. Some modules have a single power pin |
|||
(like the HopeRF modules, labeled 3.3V) but others expose multiple power |
|||
pins for different parts (like the Semtech evaluation board that has |
|||
`VDD_RF`, `VDD_ANA` and `VDD_FEM`), which can all be connected together. |
|||
Any *GND* pins need to be connected to the Arduino *GND* pin(s). |
|||
|
|||
### SPI |
|||
The primary way of communicating with the transceiver is through SPI |
|||
(Serial Peripheral Interface). This uses four pins: MOSI, MISO, SCK and |
|||
SS. The former three need to be directly connected: so MOSI to MOSI, |
|||
MISO to MISO, SCK to SCK. Where these pins are located on your Arduino |
|||
varies, see for example the "Connections" section of the [Arduino SPI |
|||
documentation](SPI). |
|||
|
|||
The SS (slave select) connection is a bit more flexible. On the SPI |
|||
slave side (the transceiver), this must be connect to the pin |
|||
(typically) labeled *NSS*. On the SPI master (Arduino) side, this pin |
|||
can connect to any I/O pin. Most Arduinos also have a pin labeled "SS", |
|||
but this is only relevant when the Arduino works as an SPI slave, which |
|||
is not the case here. Whatever pin you pick, you need to tell the |
|||
library what pin you used through the pin mapping (see below). |
|||
|
|||
[SPI]: https://www.arduino.cc/en/Reference/SPI |
|||
|
|||
### DIO pins |
|||
The DIO (digitial I/O) pins on the transceiver board can be configured |
|||
for various functions. The LMIC library uses them to get instant status |
|||
information from the transceiver. For example, when a LoRa transmission |
|||
starts, the DIO0 pin is configured as a TxDone output. When the |
|||
transmission is complete, the DIO0 pin is made high by the transceiver, |
|||
which can be detected by the LMIC library. |
|||
|
|||
The LMIC library needs only access to DIO0, DIO1 and DIO2, the other |
|||
DIOx pins can be left disconnected. On the Arduino side, they can |
|||
connect to any I/O pin, since the current implementation does not use |
|||
interrupts or other special hardware features (though this might be |
|||
added in the feature, see also the "Timing" section). |
|||
|
|||
In LoRa mode the DIO pins are used as follows: |
|||
* DIO0: TxDone and RxDone |
|||
* DIO1: RxTimeout |
|||
|
|||
In FSK mode they are used as follows:: |
|||
* DIO0: PayloadReady and PacketSent |
|||
* DIO2: TimeOut |
|||
|
|||
Both modes need only 2 pins, but the tranceiver does not allow mapping |
|||
them in such a way that all needed interrupts map to the same 2 pins. |
|||
So, if both LoRa and FSK modes are used, all three pins must be |
|||
connected. |
|||
|
|||
The pins used on the Arduino side should be configured in the pin |
|||
mapping in your sketch (see below). |
|||
|
|||
### Reset |
|||
The transceiver has a reset pin that can be used to explicitely reset |
|||
it. The LMIC library uses this to ensure the chip is in a consistent |
|||
state at startup. In practice, this pin can be left disconnected, since |
|||
the transceiver will already be in a sane state on power-on, but |
|||
connecting it might prevent problems in some cases. |
|||
|
|||
On the Arduino side, any I/O pin can be used. The pin number used must |
|||
be configured in the pin mapping (see below). |
|||
|
|||
### RXTX |
|||
The transceiver contains two separate antenna connections: One for RX |
|||
and one for TX. A typical transceiver board contains an antenna switch |
|||
chip, that allows switching a single antenna between these RX and TX |
|||
connections. Such a antenna switcher can typically be told what |
|||
position it should be through an input pin, often labeled *RXTX*. |
|||
|
|||
The easiest way to control the antenna switch is to use the *RXTX* pin |
|||
on the SX127x transceiver. This pin is automatically set high during TX |
|||
and low during RX. For example, the HopeRF boards seem to have this |
|||
connection in place, so they do not expose any *RXTX* pins and the pin |
|||
can be marked as unused in the pin mapping. |
|||
|
|||
Some boards do expose the antenna switcher pin, and sometimes also the |
|||
SX127x *RXTX* pin. For example, the SX1272 evaluation board calls the |
|||
former *FEM_CTX* and the latter *RXTX*. Again, simply connecting these |
|||
together with a jumper wire is the easiest solution. |
|||
|
|||
Alternatively, or if the SX127x *RXTX* pin is not available, LMIC can be |
|||
configured to control the antenna switch. Connect the antenna switch |
|||
control pin (e.g. *FEM_CTX* on the Semtech evaluation board) to any I/O |
|||
pin on the Arduino side, and configure the pin used in the pin map (see |
|||
below). It is not entirely clear why would *not* want the transceiver to |
|||
control the antenna directly, though. |
|||
|
|||
### Pin mapping |
|||
As described above, most connections can use arbitrary I/O pins on the |
|||
Arduino side. To tell the LMIC library about these, a pin mapping struct |
|||
is used in the sketch file. |
|||
|
|||
For example, this could look like this: |
|||
|
|||
lmic_pinmap lmic_pins = { |
|||
.nss = 6, |
|||
.rxtx = LMIC_UNUSED_PIN, |
|||
.rst = 5, |
|||
.dio = {2, 3, 4}, |
|||
}; |
|||
|
|||
The names refer to the pins on the transceiver side, the numbers refer |
|||
to the Arduino pin numbers (to use the analog pins, use constants like |
|||
`A0`). For the DIO pins, the three numbers refer to DIO0, DIO1 and DIO2 |
|||
respectively. Any pins that are not needed should be specified as |
|||
`LMIC_UNUSED_PIN`. The nss and dio0 pin is required, the others can |
|||
potentially left out (depending on the environments and requirements, |
|||
see the notes above for when a pin can or cannot be left out). |
|||
|
|||
The name of this struct must always be `lmic_pins`, which is a special name |
|||
recognized by the library. |
|||
|
|||
#### LoRa Nexus by Ideetron |
|||
This board uses the following pin mapping: |
|||
|
|||
const lmic_pinmap lmic_pins = { |
|||
.nss = 10, |
|||
.rxtx = LMIC_UNUSED_PIN, |
|||
.rst = LMIC_UNUSED_PIN, // hardwired to AtMega RESET |
|||
.dio = {4, 5, 7}, |
|||
}; |
|||
|
|||
Examples |
|||
-------- |
|||
This library currently provides three examples: |
|||
|
|||
- `ttn-abp.ino` shows a basic transmission of a "Hello, world!" message |
|||
using the LoRaWAN protocol. It contains some frequency settings and |
|||
encryption keys intended for use with The Things Network, but these |
|||
also correspond to the default settings of most gateways, so it |
|||
should work with other networks and gateways as well. This example |
|||
uses activation-by-personalization (ABP, preconfiguring a device |
|||
address and encryption keys), and does not employ over-the-air |
|||
activation. |
|||
|
|||
Reception of packets (in response to transmission, using the RX1 and |
|||
RX2 receive windows is also supported). |
|||
|
|||
- `ttn-otaa.ino` also sends a "Hello, world!" message, but uses over |
|||
the air activation (OTAA) to first join a network to establish a |
|||
session and security keys. This was tested with The Things Network, |
|||
but should also work (perhaps with some changes) for other networks. |
|||
|
|||
- `raw.ino` shows how to access the radio on a somewhat low level, |
|||
and allows to send raw (non-LoRaWAN) packets between nodes directly. |
|||
This is useful to verify basic connectivity, and when no gateway is |
|||
available, but this example also bypasses duty cycle checks, so be |
|||
careful when changing the settings. |
|||
|
|||
Timing |
|||
------ |
|||
Unfortunately, the SX127x tranceivers do not support accurate |
|||
timekeeping themselves (there is a sequencer that is *almost* sufficient |
|||
for timing the RX1 and RX2 downlink windows, but that is only available |
|||
in FSK mode, not in LoRa mode). This means that the microcontroller is |
|||
responsible for keeping track of time. In particular, it should note |
|||
when a packet finished transmitting, so it can open up the RX1 and RX2 |
|||
receive windows at a fixed time after the end of transmission. |
|||
|
|||
This timing uses the Arduino `micros()` timer, which has a granularity |
|||
of 4ฮผs and is based on the primary microcontroller clock. For timing |
|||
events, the tranceiver uses its DIOx pins as interrupt outputs. In the |
|||
current implementation, these pins are not handled by an actual |
|||
interrupt handler, but they are just polled once every LMIC loop, |
|||
resulting in a bit inaccuracy in the timestamping. Also, running |
|||
scheduled jobs (such as opening up the receive windows) is done using a |
|||
polling approach, which might also result in further delays. |
|||
|
|||
Fortunately, LoRa is a fairly slow protocol and the timing of the |
|||
receive windows is not super critical. To synchronize transmitter and |
|||
receiver, a preamble is first transmitted. Using LoRaWAN, this preamble |
|||
consists of 8 symbols, of which the receiver needs to see 4 symbols to |
|||
lock on. The current implementation tries to enable the receiver for 5 |
|||
symbol times at 1.5 symbol after the start of the receive window, |
|||
meaning that a inacurracy of plus or minus 2.5 symbol times should be |
|||
acceptable. |
|||
|
|||
At the fastest LoRa setting supported by the tranceiver (SF5BW500) a |
|||
single preamble symbol takes 64ฮผs, so the receive window timing should |
|||
be accurate within 160ฮผs (for LoRaWAN this is SF7BW250, needing accuracy |
|||
within 1280ฮผs). This is certainly within a crystal's accuracy, but using |
|||
the internal oscillator is probably not feasible (which is 1% - 10% |
|||
accurate, depending on calibration). This accuracy should also be |
|||
feasible with the polling approach used, provided that the LMIC loop is |
|||
run often enough. |
|||
|
|||
It would be good to properly review this code at some point, since it |
|||
seems that in some places some offsets and corrections are applied that |
|||
might not be appropriate for the Arduino environment. So if reception is |
|||
not working, the timing is something to have a closer look at. |
|||
|
|||
The LMIC library was intended to connect the DIO pins to interrupt |
|||
lines and run code inside the interrupt handler. However, doing this |
|||
opens up an entire can of worms with regard to doing SPI transfers |
|||
inside interrupt routines (some of which is solved by the Arduino |
|||
`beginTransaction()` API, but possibly not everything). One simpler |
|||
alternative could be to use an interrupt handler to just store a |
|||
timestamp, and then do the actual handling in the main loop (this |
|||
requires modifications of the library to pass a timestamp to the LMIC |
|||
`radio_irq_handler()` function). |
|||
|
|||
An even more accurate solution could be to use a dedicated timer with an |
|||
input capture unit, that can store the timestamp of a change on the DIO0 |
|||
pin (the only one that is timing-critical) entirely in hardware. |
|||
Unfortunately, timer0, as used by Arduino's `millis()` and `micros()` |
|||
functions does not seem to have an input capture unit, meaning a |
|||
separate timer is needed for this. |
|||
|
|||
If the main microcontroller does not have a crystal, but uses the |
|||
internal oscillator, the clock output of the transceiver (on DIO5) could |
|||
be usable to drive this timer instead of the main microcontroller clock, |
|||
to ensure the receive window timing is sufficiently accurate. Ideally, |
|||
this would use timer2, which supports asynchronous mode (e.g. running |
|||
while the microcontroller is sleeping), but that timer does not have an |
|||
input capture unit. Timer1 has one, but it seems it will stop running |
|||
once the microcontroller sleeps. Running the microcontroller in idle |
|||
mode with a slower clock might be feasible, though. Instead of using the |
|||
main crystal oscillator of the transceiver, it could be possible to use |
|||
the transceiver's internal RC oscillator (which is calibrated against |
|||
the transceiver crystal), or to calibrate the microcontroller internal |
|||
RC oscillator using the transceiver's clkout. However, that datasheet is |
|||
a bit vague on the RC oscillator's accuracy and how to use it exactly |
|||
(some registers seem to be FSK-mode only), so this needs some |
|||
experiments. |
|||
|
|||
Downlink datarate |
|||
----------------- |
|||
Note that the datarate used for downlink packets in the RX2 window |
|||
defaults to SF12BW125 according to the specification, but some networks |
|||
use different values (iot.semtech.com and The Things Network both use |
|||
SF9BW). When using personalized activate (ABP), it is your |
|||
responsibility to set the right settings, e.g. by adding this to your |
|||
sketch (after calling `LMIC_setSession`). `ttn-abp.ino` already does |
|||
this. |
|||
|
|||
LMIC.dn2Dr = DR_SF9; |
|||
|
|||
When using OTAA, the network communicates the RX2 settings in the |
|||
join accept message, but the LMIC library does not currently process |
|||
these settings. Until that is solved (see issue #20), you should |
|||
manually set the RX2 rate, *after* joining (see the handling of |
|||
`EV_JOINED` in the `ttn-otaa.ino` for an example. |
|||
|
|||
License |
|||
------- |
|||
Most source files in this repository are made available under the |
|||
Eclipse Public License v1.0. The examples which use a more liberal |
|||
license. Some of the AES code is available under the LGPL. Refer to each |
|||
individual source file for more details. |
@ -0,0 +1,4 @@ |
|||
DISCLAIMER: |
|||
Please note that the software is provided AS IS and we cannot |
|||
provide support for optimizations, adaptations, integration, |
|||
ports to other platforms or device drivers! |
@ -0,0 +1,28 @@ |
|||
============================================================================== |
|||
LMIC VERSION 1.4 (17-Mar-2015) |
|||
------------------------------- |
|||
|
|||
- changed API: inverted port indicator flag in LMIC.txrxFlags |
|||
(now TXRX_PORT, previously TXRX_NOPORT) |
|||
|
|||
- fixed offset OFF_CFLIST constant |
|||
|
|||
- changed CRC-16 algorithm for beacons to CCITT(XMODEM) polynomial |
|||
|
|||
- fixed radio driver (low data rate optimization for SF11+SF12 only for BW125) |
|||
|
|||
- fixed timer rollover handling in job queue |
|||
|
|||
============================================================================== |
|||
LMIC VERSION 1.5 (8-May-2015) |
|||
------------------------------ |
|||
|
|||
- fixed condition in convFreq() |
|||
|
|||
- fixed freq*100 bug and freq==0 bug for CFList |
|||
|
|||
- fixed TX scheduling bug |
|||
|
|||
- better support for GNU compiler toolchain |
|||
|
|||
============================================================================== |
@ -0,0 +1,162 @@ |
|||
/*******************************************************************************
|
|||
* Copyright (c) 2015 Matthijs Kooijman |
|||
* |
|||
* Permission is hereby granted, free of charge, to anyone |
|||
* obtaining a copy of this document and accompanying files, |
|||
* to do whatever they want with them without any restriction, |
|||
* including, but not limited to, copying, modification and redistribution. |
|||
* NO WARRANTY OF ANY KIND IS PROVIDED. |
|||
* |
|||
* This example transmits data on hardcoded channel and receives data |
|||
* when not transmitting. Running this sketch on two nodes should allow |
|||
* them to communicate. |
|||
*******************************************************************************/ |
|||
|
|||
#include <lmic.h>
|
|||
#include <hal/hal.h>
|
|||
#include <SPI.h>
|
|||
|
|||
#if !defined(DISABLE_INVERT_IQ_ON_RX)
|
|||
#error This example requires DISABLE_INVERT_IQ_ON_RX to be set. Update \
|
|||
config.h in the lmic library to set it. |
|||
#endif
|
|||
|
|||
// How often to send a packet. Note that this sketch bypasses the normal
|
|||
// LMIC duty cycle limiting, so when you change anything in this sketch
|
|||
// (payload length, frequency, spreading factor), be sure to check if
|
|||
// this interval should not also be increased.
|
|||
// See this spreadsheet for an easy airtime and duty cycle calculator:
|
|||
// https://docs.google.com/spreadsheets/d/1voGAtQAjC1qBmaVuP1ApNKs1ekgUjavHuVQIXyYSvNc
|
|||
#define TX_INTERVAL 2000
|
|||
|
|||
// Pin mapping
|
|||
const lmic_pinmap lmic_pins = { |
|||
.nss = 6, |
|||
.rxtx = LMIC_UNUSED_PIN, |
|||
.rst = 5, |
|||
.dio = {2, 3, 4}, |
|||
}; |
|||
|
|||
|
|||
// These callbacks are only used in over-the-air activation, so they are
|
|||
// left empty here (we cannot leave them out completely unless
|
|||
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
|
|||
void os_getArtEui (u1_t* buf) { } |
|||
void os_getDevEui (u1_t* buf) { } |
|||
void os_getDevKey (u1_t* buf) { } |
|||
|
|||
void onEvent (ev_t ev) { |
|||
} |
|||
|
|||
osjob_t txjob; |
|||
osjob_t timeoutjob; |
|||
static void tx_func (osjob_t* job); |
|||
|
|||
// Transmit the given string and call the given function afterwards
|
|||
void tx(const char *str, osjobcb_t func) { |
|||
os_radio(RADIO_RST); // Stop RX first
|
|||
delay(1); // Wait a bit, without this os_radio below asserts, apparently because the state hasn't changed yet
|
|||
LMIC.dataLen = 0; |
|||
while (*str) |
|||
LMIC.frame[LMIC.dataLen++] = *str++; |
|||
LMIC.osjob.func = func; |
|||
os_radio(RADIO_TX); |
|||
Serial.println("TX"); |
|||
} |
|||
|
|||
// Enable rx mode and call func when a packet is received
|
|||
void rx(osjobcb_t func) { |
|||
LMIC.osjob.func = func; |
|||
LMIC.rxtime = os_getTime(); // RX _now_
|
|||
// Enable "continuous" RX (e.g. without a timeout, still stops after
|
|||
// receiving a packet)
|
|||
os_radio(RADIO_RXON); |
|||
Serial.println("RX"); |
|||
} |
|||
|
|||
static void rxtimeout_func(osjob_t *job) { |
|||
digitalWrite(LED_BUILTIN, LOW); // off
|
|||
} |
|||
|
|||
static void rx_func (osjob_t* job) { |
|||
// Blink once to confirm reception and then keep the led on
|
|||
digitalWrite(LED_BUILTIN, LOW); // off
|
|||
delay(10); |
|||
digitalWrite(LED_BUILTIN, HIGH); // on
|
|||
|
|||
// Timeout RX (i.e. update led status) after 3 periods without RX
|
|||
os_setTimedCallback(&timeoutjob, os_getTime() + ms2osticks(3*TX_INTERVAL), rxtimeout_func); |
|||
|
|||
// Reschedule TX so that it should not collide with the other side's
|
|||
// next TX
|
|||
os_setTimedCallback(&txjob, os_getTime() + ms2osticks(TX_INTERVAL/2), tx_func); |
|||
|
|||
Serial.print("Got "); |
|||
Serial.print(LMIC.dataLen); |
|||
Serial.println(" bytes"); |
|||
Serial.write(LMIC.frame, LMIC.dataLen); |
|||
Serial.println(); |
|||
|
|||
// Restart RX
|
|||
rx(rx_func); |
|||
} |
|||
|
|||
static void txdone_func (osjob_t* job) { |
|||
rx(rx_func); |
|||
} |
|||
|
|||
// log text to USART and toggle LED
|
|||
static void tx_func (osjob_t* job) { |
|||
// say hello
|
|||
tx("Hello, world!", txdone_func); |
|||
// reschedule job every TX_INTERVAL (plus a bit of random to prevent
|
|||
// systematic collisions), unless packets are received, then rx_func
|
|||
// will reschedule at half this time.
|
|||
os_setTimedCallback(job, os_getTime() + ms2osticks(TX_INTERVAL + random(500)), tx_func); |
|||
} |
|||
|
|||
// application entry point
|
|||
void setup() { |
|||
Serial.begin(115200); |
|||
Serial.println("Starting"); |
|||
#ifdef VCC_ENABLE
|
|||
// For Pinoccio Scout boards
|
|||
pinMode(VCC_ENABLE, OUTPUT); |
|||
digitalWrite(VCC_ENABLE, HIGH); |
|||
delay(1000); |
|||
#endif
|
|||
|
|||
pinMode(LED_BUILTIN, OUTPUT); |
|||
|
|||
// initialize runtime env
|
|||
os_init(); |
|||
|
|||
// Set up these settings once, and use them for both TX and RX
|
|||
|
|||
#if defined(CFG_eu868)
|
|||
// Use a frequency in the g3 which allows 10% duty cycling.
|
|||
LMIC.freq = 869525000; |
|||
#elif defined(CFG_us915)
|
|||
LMIC.freq = 902300000; |
|||
#endif
|
|||
|
|||
// Maximum TX power
|
|||
LMIC.txpow = 27; |
|||
// Use a medium spread factor. This can be increased up to SF12 for
|
|||
// better range, but then the interval should be (significantly)
|
|||
// lowered to comply with duty cycle limits as well.
|
|||
LMIC.datarate = DR_SF9; |
|||
// This sets CR 4/5, BW125 (except for DR_SF7B, which uses BW250)
|
|||
LMIC.rps = updr2rps(LMIC.datarate); |
|||
|
|||
Serial.println("Started"); |
|||
Serial.flush(); |
|||
|
|||
// setup initial job
|
|||
os_setCallback(&txjob, tx_func); |
|||
} |
|||
|
|||
void loop() { |
|||
// execute scheduled jobs and events
|
|||
os_runloop_once(); |
|||
} |
@ -0,0 +1,226 @@ |
|||
/*******************************************************************************
|
|||
* Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman |
|||
* |
|||
* Permission is hereby granted, free of charge, to anyone |
|||
* obtaining a copy of this document and accompanying files, |
|||
* to do whatever they want with them without any restriction, |
|||
* including, but not limited to, copying, modification and redistribution. |
|||
* NO WARRANTY OF ANY KIND IS PROVIDED. |
|||
* |
|||
* This example sends a valid LoRaWAN packet with payload "Hello, |
|||
* world!", using frequency and encryption settings matching those of |
|||
* the The Things Network. |
|||
* |
|||
* This uses ABP (Activation-by-personalisation), where a DevAddr and |
|||
* Session keys are preconfigured (unlike OTAA, where a DevEUI and |
|||
* application key is configured, while the DevAddr and session keys are |
|||
* assigned/generated in the over-the-air-activation procedure). |
|||
* |
|||
* Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in |
|||
* g1, 0.1% in g2), but not the TTN fair usage policy (which is probably |
|||
* violated by this sketch when left running for longer)! |
|||
* |
|||
* To use this sketch, first register your application and device with |
|||
* the things network, to set or generate a DevAddr, NwkSKey and |
|||
* AppSKey. Each device should have their own unique values for these |
|||
* fields. |
|||
* |
|||
* Do not forget to define the radio type correctly in config.h. |
|||
* |
|||
*******************************************************************************/ |
|||
|
|||
#include <lmic.h>
|
|||
#include <hal/hal.h>
|
|||
#include <SPI.h>
|
|||
|
|||
// LoRaWAN NwkSKey, network session key
|
|||
// This is the default Semtech key, which is used by the early prototype TTN
|
|||
// network.
|
|||
static const PROGMEM u1_t NWKSKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; |
|||
|
|||
// LoRaWAN AppSKey, application session key
|
|||
// This is the default Semtech key, which is used by the early prototype TTN
|
|||
// network.
|
|||
static const u1_t PROGMEM APPSKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; |
|||
|
|||
// LoRaWAN end-device address (DevAddr)
|
|||
static const u4_t DEVADDR = 0x03FF0001 ; // <-- Change this address for every node!
|
|||
|
|||
// These callbacks are only used in over-the-air activation, so they are
|
|||
// left empty here (we cannot leave them out completely unless
|
|||
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
|
|||
void os_getArtEui (u1_t* buf) { } |
|||
void os_getDevEui (u1_t* buf) { } |
|||
void os_getDevKey (u1_t* buf) { } |
|||
|
|||
static uint8_t mydata[] = "Hello, world!"; |
|||
static osjob_t sendjob; |
|||
|
|||
// Schedule TX every this many seconds (might become longer due to duty
|
|||
// cycle limitations).
|
|||
const unsigned TX_INTERVAL = 60; |
|||
|
|||
// Pin mapping
|
|||
const lmic_pinmap lmic_pins = { |
|||
.nss = 6, |
|||
.rxtx = LMIC_UNUSED_PIN, |
|||
.rst = 5, |
|||
.dio = {2, 3, 4}, |
|||
}; |
|||
|
|||
void onEvent (ev_t ev) { |
|||
Serial.print(os_getTime()); |
|||
Serial.print(": "); |
|||
switch(ev) { |
|||
case EV_SCAN_TIMEOUT: |
|||
Serial.println(F("EV_SCAN_TIMEOUT")); |
|||
break; |
|||
case EV_BEACON_FOUND: |
|||
Serial.println(F("EV_BEACON_FOUND")); |
|||
break; |
|||
case EV_BEACON_MISSED: |
|||
Serial.println(F("EV_BEACON_MISSED")); |
|||
break; |
|||
case EV_BEACON_TRACKED: |
|||
Serial.println(F("EV_BEACON_TRACKED")); |
|||
break; |
|||
case EV_JOINING: |
|||
Serial.println(F("EV_JOINING")); |
|||
break; |
|||
case EV_JOINED: |
|||
Serial.println(F("EV_JOINED")); |
|||
break; |
|||
case EV_RFU1: |
|||
Serial.println(F("EV_RFU1")); |
|||
break; |
|||
case EV_JOIN_FAILED: |
|||
Serial.println(F("EV_JOIN_FAILED")); |
|||
break; |
|||
case EV_REJOIN_FAILED: |
|||
Serial.println(F("EV_REJOIN_FAILED")); |
|||
break; |
|||
case EV_TXCOMPLETE: |
|||
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); |
|||
if (LMIC.txrxFlags & TXRX_ACK) |
|||
Serial.println(F("Received ack")); |
|||
if (LMIC.dataLen) { |
|||
Serial.println(F("Received ")); |
|||
Serial.println(LMIC.dataLen); |
|||
Serial.println(F(" bytes of payload")); |
|||
} |
|||
// Schedule next transmission
|
|||
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send); |
|||
break; |
|||
case EV_LOST_TSYNC: |
|||
Serial.println(F("EV_LOST_TSYNC")); |
|||
break; |
|||
case EV_RESET: |
|||
Serial.println(F("EV_RESET")); |
|||
break; |
|||
case EV_RXCOMPLETE: |
|||
// data received in ping slot
|
|||
Serial.println(F("EV_RXCOMPLETE")); |
|||
break; |
|||
case EV_LINK_DEAD: |
|||
Serial.println(F("EV_LINK_DEAD")); |
|||
break; |
|||
case EV_LINK_ALIVE: |
|||
Serial.println(F("EV_LINK_ALIVE")); |
|||
break; |
|||
default: |
|||
Serial.println(F("Unknown event")); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void do_send(osjob_t* j){ |
|||
// Check if there is not a current TX/RX job running
|
|||
if (LMIC.opmode & OP_TXRXPEND) { |
|||
Serial.println(F("OP_TXRXPEND, not sending")); |
|||
} else { |
|||
// Prepare upstream data transmission at the next possible time.
|
|||
LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0); |
|||
Serial.println(F("Packet queued")); |
|||
} |
|||
// Next TX is scheduled after TX_COMPLETE event.
|
|||
} |
|||
|
|||
void setup() { |
|||
Serial.begin(115200); |
|||
Serial.println(F("Starting")); |
|||
|
|||
#ifdef VCC_ENABLE
|
|||
// For Pinoccio Scout boards
|
|||
pinMode(VCC_ENABLE, OUTPUT); |
|||
digitalWrite(VCC_ENABLE, HIGH); |
|||
delay(1000); |
|||
#endif
|
|||
|
|||
// LMIC init
|
|||
os_init(); |
|||
// Reset the MAC state. Session and pending data transfers will be discarded.
|
|||
LMIC_reset(); |
|||
|
|||
// Set static session parameters. Instead of dynamically establishing a session
|
|||
// by joining the network, precomputed session parameters are be provided.
|
|||
#ifdef PROGMEM
|
|||
// On AVR, these values are stored in flash and only copied to RAM
|
|||
// once. Copy them to a temporary buffer here, LMIC_setSession will
|
|||
// copy them into a buffer of its own again.
|
|||
uint8_t appskey[sizeof(APPSKEY)]; |
|||
uint8_t nwkskey[sizeof(NWKSKEY)]; |
|||
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY)); |
|||
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY)); |
|||
LMIC_setSession (0x1, DEVADDR, nwkskey, appskey); |
|||
#else
|
|||
// If not running an AVR with PROGMEM, just use the arrays directly
|
|||
LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY); |
|||
#endif
|
|||
|
|||
#if defined(CFG_eu868)
|
|||
// Set up the channels used by the Things Network, which corresponds
|
|||
// to the defaults of most gateways. Without this, only three base
|
|||
// channels from the LoRaWAN specification are used, which certainly
|
|||
// works, so it is good for debugging, but can overload those
|
|||
// frequencies, so be sure to configure the full frequency range of
|
|||
// your network here (unless your network autoconfigures them).
|
|||
// Setting up channels should happen after LMIC_setSession, as that
|
|||
// configures the minimal channel set.
|
|||
// NA-US channels 0-71 are configured automatically
|
|||
LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
|||
LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI); // g-band
|
|||
LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
|||
LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
|||
LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
|||
LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
|||
LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
|||
LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
|
|||
LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK, DR_FSK), BAND_MILLI); // g2-band
|
|||
// TTN defines an additional channel at 869.525Mhz using SF9 for class B
|
|||
// devices' ping slots. LMIC does not have an easy way to define set this
|
|||
// frequency and support for class B is spotty and untested, so this
|
|||
// frequency is not configured here.
|
|||
#elif defined(CFG_us915)
|
|||
// NA-US channels 0-71 are configured automatically
|
|||
// but only one group of 8 should (a subband) should be active
|
|||
// TTN recommends the second sub band, 1 in a zero based count.
|
|||
// https://github.com/TheThingsNetwork/gateway-conf/blob/master/US-global_conf.json
|
|||
LMIC_selectSubBand(1); |
|||
#endif
|
|||
|
|||
// Disable link check validation
|
|||
LMIC_setLinkCheckMode(0); |
|||
|
|||
// TTN uses SF9 for its RX2 window.
|
|||
LMIC.dn2Dr = DR_SF9; |
|||
|
|||
// Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)
|
|||
LMIC_setDrTxpow(DR_SF7,14); |
|||
|
|||
// Start job
|
|||
do_send(&sendjob); |
|||
} |
|||
|
|||
void loop() { |
|||
os_runloop_once(); |
|||
} |
@ -0,0 +1,173 @@ |
|||
/*******************************************************************************
|
|||
* Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman |
|||
* |
|||
* Permission is hereby granted, free of charge, to anyone |
|||
* obtaining a copy of this document and accompanying files, |
|||
* to do whatever they want with them without any restriction, |
|||
* including, but not limited to, copying, modification and redistribution. |
|||
* NO WARRANTY OF ANY KIND IS PROVIDED. |
|||
* |
|||
* This example sends a valid LoRaWAN packet with payload "Hello, |
|||
* world!", using frequency and encryption settings matching those of |
|||
* the The Things Network. |
|||
* |
|||
* This uses OTAA (Over-the-air activation), where where a DevEUI and |
|||
* application key is configured, which are used in an over-the-air |
|||
* activation procedure where a DevAddr and session keys are |
|||
* assigned/generated for use with all further communication. |
|||
* |
|||
* Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in |
|||
* g1, 0.1% in g2), but not the TTN fair usage policy (which is probably |
|||
* violated by this sketch when left running for longer)! |
|||
|
|||
* To use this sketch, first register your application and device with |
|||
* the things network, to set or generate an AppEUI, DevEUI and AppKey. |
|||
* Multiple devices can use the same AppEUI, but each device has its own |
|||
* DevEUI and AppKey. |
|||
* |
|||
* Do not forget to define the radio type correctly in config.h. |
|||
* |
|||
*******************************************************************************/ |
|||
|
|||
#include <lmic.h>
|
|||
#include <hal/hal.h>
|
|||
#include <SPI.h>
|
|||
|
|||
// This EUI must be in little-endian format, so least-significant-byte
|
|||
// first. When copying an EUI from ttnctl output, this means to reverse
|
|||
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
|
|||
// 0x70.
|
|||
static const u1_t PROGMEM APPEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
|||
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);} |
|||
|
|||
// This should also be in little endian format, see above.
|
|||
static const u1_t PROGMEM DEVEUI[8]={ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; |
|||
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);} |
|||
|
|||
// This key should be in big endian format (or, since it is not really a
|
|||
// number but a block of memory, endianness does not really apply). In
|
|||
// practice, a key taken from ttnctl can be copied as-is.
|
|||
// The key shown here is the semtech default key.
|
|||
static const u1_t PROGMEM APPKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; |
|||
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);} |
|||
|
|||
static uint8_t mydata[] = "Hello, world!"; |
|||
static osjob_t sendjob; |
|||
|
|||
// Schedule TX every this many seconds (might become longer due to duty
|
|||
// cycle limitations).
|
|||
const unsigned TX_INTERVAL = 60; |
|||
|
|||
// Pin mapping
|
|||
const lmic_pinmap lmic_pins = { |
|||
.nss = 6, |
|||
.rxtx = LMIC_UNUSED_PIN, |
|||
.rst = 5, |
|||
.dio = {2, 3, 4}, |
|||
}; |
|||
|
|||
void onEvent (ev_t ev) { |
|||
Serial.print(os_getTime()); |
|||
Serial.print(": "); |
|||
switch(ev) { |
|||
case EV_SCAN_TIMEOUT: |
|||
Serial.println(F("EV_SCAN_TIMEOUT")); |
|||
break; |
|||
case EV_BEACON_FOUND: |
|||
Serial.println(F("EV_BEACON_FOUND")); |
|||
break; |
|||
case EV_BEACON_MISSED: |
|||
Serial.println(F("EV_BEACON_MISSED")); |
|||
break; |
|||
case EV_BEACON_TRACKED: |
|||
Serial.println(F("EV_BEACON_TRACKED")); |
|||
break; |
|||
case EV_JOINING: |
|||
Serial.println(F("EV_JOINING")); |
|||
break; |
|||
case EV_JOINED: |
|||
Serial.println(F("EV_JOINED")); |
|||
|
|||
// Disable link check validation (automatically enabled
|
|||
// during join, but not supported by TTN at this time).
|
|||
LMIC_setLinkCheckMode(0); |
|||
break; |
|||
case EV_RFU1: |
|||
Serial.println(F("EV_RFU1")); |
|||
break; |
|||
case EV_JOIN_FAILED: |
|||
Serial.println(F("EV_JOIN_FAILED")); |
|||
break; |
|||
case EV_REJOIN_FAILED: |
|||
Serial.println(F("EV_REJOIN_FAILED")); |
|||
break; |
|||
break; |
|||
case EV_TXCOMPLETE: |
|||
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); |
|||
if (LMIC.txrxFlags & TXRX_ACK) |
|||
Serial.println(F("Received ack")); |
|||
if (LMIC.dataLen) { |
|||
Serial.println(F("Received ")); |
|||
Serial.println(LMIC.dataLen); |
|||
Serial.println(F(" bytes of payload")); |
|||
} |
|||
// Schedule next transmission
|
|||
os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send); |
|||
break; |
|||
case EV_LOST_TSYNC: |
|||
Serial.println(F("EV_LOST_TSYNC")); |
|||
break; |
|||
case EV_RESET: |
|||
Serial.println(F("EV_RESET")); |
|||
break; |
|||
case EV_RXCOMPLETE: |
|||
// data received in ping slot
|
|||
Serial.println(F("EV_RXCOMPLETE")); |
|||
break; |
|||
case EV_LINK_DEAD: |
|||
Serial.println(F("EV_LINK_DEAD")); |
|||
break; |
|||
case EV_LINK_ALIVE: |
|||
Serial.println(F("EV_LINK_ALIVE")); |
|||
break; |
|||
default: |
|||
Serial.println(F("Unknown event")); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
void do_send(osjob_t* j){ |
|||
// Check if there is not a current TX/RX job running
|
|||
if (LMIC.opmode & OP_TXRXPEND) { |
|||
Serial.println(F("OP_TXRXPEND, not sending")); |
|||
} else { |
|||
// Prepare upstream data transmission at the next possible time.
|
|||
LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0); |
|||
Serial.println(F("Packet queued")); |
|||
} |
|||
// Next TX is scheduled after TX_COMPLETE event.
|
|||
} |
|||
|
|||
void setup() { |
|||
Serial.begin(9600); |
|||
Serial.println(F("Starting")); |
|||
|
|||
#ifdef VCC_ENABLE
|
|||
// For Pinoccio Scout boards
|
|||
pinMode(VCC_ENABLE, OUTPUT); |
|||
digitalWrite(VCC_ENABLE, HIGH); |
|||
delay(1000); |
|||
#endif
|
|||
|
|||
// LMIC init
|
|||
os_init(); |
|||
// Reset the MAC state. Session and pending data transfers will be discarded.
|
|||
LMIC_reset(); |
|||
|
|||
// Start job (sending automatically starts OTAA too)
|
|||
do_send(&sendjob); |
|||
} |
|||
|
|||
void loop() { |
|||
os_runloop_once(); |
|||
} |
@ -0,0 +1,207 @@ |
|||
/*******************************************************************************
|
|||
* Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman |
|||
* |
|||
* Permission is hereby granted, free of charge, to anyone |
|||
* obtaining a copy of this document and accompanying files, |
|||
* to do whatever they want with them without any restriction, |
|||
* including, but not limited to, copying, modification and redistribution. |
|||
* NO WARRANTY OF ANY KIND IS PROVIDED. |
|||
* |
|||
* This example sends a valid LoRaWAN packet with payload "Hello, |
|||
* world!", using frequency and encryption settings matching those of |
|||
* the (early prototype version of) The Things Network. |
|||
* |
|||
* Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in g1, |
|||
* 0.1% in g2). |
|||
* |
|||
* Change DEVADDR to a unique address! |
|||
* See http://thethingsnetwork.org/wiki/AddressSpace
|
|||
* |
|||
* Do not forget to define the radio type correctly in config.h. |
|||
* |
|||
*******************************************************************************/ |
|||
|
|||
#include <lmic.h>
|
|||
#include <hal/hal.h>
|
|||
#include <SPI.h>
|
|||
|
|||
// LoRaWAN NwkSKey, network session key
|
|||
// This is the default Semtech key, which is used by the prototype TTN
|
|||
// network initially.
|
|||
static const PROGMEM u1_t NWKSKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; |
|||
|
|||
// LoRaWAN AppSKey, application session key
|
|||
// This is the default Semtech key, which is used by the prototype TTN
|
|||
// network initially.
|
|||
static const u1_t PROGMEM APPSKEY[16] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; |
|||
|
|||
// LoRaWAN end-device address (DevAddr)
|
|||
// See http://thethingsnetwork.org/wiki/AddressSpace
|
|||
static const u4_t DEVADDR = 0x03FF0001 ; // <-- Change this address for every node!
|
|||
|
|||
// These callbacks are only used in over-the-air activation, so they are
|
|||
// left empty here (we cannot leave them out completely unless
|
|||
// DISABLE_JOIN is set in config.h, otherwise the linker will complain).
|
|||
void os_getArtEui (u1_t* buf) { } |
|||
void os_getDevEui (u1_t* buf) { } |
|||
void os_getDevKey (u1_t* buf) { } |
|||
|
|||
static uint8_t mydata[] = "Hello, world!"; |
|||
static osjob_t sendjob; |
|||
|
|||
// Schedule TX every this many seconds (might become longer due to duty
|
|||
// cycle limitations).
|
|||
const unsigned TX_INTERVAL = 60; |
|||
|
|||
// Pin mapping
|
|||
const lmic_pinmap lmic_pins = { |
|||
.nss = 6, |
|||
.rxtx = LMIC_UNUSED_PIN, |
|||
.rst = 5, |
|||
.dio = {2, 3, 4}, |
|||
}; |
|||
|
|||
void onEvent (ev_t ev) { |
|||
Serial.print(os_getTime()); |
|||
Serial.print(": "); |
|||
switch(ev) { |
|||
case EV_SCAN_TIMEOUT: |
|||
Serial.println(F("EV_SCAN_TIMEOUT")); |
|||
break; |
|||
case EV_BEACON_FOUND: |
|||
Serial.println(F("EV_BEACON_FOUND")); |
|||
break; |
|||
case EV_BEACON_MISSED: |
|||
Serial.println(F("EV_BEACON_MISSED")); |
|||
break; |
|||
case EV_BEACON_TRACKED: |
|||
Serial.println(F("EV_BEACON_TRACKED")); |
|||
break; |
|||
case EV_JOINING: |
|||
Serial.println(F("EV_JOINING")); |
|||
break; |
|||
case EV_JOINED: |
|||
Serial.println(F("EV_JOINED")); |
|||
break; |
|||
case EV_RFU1: |
|||
Serial.println(F("EV_RFU1")); |
|||
break; |
|||
case EV_JOIN_FAILED: |
|||
Serial.println(F("EV_JOIN_FAILED")); |
|||
break; |
|||
case EV_REJOIN_FAILED: |
|||
Serial.println(F("EV_REJOIN_FAILED")); |
|||
break; |
|||
break; |
|||
case EV_TXCOMPLETE: |
|||
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); |
|||
if(LMIC.dataLen) { |
|||
// data received in rx slot after tx
|
|||
Serial.print(F("Data Received: ")); |
|||
Serial.write(LMIC.frame+LMIC.dataBeg, LMIC.dataLen); |
|||
Serial.println(); |
|||
} |
|||
// Schedule next transmission
|
|||