Skip to content

Commit f118410

Browse files
committed
lora: sensor-lorawan: Initial commit
Signed-off-by: Alistair Francis <[email protected]>
1 parent e0ddbe6 commit f118410

File tree

8 files changed

+486
-1
lines changed

8 files changed

+486
-1
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
build/
22
.vscode/
3+
examples/lora/sensor-lorawan/radioConfig.h
+219
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*
2+
* The Cayenne Low Power Payload (LPP) provides a convenient and
3+
* easy way to send data over LPWAN networks such as LoRaWAN. The Cayenne LPP
4+
* is compliant with the payload size restriction, which can be lowered down to
5+
* 11 bytes, and allows the device to send multiple sensor data at one time.
6+
*
7+
* CayenneLPP is also support by TTN:
8+
* https://www.thethingsindustries.com/docs/integrations/payload-formatters/cayenne/
9+
*
10+
* This code is direct from: https://github.com/myDevicesIoT/CayenneLPP
11+
*
12+
* GPL-3.0 license
13+
* See https://github.com/myDevicesIoT/CayenneLPP for license details
14+
*/
15+
16+
#include "CayenneLPP.h"
17+
18+
CayenneLPP::CayenneLPP(uint8_t size) : maxsize(size) {
19+
buffer = (uint8_t*) malloc(size);
20+
cursor = 0;
21+
}
22+
23+
CayenneLPP::~CayenneLPP(void) {
24+
free(buffer);
25+
}
26+
27+
void CayenneLPP::reset(void) {
28+
cursor = 0;
29+
}
30+
31+
uint8_t CayenneLPP::getSize(void) {
32+
return cursor;
33+
}
34+
35+
uint8_t* CayenneLPP::getBuffer(void) {
36+
// uint8_t[cursor] result;
37+
// memcpy(result, buffer, cursor);
38+
// return result;
39+
return buffer;
40+
}
41+
42+
uint8_t CayenneLPP::copy(uint8_t* dst) {
43+
memcpy(dst, buffer, cursor);
44+
return cursor;
45+
}
46+
47+
uint8_t CayenneLPP::addDigitalInput(uint8_t channel, uint8_t value) {
48+
if ((cursor + LPP_DIGITAL_INPUT_SIZE) > maxsize) {
49+
return 0;
50+
}
51+
buffer[cursor++] = channel;
52+
buffer[cursor++] = LPP_DIGITAL_INPUT;
53+
buffer[cursor++] = value;
54+
55+
return cursor;
56+
}
57+
58+
uint8_t CayenneLPP::addDigitalOutput(uint8_t channel, uint8_t value) {
59+
if ((cursor + LPP_DIGITAL_OUTPUT_SIZE) > maxsize) {
60+
return 0;
61+
}
62+
buffer[cursor++] = channel;
63+
buffer[cursor++] = LPP_DIGITAL_OUTPUT;
64+
buffer[cursor++] = value;
65+
66+
return cursor;
67+
}
68+
69+
uint8_t CayenneLPP::addAnalogInput(uint8_t channel, float value) {
70+
if ((cursor + LPP_ANALOG_INPUT_SIZE) > maxsize) {
71+
return 0;
72+
}
73+
74+
int16_t val = value * 100;
75+
buffer[cursor++] = channel;
76+
buffer[cursor++] = LPP_ANALOG_INPUT;
77+
buffer[cursor++] = val >> 8;
78+
buffer[cursor++] = val;
79+
80+
return cursor;
81+
}
82+
83+
uint8_t CayenneLPP::addAnalogOutput(uint8_t channel, float value) {
84+
if ((cursor + LPP_ANALOG_OUTPUT_SIZE) > maxsize) {
85+
return 0;
86+
}
87+
int16_t val = value * 100;
88+
buffer[cursor++] = channel;
89+
buffer[cursor++] = LPP_ANALOG_OUTPUT;
90+
buffer[cursor++] = val >> 8;
91+
buffer[cursor++] = val;
92+
93+
return cursor;
94+
}
95+
96+
uint8_t CayenneLPP::addLuminosity(uint8_t channel, uint16_t lux) {
97+
if ((cursor + LPP_LUMINOSITY_SIZE) > maxsize) {
98+
return 0;
99+
}
100+
buffer[cursor++] = channel;
101+
buffer[cursor++] = LPP_LUMINOSITY;
102+
buffer[cursor++] = lux >> 8;
103+
buffer[cursor++] = lux;
104+
105+
return cursor;
106+
}
107+
108+
uint8_t CayenneLPP::addPresence(uint8_t channel, uint8_t value) {
109+
if ((cursor + LPP_PRESENCE_SIZE) > maxsize) {
110+
return 0;
111+
}
112+
buffer[cursor++] = channel;
113+
buffer[cursor++] = LPP_PRESENCE;
114+
buffer[cursor++] = value;
115+
116+
return cursor;
117+
}
118+
119+
uint8_t CayenneLPP::addTemperature(uint8_t channel, float celsius) {
120+
if ((cursor + LPP_TEMPERATURE_SIZE) > maxsize) {
121+
return 0;
122+
}
123+
int16_t val = celsius * 10;
124+
buffer[cursor++] = channel;
125+
buffer[cursor++] = LPP_TEMPERATURE;
126+
buffer[cursor++] = val >> 8;
127+
buffer[cursor++] = val;
128+
129+
return cursor;
130+
}
131+
132+
uint8_t CayenneLPP::addRelativeHumidity(uint8_t channel, float rh) {
133+
if ((cursor + LPP_RELATIVE_HUMIDITY_SIZE) > maxsize) {
134+
return 0;
135+
}
136+
buffer[cursor++] = channel;
137+
buffer[cursor++] = LPP_RELATIVE_HUMIDITY;
138+
buffer[cursor++] = rh * 2;
139+
140+
return cursor;
141+
}
142+
143+
uint8_t CayenneLPP::addAccelerometer(uint8_t channel, float x, float y, float z) {
144+
if ((cursor + LPP_ACCELEROMETER_SIZE) > maxsize) {
145+
return 0;
146+
}
147+
int16_t vx = x * 1000;
148+
int16_t vy = y * 1000;
149+
int16_t vz = z * 1000;
150+
151+
buffer[cursor++] = channel;
152+
buffer[cursor++] = LPP_ACCELEROMETER;
153+
buffer[cursor++] = vx >> 8;
154+
buffer[cursor++] = vx;
155+
buffer[cursor++] = vy >> 8;
156+
buffer[cursor++] = vy;
157+
buffer[cursor++] = vz >> 8;
158+
buffer[cursor++] = vz;
159+
160+
return cursor;
161+
}
162+
163+
uint8_t CayenneLPP::addBarometricPressure(uint8_t channel, float hpa) {
164+
if ((cursor + LPP_BAROMETRIC_PRESSURE_SIZE) > maxsize) {
165+
return 0;
166+
}
167+
int16_t val = hpa * 10;
168+
169+
buffer[cursor++] = channel;
170+
buffer[cursor++] = LPP_BAROMETRIC_PRESSURE;
171+
buffer[cursor++] = val >> 8;
172+
buffer[cursor++] = val;
173+
174+
return cursor;
175+
}
176+
177+
uint8_t CayenneLPP::addGyrometer(uint8_t channel, float x, float y, float z) {
178+
if ((cursor + LPP_GYROMETER_SIZE) > maxsize) {
179+
return 0;
180+
}
181+
int16_t vx = x * 100;
182+
int16_t vy = y * 100;
183+
int16_t vz = z * 100;
184+
185+
buffer[cursor++] = channel;
186+
buffer[cursor++] = LPP_GYROMETER;
187+
buffer[cursor++] = vx >> 8;
188+
buffer[cursor++] = vx;
189+
buffer[cursor++] = vy >> 8;
190+
buffer[cursor++] = vy;
191+
buffer[cursor++] = vz >> 8;
192+
buffer[cursor++] = vz;
193+
194+
return cursor;
195+
}
196+
197+
uint8_t CayenneLPP::addGPS(uint8_t channel, float latitude, float longitude, float meters) {
198+
if ((cursor + LPP_GPS_SIZE) > maxsize) {
199+
return 0;
200+
}
201+
int32_t lat = latitude * 10000;
202+
int32_t lon = longitude * 10000;
203+
int32_t alt = meters * 100;
204+
205+
buffer[cursor++] = channel;
206+
buffer[cursor++] = LPP_GPS;
207+
208+
buffer[cursor++] = lat >> 16;
209+
buffer[cursor++] = lat >> 8;
210+
buffer[cursor++] = lat;
211+
buffer[cursor++] = lon >> 16;
212+
buffer[cursor++] = lon >> 8;
213+
buffer[cursor++] = lon;
214+
buffer[cursor++] = alt >> 16;
215+
buffer[cursor++] = alt >> 8;
216+
buffer[cursor++] = alt;
217+
218+
return cursor;
219+
}
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* The Cayenne Low Power Payload (LPP) provides a convenient and
3+
* easy way to send data over LPWAN networks such as LoRaWAN. The Cayenne LPP
4+
* is compliant with the payload size restriction, which can be lowered down to
5+
* 11 bytes, and allows the device to send multiple sensor data at one time.
6+
*
7+
* CayenneLPP is also support by TTN:
8+
* https://www.thethingsindustries.com/docs/integrations/payload-formatters/cayenne/
9+
*
10+
* This code is direct from: https://github.com/myDevicesIoT/CayenneLPP
11+
*
12+
* GPL-3.0 license
13+
* See https://github.com/myDevicesIoT/CayenneLPP for license details
14+
*/
15+
16+
#ifndef _CAYENNE_LPP_H_
17+
#define _CAYENNE_LPP_H_
18+
19+
#include <cstdint>
20+
#include <stdlib.h>
21+
#include <cstring>
22+
23+
#define LPP_DIGITAL_INPUT 0 // 1 byte
24+
#define LPP_DIGITAL_OUTPUT 1 // 1 byte
25+
#define LPP_ANALOG_INPUT 2 // 2 bytes, 0.01 signed
26+
#define LPP_ANALOG_OUTPUT 3 // 2 bytes, 0.01 signed
27+
#define LPP_LUMINOSITY 101 // 2 bytes, 1 lux unsigned
28+
#define LPP_PRESENCE 102 // 1 byte, 1
29+
#define LPP_TEMPERATURE 103 // 2 bytes, 0.1°C signed
30+
#define LPP_RELATIVE_HUMIDITY 104 // 1 byte, 0.5% unsigned
31+
#define LPP_ACCELEROMETER 113 // 2 bytes per axis, 0.001G
32+
#define LPP_BAROMETRIC_PRESSURE 115 // 2 bytes 0.1 hPa Unsigned
33+
#define LPP_GYROMETER 134 // 2 bytes per axis, 0.01 °/s
34+
#define LPP_GPS 136 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01 meter
35+
36+
37+
// Data ID + Data Type + Data Size
38+
#define LPP_DIGITAL_INPUT_SIZE 3 // 1 byte
39+
#define LPP_DIGITAL_OUTPUT_SIZE 3 // 1 byte
40+
#define LPP_ANALOG_INPUT_SIZE 4 // 2 bytes, 0.01 signed
41+
#define LPP_ANALOG_OUTPUT_SIZE 4 // 2 bytes, 0.01 signed
42+
#define LPP_LUMINOSITY_SIZE 4 // 2 bytes, 1 lux unsigned
43+
#define LPP_PRESENCE_SIZE 3 // 1 byte, 1
44+
#define LPP_TEMPERATURE_SIZE 4 // 2 bytes, 0.1°C signed
45+
#define LPP_RELATIVE_HUMIDITY_SIZE 3 // 1 byte, 0.5% unsigned
46+
#define LPP_ACCELEROMETER_SIZE 8 // 2 bytes per axis, 0.001G
47+
#define LPP_BAROMETRIC_PRESSURE_SIZE 4 // 2 bytes 0.1 hPa Unsigned
48+
#define LPP_GYROMETER_SIZE 8 // 2 bytes per axis, 0.01 °/s
49+
#define LPP_GPS_SIZE 11 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01 meter
50+
51+
52+
class CayenneLPP {
53+
public:
54+
CayenneLPP(uint8_t size);
55+
~CayenneLPP();
56+
57+
void reset(void);
58+
uint8_t getSize(void);
59+
uint8_t* getBuffer(void);
60+
uint8_t copy(uint8_t* buffer);
61+
62+
uint8_t addDigitalInput(uint8_t channel, uint8_t value);
63+
uint8_t addDigitalOutput(uint8_t channel, uint8_t value);
64+
65+
uint8_t addAnalogInput(uint8_t channel, float value);
66+
uint8_t addAnalogOutput(uint8_t channel, float value);
67+
68+
uint8_t addLuminosity(uint8_t channel, uint16_t lux);
69+
uint8_t addPresence(uint8_t channel, uint8_t value);
70+
uint8_t addTemperature(uint8_t channel, float celsius);
71+
uint8_t addRelativeHumidity(uint8_t channel, float rh);
72+
uint8_t addAccelerometer(uint8_t channel, float x, float y, float z);
73+
uint8_t addBarometricPressure(uint8_t channel, float hpa);
74+
uint8_t addGyrometer(uint8_t channel, float x, float y, float z);
75+
uint8_t addGPS(uint8_t channel, float latitude, float longitude, float meters);
76+
77+
private:
78+
uint8_t *buffer;
79+
uint8_t maxsize;
80+
uint8_t cursor;
81+
82+
83+
};
84+
85+
86+
#endif

examples/lora/sensor-lorawan/Makefile

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Makefile for user application
2+
3+
# Specify this directory relative to the current application.
4+
TOCK_USERLAND_BASE_DIR = ../../../
5+
6+
STACK_SIZE = 4096
7+
8+
# Which files to compile.
9+
CXX_SRCS := $(wildcard *.cc)
10+
11+
# Include the core RadioLib headers
12+
override CPPFLAGS += -isystem $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/src
13+
14+
# Include the Tock specific headers
15+
override CPPFLAGS += -isystem $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/examples/NonArduino/Tock
16+
17+
# Include the base of libtock-c to fix the libtock/ includes from RadioLib
18+
override CPPFLAGS += -I$(TOCK_USERLAND_BASE_DIR)/ -DRADIOLIB_CLOCK_DRIFT_MS=9
19+
20+
ifneq ($(CI),)
21+
override CPPFLAGS += "-DRADIO_CONFIG_CI=radioConfig_example.h"
22+
endif
23+
24+
# Use the libtock-c Make system
25+
LIBS_cortex-m0 += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/cortex-m0/RadioLib.a
26+
LIBS_cortex-m3 += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/cortex-m3/RadioLib.a
27+
LIBS_cortex-m4 += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/cortex-m4/RadioLib.a
28+
LIBS_cortex-m7 += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/cortex-m7/RadioLib.a
29+
30+
LIBS_rv32imc += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/rv32imc/RadioLib.a
31+
LIBS_rv32imac += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/rv32imac/RadioLib.a
32+
33+
EXTERN_LIBS := $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib
34+
include $(TOCK_USERLAND_BASE_DIR)/libradio/Makefile
35+
36+
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Sensor LoRaWAN Transmitter
2+
==========================
3+
4+
This example builds an application to transmit sensor data via LoRaWAN.
5+
6+
See https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md
7+
for notes on setting up the LoRaWAN device.
8+
9+
The most important part is creating a radioConfig.h file with the secrets
10+
from your LoRaWAN server and any country specific settings. There is an
11+
existing radioConfig_example.h which can be used as a useful starting point.
12+
13+
This has been tested against The Things Network. Before changing settings
14+
make sure you consider regulatory duty cycles and TTN's Fair Usage Policy,
15+
for example don't drop the delay in the loop, otherwise you will break the
16+
TTN Fair Usage Policy.

0 commit comments

Comments
 (0)