Skip to content

Commit

Permalink
lora: sensor-lorawan: Initial commit
Browse files Browse the repository at this point in the history
Signed-off-by: Alistair Francis <[email protected]>
  • Loading branch information
alistair23 committed Jul 19, 2024
1 parent e0ddbe6 commit 5e43d89
Show file tree
Hide file tree
Showing 6 changed files with 464 additions and 1 deletion.
219 changes: 219 additions & 0 deletions examples/lora/sensor-lorawan/CayenneLPP.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
/*
* The Cayenne Low Power Payload (LPP) provides a convenient and
* easy way to send data over LPWAN networks such as LoRaWAN. The Cayenne LPP
* is compliant with the payload size restriction, which can be lowered down to
* 11 bytes, and allows the device to send multiple sensor data at one time.
*
* CayenneLPP is also support by TTN:
* https://www.thethingsindustries.com/docs/integrations/payload-formatters/cayenne/
*
* This code is direct from: https://github.com/myDevicesIoT/CayenneLPP
*
* GPL-3.0 license
* See https://github.com/myDevicesIoT/CayenneLPP for license details
*/

#include "CayenneLPP.h"

CayenneLPP::CayenneLPP(uint8_t size) : maxsize(size) {
buffer = (uint8_t*) malloc(size);
cursor = 0;
}

CayenneLPP::~CayenneLPP(void) {
free(buffer);
}

void CayenneLPP::reset(void) {
cursor = 0;
}

uint8_t CayenneLPP::getSize(void) {
return cursor;
}

uint8_t* CayenneLPP::getBuffer(void) {
// uint8_t[cursor] result;
// memcpy(result, buffer, cursor);
// return result;
return buffer;
}

uint8_t CayenneLPP::copy(uint8_t* dst) {
memcpy(dst, buffer, cursor);
return cursor;
}

uint8_t CayenneLPP::addDigitalInput(uint8_t channel, uint8_t value) {
if ((cursor + LPP_DIGITAL_INPUT_SIZE) > maxsize) {
return 0;
}
buffer[cursor++] = channel;
buffer[cursor++] = LPP_DIGITAL_INPUT;
buffer[cursor++] = value;

return cursor;
}

uint8_t CayenneLPP::addDigitalOutput(uint8_t channel, uint8_t value) {
if ((cursor + LPP_DIGITAL_OUTPUT_SIZE) > maxsize) {
return 0;
}
buffer[cursor++] = channel;
buffer[cursor++] = LPP_DIGITAL_OUTPUT;
buffer[cursor++] = value;

return cursor;
}

uint8_t CayenneLPP::addAnalogInput(uint8_t channel, float value) {
if ((cursor + LPP_ANALOG_INPUT_SIZE) > maxsize) {
return 0;
}

int16_t val = value * 100;
buffer[cursor++] = channel;
buffer[cursor++] = LPP_ANALOG_INPUT;
buffer[cursor++] = val >> 8;
buffer[cursor++] = val;

return cursor;
}

uint8_t CayenneLPP::addAnalogOutput(uint8_t channel, float value) {
if ((cursor + LPP_ANALOG_OUTPUT_SIZE) > maxsize) {
return 0;
}
int16_t val = value * 100;
buffer[cursor++] = channel;
buffer[cursor++] = LPP_ANALOG_OUTPUT;
buffer[cursor++] = val >> 8;
buffer[cursor++] = val;

return cursor;
}

uint8_t CayenneLPP::addLuminosity(uint8_t channel, uint16_t lux) {
if ((cursor + LPP_LUMINOSITY_SIZE) > maxsize) {
return 0;
}
buffer[cursor++] = channel;
buffer[cursor++] = LPP_LUMINOSITY;
buffer[cursor++] = lux >> 8;
buffer[cursor++] = lux;

return cursor;
}

uint8_t CayenneLPP::addPresence(uint8_t channel, uint8_t value) {
if ((cursor + LPP_PRESENCE_SIZE) > maxsize) {
return 0;
}
buffer[cursor++] = channel;
buffer[cursor++] = LPP_PRESENCE;
buffer[cursor++] = value;

return cursor;
}

uint8_t CayenneLPP::addTemperature(uint8_t channel, float celsius) {
if ((cursor + LPP_TEMPERATURE_SIZE) > maxsize) {
return 0;
}
int16_t val = celsius * 10;
buffer[cursor++] = channel;
buffer[cursor++] = LPP_TEMPERATURE;
buffer[cursor++] = val >> 8;
buffer[cursor++] = val;

return cursor;
}

uint8_t CayenneLPP::addRelativeHumidity(uint8_t channel, float rh) {
if ((cursor + LPP_RELATIVE_HUMIDITY_SIZE) > maxsize) {
return 0;
}
buffer[cursor++] = channel;
buffer[cursor++] = LPP_RELATIVE_HUMIDITY;
buffer[cursor++] = rh * 2;

return cursor;
}

uint8_t CayenneLPP::addAccelerometer(uint8_t channel, float x, float y, float z) {
if ((cursor + LPP_ACCELEROMETER_SIZE) > maxsize) {
return 0;
}
int16_t vx = x * 1000;
int16_t vy = y * 1000;
int16_t vz = z * 1000;

buffer[cursor++] = channel;
buffer[cursor++] = LPP_ACCELEROMETER;
buffer[cursor++] = vx >> 8;
buffer[cursor++] = vx;
buffer[cursor++] = vy >> 8;
buffer[cursor++] = vy;
buffer[cursor++] = vz >> 8;
buffer[cursor++] = vz;

return cursor;
}

uint8_t CayenneLPP::addBarometricPressure(uint8_t channel, float hpa) {
if ((cursor + LPP_BAROMETRIC_PRESSURE_SIZE) > maxsize) {
return 0;
}
int16_t val = hpa * 10;

buffer[cursor++] = channel;
buffer[cursor++] = LPP_BAROMETRIC_PRESSURE;
buffer[cursor++] = val >> 8;
buffer[cursor++] = val;

return cursor;
}

uint8_t CayenneLPP::addGyrometer(uint8_t channel, float x, float y, float z) {
if ((cursor + LPP_GYROMETER_SIZE) > maxsize) {
return 0;
}
int16_t vx = x * 100;
int16_t vy = y * 100;
int16_t vz = z * 100;

buffer[cursor++] = channel;
buffer[cursor++] = LPP_GYROMETER;
buffer[cursor++] = vx >> 8;
buffer[cursor++] = vx;
buffer[cursor++] = vy >> 8;
buffer[cursor++] = vy;
buffer[cursor++] = vz >> 8;
buffer[cursor++] = vz;

return cursor;
}

uint8_t CayenneLPP::addGPS(uint8_t channel, float latitude, float longitude, float meters) {
if ((cursor + LPP_GPS_SIZE) > maxsize) {
return 0;
}
int32_t lat = latitude * 10000;
int32_t lon = longitude * 10000;
int32_t alt = meters * 100;

buffer[cursor++] = channel;
buffer[cursor++] = LPP_GPS;

buffer[cursor++] = lat >> 16;
buffer[cursor++] = lat >> 8;
buffer[cursor++] = lat;
buffer[cursor++] = lon >> 16;
buffer[cursor++] = lon >> 8;
buffer[cursor++] = lon;
buffer[cursor++] = alt >> 16;
buffer[cursor++] = alt >> 8;
buffer[cursor++] = alt;

return cursor;
}
86 changes: 86 additions & 0 deletions examples/lora/sensor-lorawan/CayenneLPP.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* The Cayenne Low Power Payload (LPP) provides a convenient and
* easy way to send data over LPWAN networks such as LoRaWAN. The Cayenne LPP
* is compliant with the payload size restriction, which can be lowered down to
* 11 bytes, and allows the device to send multiple sensor data at one time.
*
* CayenneLPP is also support by TTN:
* https://www.thethingsindustries.com/docs/integrations/payload-formatters/cayenne/
*
* This code is direct from: https://github.com/myDevicesIoT/CayenneLPP
*
* GPL-3.0 license
* See https://github.com/myDevicesIoT/CayenneLPP for license details
*/

#ifndef _CAYENNE_LPP_H_
#define _CAYENNE_LPP_H_

#include <cstdint>
#include <stdlib.h>
#include <cstring>

#define LPP_DIGITAL_INPUT 0 // 1 byte
#define LPP_DIGITAL_OUTPUT 1 // 1 byte
#define LPP_ANALOG_INPUT 2 // 2 bytes, 0.01 signed
#define LPP_ANALOG_OUTPUT 3 // 2 bytes, 0.01 signed
#define LPP_LUMINOSITY 101 // 2 bytes, 1 lux unsigned
#define LPP_PRESENCE 102 // 1 byte, 1
#define LPP_TEMPERATURE 103 // 2 bytes, 0.1°C signed
#define LPP_RELATIVE_HUMIDITY 104 // 1 byte, 0.5% unsigned
#define LPP_ACCELEROMETER 113 // 2 bytes per axis, 0.001G
#define LPP_BAROMETRIC_PRESSURE 115 // 2 bytes 0.1 hPa Unsigned
#define LPP_GYROMETER 134 // 2 bytes per axis, 0.01 °/s
#define LPP_GPS 136 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01 meter


// Data ID + Data Type + Data Size
#define LPP_DIGITAL_INPUT_SIZE 3 // 1 byte
#define LPP_DIGITAL_OUTPUT_SIZE 3 // 1 byte
#define LPP_ANALOG_INPUT_SIZE 4 // 2 bytes, 0.01 signed
#define LPP_ANALOG_OUTPUT_SIZE 4 // 2 bytes, 0.01 signed
#define LPP_LUMINOSITY_SIZE 4 // 2 bytes, 1 lux unsigned
#define LPP_PRESENCE_SIZE 3 // 1 byte, 1
#define LPP_TEMPERATURE_SIZE 4 // 2 bytes, 0.1°C signed
#define LPP_RELATIVE_HUMIDITY_SIZE 3 // 1 byte, 0.5% unsigned
#define LPP_ACCELEROMETER_SIZE 8 // 2 bytes per axis, 0.001G
#define LPP_BAROMETRIC_PRESSURE_SIZE 4 // 2 bytes 0.1 hPa Unsigned
#define LPP_GYROMETER_SIZE 8 // 2 bytes per axis, 0.01 °/s
#define LPP_GPS_SIZE 11 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01 meter


class CayenneLPP {
public:
CayenneLPP(uint8_t size);
~CayenneLPP();

void reset(void);
uint8_t getSize(void);
uint8_t* getBuffer(void);
uint8_t copy(uint8_t* buffer);

uint8_t addDigitalInput(uint8_t channel, uint8_t value);
uint8_t addDigitalOutput(uint8_t channel, uint8_t value);

uint8_t addAnalogInput(uint8_t channel, float value);
uint8_t addAnalogOutput(uint8_t channel, float value);

uint8_t addLuminosity(uint8_t channel, uint16_t lux);
uint8_t addPresence(uint8_t channel, uint8_t value);
uint8_t addTemperature(uint8_t channel, float celsius);
uint8_t addRelativeHumidity(uint8_t channel, float rh);
uint8_t addAccelerometer(uint8_t channel, float x, float y, float z);
uint8_t addBarometricPressure(uint8_t channel, float hpa);
uint8_t addGyrometer(uint8_t channel, float x, float y, float z);
uint8_t addGPS(uint8_t channel, float latitude, float longitude, float meters);

private:
uint8_t *buffer;
uint8_t maxsize;
uint8_t cursor;


};


#endif
32 changes: 32 additions & 0 deletions examples/lora/sensor-lorawan/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Makefile for user application

# Specify this directory relative to the current application.
TOCK_USERLAND_BASE_DIR = ../../../

STACK_SIZE = 4096

# Which files to compile.
CXX_SRCS := $(wildcard *.cc)

# Include the core RadioLib headers
override CPPFLAGS += -isystem $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/src

# Include the Tock specific headers
override CPPFLAGS += -isystem $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/examples/NonArduino/Tock

# Include the base of libtock-c to fix the libtock/ includes from RadioLib
override CPPFLAGS += -I$(TOCK_USERLAND_BASE_DIR)/ -DRADIOLIB_CLOCK_DRIFT_MS=9

# Use the libtock-c Make system
LIBS_cortex-m0 += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/cortex-m0/RadioLib.a
LIBS_cortex-m3 += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/cortex-m3/RadioLib.a
LIBS_cortex-m4 += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/cortex-m4/RadioLib.a
LIBS_cortex-m7 += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/cortex-m7/RadioLib.a

LIBS_rv32imc += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/rv32imc/RadioLib.a
LIBS_rv32imac += $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib/build/rv32imac/RadioLib.a

EXTERN_LIBS := $(TOCK_USERLAND_BASE_DIR)/libradio/RadioLib
include $(TOCK_USERLAND_BASE_DIR)/libradio/Makefile

include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
14 changes: 14 additions & 0 deletions examples/lora/sensor-lorawan/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Sensor LoRaWAN Transmitter
==========================

This example builds an application to transmit sensor data via LoRaWAN.

See https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md
for notes on setting up the LoRaWAN device. The most important part is modifying
main.cc with the secrets from your LoRaWAN server and any country specific
settings.

This has been tested against The Things Network. Before changing settings
make sure you consider regulatory duty cycles and TTN's Fair Usage Policy,
for example don't drop the delay in the loop, otherwise you will break the
TTN Fair Usage Policy.
Loading

0 comments on commit 5e43d89

Please sign in to comment.