a bit of of tidy up and uniformity
This commit is contained in:
parent
6748ddb59c
commit
d901ffb32a
2 changed files with 84 additions and 31 deletions
|
|
@ -13,6 +13,9 @@
|
||||||
* so that a host computer can then do whatever is needed with it (i.e.
|
* so that a host computer can then do whatever is needed with it (i.e.
|
||||||
* send out to IP network via MQTT, or place into a database, etc.)
|
* send out to IP network via MQTT, or place into a database, etc.)
|
||||||
*
|
*
|
||||||
|
* DISCLAIMER: The code is in no way warranted to be fit for any purpose at
|
||||||
|
* all. In fact it is almost certainly "buggy as hell". You have been warned.
|
||||||
|
*
|
||||||
* Yvan Seth <allotment.sensors@seth.id.au>
|
* Yvan Seth <allotment.sensors@seth.id.au>
|
||||||
* https://yvan.seth.id.au/tag/lora.html
|
* https://yvan.seth.id.au/tag/lora.html
|
||||||
*/
|
*/
|
||||||
|
|
@ -80,7 +83,7 @@ struct rxdata {
|
||||||
uint8_t wtf; // possibly an extra byte in the received data here? what is it? padding?
|
uint8_t wtf; // possibly an extra byte in the received data here? what is it? padding?
|
||||||
int16_t rssi;
|
int16_t rssi;
|
||||||
uint16_t src;
|
uint16_t src;
|
||||||
uint16_t dst; // see LoRaEMB on page 42: https://www.embit.eu/wp-content/uploads/2020/10/ebi-LoRa_rev1.0.1.pdf
|
uint16_t dst;
|
||||||
|
|
||||||
// our data starts here
|
// our data starts here
|
||||||
uint8_t charge_state; // the charge status as supplied by Melopero library - actual struct +3 bytes padding/alignment
|
uint8_t charge_state; // the charge status as supplied by Melopero library - actual struct +3 bytes padding/alignment
|
||||||
|
|
@ -93,7 +96,7 @@ struct rxdata {
|
||||||
uint8_t checksum;
|
uint8_t checksum;
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: error detection - format, length, etc - this code is unsafe
|
// FIXME: error detection - format, length, etc - this code is **UNSAFE**
|
||||||
uint8_t * deserialise_i16(uint8_t * buf, int16_t * val) {
|
uint8_t * deserialise_i16(uint8_t * buf, int16_t * val) {
|
||||||
uint16_t uval = 0;
|
uint16_t uval = 0;
|
||||||
uval |= ((uint16_t)buf[0]) << 8;
|
uval |= ((uint16_t)buf[0]) << 8;
|
||||||
|
|
@ -197,27 +200,42 @@ int main() {
|
||||||
melopero.enablelWs2812(true);
|
melopero.enablelWs2812(true);
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
printf("\n=============================================\n");
|
// simple LED on
|
||||||
|
gpio_put(23, 1);
|
||||||
|
|
||||||
|
printf("\n============================================\n");
|
||||||
|
|
||||||
// print out the battery charging state, also set LED colour code
|
// print out the battery charging state, also set LED colour code
|
||||||
printf("Battery: %d (", melopero.getChargerStatus());
|
printf("Battery: %d (", melopero.getChargerStatus());
|
||||||
if (melopero.isCharging()) {
|
if (melopero.isCharging()) {
|
||||||
printf("charging)\n");
|
printf("charging)\n");
|
||||||
|
// yellow
|
||||||
melopero.setWs2812Color(255, 255, 0, 0.1);
|
melopero.setWs2812Color(255, 255, 0, 0.1);
|
||||||
}
|
}
|
||||||
else if (melopero.isFullyCharged()) {
|
else if (melopero.isFullyCharged()) {
|
||||||
printf("charged)\n");
|
printf("charged)\n");
|
||||||
|
// green
|
||||||
melopero.setWs2812Color(0, 255, 0, 0.05);
|
melopero.setWs2812Color(0, 255, 0, 0.05);
|
||||||
}
|
}
|
||||||
else if (melopero.hasRecoverableFault()) {
|
else if (melopero.hasRecoverableFault()) {
|
||||||
printf("fault: recoverable)\n");
|
printf("fault: recoverable)\n");
|
||||||
|
// blue
|
||||||
melopero.setWs2812Color(0, 0, 255, 0.05);
|
melopero.setWs2812Color(0, 0, 255, 0.05);
|
||||||
}
|
}
|
||||||
else if (melopero.hasNonRecoverableFault()) {
|
else if (melopero.hasNonRecoverableFault()) {
|
||||||
printf("fault: non-recoverable)\n");
|
printf("fault: non-recoverable)\n");
|
||||||
melopero.setWs2812Color(255, 255, 255, 0.25);
|
// red
|
||||||
|
melopero.setWs2812Color(255, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
sleep_ms(500);
|
// NOTE: there seems to be an error in the charging on these
|
||||||
|
// boards where it never reaches full charge and then hits a
|
||||||
|
// timeout and enters non-recoverable error, but then this is
|
||||||
|
// reset by external power loss (i.e. no light on solar
|
||||||
|
// overnight) - though this doesn't help if you're using
|
||||||
|
// solar+battery as the external power source.
|
||||||
|
//
|
||||||
|
// NOTE2: if there is no battery plugged in this just flips
|
||||||
|
// between charging and charged status.
|
||||||
|
|
||||||
// check the temperature of the RP2350
|
// check the temperature of the RP2350
|
||||||
float voltage = readADCVoltage( 4 );
|
float voltage = readADCVoltage( 4 );
|
||||||
|
|
@ -225,23 +243,28 @@ int main() {
|
||||||
printf( "RP2350 Temperature: %0.2f C\n", temp );
|
printf( "RP2350 Temperature: %0.2f C\n", temp );
|
||||||
|
|
||||||
// read received LoRa data, if available
|
// read received LoRa data, if available
|
||||||
uint8_t rxbuff[sizeof(struct rxdata)]; // at least enough for our expected data
|
uint8_t rxbuff[sizeof(struct rxdata)]; // at least big enough for our *expected* data
|
||||||
size_t rxbuff_ptr = 0;
|
size_t rxbuff_ptr = 0;
|
||||||
|
bool verbose = false;
|
||||||
if (melopero.checkRxFifo(500)) { // if there is data received...
|
if (melopero.checkRxFifo(500)) { // if there is data received...
|
||||||
// TODO: this really needs some sort of validation
|
// TODO: this really needs some sort of validation
|
||||||
do {
|
do {
|
||||||
printf("rx: ");
|
if (verbose) printf("rx: ");
|
||||||
for (size_t i = 0; i < melopero.responseLen; i++) {
|
for (size_t i = 0; i < melopero.responseLen; i++) {
|
||||||
if (rxbuff_ptr < sizeof(rxbuff)) {
|
if (rxbuff_ptr < sizeof(rxbuff)) {
|
||||||
rxbuff[rxbuff_ptr] = melopero.response[i];
|
rxbuff[rxbuff_ptr] = melopero.response[i];
|
||||||
printf("0x%02X ", rxbuff[rxbuff_ptr]);
|
if (verbose) printf("0x%02X ", rxbuff[rxbuff_ptr]);
|
||||||
} else {
|
} else {
|
||||||
// discarded excess data
|
// more data than buffer holds received, we just ignore it
|
||||||
printf("(0x%02X) ", melopero.response[i]);
|
if (verbose) {
|
||||||
|
printf("(0x%02X) ", melopero.response[i]);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rxbuff_ptr++;
|
rxbuff_ptr++;
|
||||||
}
|
}
|
||||||
printf("\n");
|
if (verbose) printf("\n");
|
||||||
} while (melopero.checkRxFifo(500)); // Keep checking the FIFO for new data
|
} while (melopero.checkRxFifo(500)); // Keep checking the FIFO for new data
|
||||||
|
|
||||||
// NOTE: the length could be < or > actual buffer length
|
// NOTE: the length could be < or > actual buffer length
|
||||||
|
|
@ -272,7 +295,10 @@ int main() {
|
||||||
printf("nothing in the rx fifo\n");
|
printf("nothing in the rx fifo\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// take a nap
|
// simple LED off
|
||||||
|
gpio_put(23, 0);
|
||||||
|
|
||||||
|
// check every second for recieved data
|
||||||
sleep_ms(1000);
|
sleep_ms(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,24 @@
|
||||||
|
/**
|
||||||
|
* Melopero Perpetuo LoRa - Allotment Telemetry Sender
|
||||||
|
*
|
||||||
|
* This code began life as the Melopero sample code the Perpetuo LoRa board.
|
||||||
|
* This can be found here: https://github.com/melopero/Melopero_Perpetuo_Lora
|
||||||
|
*
|
||||||
|
* As per their code I choose to continue the MIT licencing for this.
|
||||||
|
*
|
||||||
|
* This is the code for a LoRa reciever note that collects the data from
|
||||||
|
* one or many LoRa sender nodes which transmit sensor data from various
|
||||||
|
* points on an allotment or similar environment where you may want to
|
||||||
|
* record sensor data. The sensor data is output via the serial console
|
||||||
|
* so that a host computer can then do whatever is needed with it (i.e.
|
||||||
|
* send out to IP network via MQTT, or place into a database, etc.)
|
||||||
|
*
|
||||||
|
* DISCLAIMER: The code is in no way warranted to be fit for any purpose at
|
||||||
|
* all. In fact it is almost certainly "buggy as hell". You have been warned.
|
||||||
|
*
|
||||||
|
* Yvan Seth <allotment.sensors@seth.id.au>
|
||||||
|
* https://yvan.seth.id.au/tag/lora.html
|
||||||
|
*/
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
|
@ -9,13 +30,16 @@
|
||||||
#include "hardware/adc.h"
|
#include "hardware/adc.h"
|
||||||
#include "MeloperoPerpetuo.h"
|
#include "MeloperoPerpetuo.h"
|
||||||
|
|
||||||
|
// The number of times to take an ADC reading to get an average ADC reading
|
||||||
static const int ADC_SAMPLE_COUNT = 16;
|
static const int ADC_SAMPLE_COUNT = 16;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a given ADC value, returns a voltage value.
|
* Read a given ADC value, returns a voltage value.
|
||||||
*
|
*
|
||||||
* Actually reads ACD_SAMPLE_COUNT values and returns an average after an
|
* Actually reads ACD_SAMPLE_COUNT values and returns an average after an
|
||||||
* outlier elimination filter.
|
* outlier elimination filter. I don't know how necessary this is on the
|
||||||
|
* RP2350 platform, but also it probably doesn't hurt aside from a little
|
||||||
|
* more power usage I guess.
|
||||||
*/
|
*/
|
||||||
float readADCVoltage( int adc ) { std::vector<uint16_t> values;
|
float readADCVoltage( int adc ) { std::vector<uint16_t> values;
|
||||||
|
|
||||||
|
|
@ -56,7 +80,7 @@ float readADCVoltage( int adc ) { std::vector<uint16_t> values;
|
||||||
return adc_volts;
|
return adc_volts;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is our data transfer/packet struct - note: it isn't platform/endian portable
|
// This is our data transfer/packet struct
|
||||||
struct txdata {
|
struct txdata {
|
||||||
uint16_t options; // options as defined page 42: https://www.embit.eu/wp-content/uploads/2020/10/ebi-LoRa_rev1.0.1.pdf
|
uint16_t options; // options as defined page 42: https://www.embit.eu/wp-content/uploads/2020/10/ebi-LoRa_rev1.0.1.pdf
|
||||||
uint16_t dest; // destination id, 0xFFFF for broadcast
|
uint16_t dest; // destination id, 0xFFFF for broadcast
|
||||||
|
|
@ -66,6 +90,7 @@ struct txdata {
|
||||||
float vin; // supply voltage, i.e. USB, solar, or battery
|
float vin; // supply voltage, i.e. USB, solar, or battery
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Serialisation functions
|
||||||
uint8_t* serialise_u8(uint8_t* buf, uint8_t val) {
|
uint8_t* serialise_u8(uint8_t* buf, uint8_t val) {
|
||||||
buf[0] = val;
|
buf[0] = val;
|
||||||
return buf + 1;
|
return buf + 1;
|
||||||
|
|
@ -170,6 +195,7 @@ int main() {
|
||||||
adc_gpio_init(26);
|
adc_gpio_init(26);
|
||||||
adc_gpio_init(27);
|
adc_gpio_init(27);
|
||||||
adc_set_temp_sensor_enabled(true);
|
adc_set_temp_sensor_enabled(true);
|
||||||
|
melopero.enablelWs2812(true);
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
|
|
@ -178,53 +204,54 @@ int main() {
|
||||||
// simple LED on
|
// simple LED on
|
||||||
gpio_put(23, 1);
|
gpio_put(23, 1);
|
||||||
|
|
||||||
// cycle the RGB LEDS - just for fun
|
|
||||||
melopero.enablelWs2812(true);
|
|
||||||
melopero.setWs2812Color(255, 0, 0, 0.2);
|
|
||||||
sleep_ms(500);
|
|
||||||
melopero.setWs2812Color(0, 255, 0, 0.2);
|
|
||||||
sleep_ms(500);
|
|
||||||
melopero.setWs2812Color(0, 0, 255, 0.2);
|
|
||||||
sleep_ms(500);
|
|
||||||
melopero.setWs2812Color(0, 0, 0, 0);
|
|
||||||
melopero.enablelWs2812(false);
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
// read sensor values
|
// read sensor values
|
||||||
printf("\n============================================\n");
|
printf("\n============================================\n");
|
||||||
|
|
||||||
|
// the sensor data struct
|
||||||
struct txdata txd = {};
|
struct txdata txd = {};
|
||||||
|
// set header values
|
||||||
txd.options = 0;
|
txd.options = 0;
|
||||||
txd.dest = 0xFFFF;
|
txd.dest = 0xFFFF; // broadcast "address"
|
||||||
|
|
||||||
// print out the battery charging state
|
// print out the battery charging state
|
||||||
txd.charge_state = melopero.getChargerStatus();
|
txd.charge_state = melopero.getChargerStatus();
|
||||||
printf("Battery: %d (", txd.charge_state);
|
printf("Battery: %d (", txd.charge_state);
|
||||||
if (melopero.isCharging()) {
|
if (melopero.isCharging()) {
|
||||||
printf("charging)\n");
|
printf("charging)\n");
|
||||||
|
// yellow
|
||||||
melopero.setWs2812Color(255, 255, 0, 0.1);
|
melopero.setWs2812Color(255, 255, 0, 0.1);
|
||||||
}
|
}
|
||||||
else if (melopero.isFullyCharged()) {
|
else if (melopero.isFullyCharged()) {
|
||||||
printf("charged)\n");
|
printf("charged)\n");
|
||||||
|
// green
|
||||||
melopero.setWs2812Color(0, 255, 0, 0.05);
|
melopero.setWs2812Color(0, 255, 0, 0.05);
|
||||||
}
|
}
|
||||||
else if (melopero.hasRecoverableFault()) {
|
else if (melopero.hasRecoverableFault()) {
|
||||||
printf("fault: recoverable)\n");
|
printf("fault: recoverable)\n");
|
||||||
|
// blue
|
||||||
melopero.setWs2812Color(0, 0, 255, 0.05);
|
melopero.setWs2812Color(0, 0, 255, 0.05);
|
||||||
}
|
}
|
||||||
else if (melopero.hasNonRecoverableFault()) {
|
else if (melopero.hasNonRecoverableFault()) {
|
||||||
printf("fault: non-recoverable)\n");
|
printf("fault: non-recoverable)\n");
|
||||||
melopero.setWs2812Color(255, 255, 255, 0.25);
|
// red
|
||||||
|
melopero.setWs2812Color(255, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
sleep_ms(500);
|
// NOTE: there seems to be an error in the charging on these
|
||||||
melopero.setWs2812Color(0, 0, 0, 0);
|
// boards where it never reaches full charge and then hits a
|
||||||
|
// timeout and enters non-recoverable error, but then this is
|
||||||
|
// reset by external power loss (i.e. no light on solar
|
||||||
|
// overnight) - though this doesn't help if you're using
|
||||||
|
// solar+battery as the external power source.
|
||||||
|
//
|
||||||
|
// NOTE2: if there is no battery plugged in this just flips
|
||||||
|
// between charging and charged status.
|
||||||
|
|
||||||
// flip the enable on the VSEN on/off each iteration, this is just
|
// flip the enable on the VSEN on/off each iteration, this is just
|
||||||
// testing it can turn an LED on/off if you like, or enable/disable
|
// testing it can turn an LED on/off if you like, or enable/disable
|
||||||
// other external hardware (thus saving power, only power on sensors
|
// other external hardware (thus saving power, only power on sensors
|
||||||
// to read data every 5 minutes, say...)
|
// to read data every 5 minutes, say...)
|
||||||
int vsen = gpio_get( 0 );
|
int vsen = gpio_get( 0 );
|
||||||
printf( "vsen: %d\n", vsen );
|
|
||||||
if ( vsen ) {
|
if ( vsen ) {
|
||||||
printf("vsen off\n");
|
printf("vsen off\n");
|
||||||
gpio_put( 0, 0 );
|
gpio_put( 0, 0 );
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue