support indicator sensors through Rp2040 serial (#5696)

* support indicator sensors through Rp2040 serial

* disable excessive debug printing
pull/5691/head
Thomas Göttgens 2024-12-30 21:28:31 +01:00 zatwierdzone przez GitHub
rodzic 3c7053c66a
commit a2a6b236b7
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
6 zmienionych plików z 409 dodań i 1 usunięć

Wyświetl plik

@ -64,6 +64,10 @@ CGRadSensSensor cgRadSens;
#include "Sensor/T1000xSensor.h"
T1000xSensor t1000xSensor;
#endif
#ifdef SENSECAP_INDICATOR
#include "Sensor/IndicatorSensor.h"
IndicatorSensor indicatorSensor;
#endif
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
@ -103,6 +107,9 @@ int32_t EnvironmentTelemetryModule::runOnce()
LOG_INFO("Environment Telemetry: init");
// it's possible to have this module enabled, only for displaying values on the screen.
// therefore, we should only enable the sensor loop if measurement is also enabled
#ifdef SENSECAP_INDICATOR
result = indicatorSensor.runOnce();
#endif
#ifdef T1000X_SENSOR_EN
result = t1000xSensor.runOnce();
#elif !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR_EXTERNAL
@ -298,6 +305,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
m->which_variant = meshtastic_Telemetry_environment_metrics_tag;
m->variant.environment_metrics = meshtastic_EnvironmentMetrics_init_zero;
#ifdef SENSECAP_INDICATOR
valid = valid && indicatorSensor.getMetrics(m);
hasSensor = true;
#endif
#ifdef T1000X_SENSOR_EN // add by WayenWeng
valid = valid && t1000xSensor.getMetrics(m);
hasSensor = true;
@ -410,7 +421,6 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m
valid = valid && cgRadSens.getMetrics(m);
hasSensor = true;
}
#endif
return valid && hasSensor;
}

Wyświetl plik

@ -0,0 +1,167 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(SENSECAP_INDICATOR)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "IndicatorSensor.h"
#include "TelemetrySensor.h"
#include "serialization/cobs.h"
#include <Adafruit_Sensor.h>
#include <driver/uart.h>
IndicatorSensor::IndicatorSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SENSOR_UNSET, "Indicator") {}
#define SENSOR_BUF_SIZE (512)
uint8_t buf[SENSOR_BUF_SIZE]; // recv
uint8_t data[SENSOR_BUF_SIZE]; // decode
#define ACK_PKT_PARA "ACK"
enum sensor_pkt_type {
PKT_TYPE_ACK = 0x00, // uin32_t
PKT_TYPE_CMD_COLLECT_INTERVAL = 0xA0, // uin32_t
PKT_TYPE_CMD_BEEP_ON = 0xA1, // uin32_t ms: on time
PKT_TYPE_CMD_BEEP_OFF = 0xA2,
PKT_TYPE_CMD_SHUTDOWN = 0xA3, // uin32_t
PKT_TYPE_CMD_POWER_ON = 0xA4,
PKT_TYPE_SENSOR_SCD41_TEMP = 0xB0, // float
PKT_TYPE_SENSOR_SCD41_HUMIDITY = 0xB1, // float
PKT_TYPE_SENSOR_SCD41_CO2 = 0xB2, // float
PKT_TYPE_SENSOR_AHT20_TEMP = 0xB3, // float
PKT_TYPE_SENSOR_AHT20_HUMIDITY = 0xB4, // float
PKT_TYPE_SENSOR_TVOC_INDEX = 0xB5, // float
};
static int cmd_send(uint8_t cmd, const char *p_data, uint8_t len)
{
uint8_t buf[32] = {0};
uint8_t data[32] = {0};
if (len > 31) {
return -1;
}
uint8_t index = 1;
data[0] = cmd;
if (len > 0 && p_data != NULL) {
memcpy(&data[1], p_data, len);
index += len;
}
cobs_encode_result ret = cobs_encode(buf, sizeof(buf), data, index);
// LOG_DEBUG("cobs TX status:%d, len:%d, type 0x%x", ret.status, ret.out_len, cmd);
if (ret.status == COBS_ENCODE_OK) {
return uart_write_bytes(SENSOR_PORT_NUM, buf, ret.out_len + 1);
}
return -1;
}
int32_t IndicatorSensor::runOnce()
{
LOG_INFO("%s: init", sensorName);
setup();
return 2 * DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; // give it some time to start up
}
void IndicatorSensor::setup()
{
uart_config_t uart_config = {
.baud_rate = SENSOR_BAUD_RATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
int intr_alloc_flags = 0;
char buffer[11];
uart_driver_install(SENSOR_PORT_NUM, SENSOR_BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags);
uart_param_config(SENSOR_PORT_NUM, &uart_config);
uart_set_pin(SENSOR_PORT_NUM, SENSOR_RP2040_TXD, SENSOR_RP2040_RXD, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
cmd_send(PKT_TYPE_CMD_POWER_ON, NULL, 0);
// measure and send only once every minute, for the phone API
const char *interval = ultoa(60000, buffer, 10);
cmd_send(PKT_TYPE_CMD_COLLECT_INTERVAL, interval, strlen(interval) + 1);
}
bool IndicatorSensor::getMetrics(meshtastic_Telemetry *measurement)
{
cobs_decode_result ret;
int len = uart_read_bytes(SENSOR_PORT_NUM, buf, (SENSOR_BUF_SIZE - 1), 100 / portTICK_PERIOD_MS);
float value = 0.0;
uint8_t pkt_type = 0;
uint8_t *p_buf_start = buf;
uint8_t *p_buf_end = buf;
if (len > 0) {
while (p_buf_start < (buf + len)) {
p_buf_end = p_buf_start;
while (p_buf_end < (buf + len)) {
if (*p_buf_end == 0x00) {
break;
}
p_buf_end++;
}
// decode buf
memset(data, 0, sizeof(data));
ret = cobs_decode(data, sizeof(data), p_buf_start, p_buf_end - p_buf_start);
// LOG_DEBUG("cobs RX status:%d, len:%d, type:0x%x ", ret.status, ret.out_len, data[0]);
if (ret.out_len > 1 && ret.status == COBS_DECODE_OK) {
value = 0.0;
pkt_type = data[0];
switch (pkt_type) {
case PKT_TYPE_SENSOR_SCD41_CO2: {
memcpy(&value, &data[1], sizeof(value));
// LOG_DEBUG("CO2: %.1f", value);
cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4);
break;
}
case PKT_TYPE_SENSOR_AHT20_TEMP: {
memcpy(&value, &data[1], sizeof(value));
// LOG_DEBUG("Temp: %.1f", value);
cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4);
measurement->variant.environment_metrics.has_temperature = true;
measurement->variant.environment_metrics.temperature = value;
break;
}
case PKT_TYPE_SENSOR_AHT20_HUMIDITY: {
memcpy(&value, &data[1], sizeof(value));
// LOG_DEBUG("Humidity: %.1f", value);
cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4);
measurement->variant.environment_metrics.has_relative_humidity = true;
measurement->variant.environment_metrics.relative_humidity = value;
break;
}
case PKT_TYPE_SENSOR_TVOC_INDEX: {
memcpy(&value, &data[1], sizeof(value));
// LOG_DEBUG("Tvoc: %.1f", value);
cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4);
measurement->variant.environment_metrics.has_iaq = true;
measurement->variant.environment_metrics.iaq = value;
break;
}
default:
break;
}
}
p_buf_start = p_buf_end + 1; // next message
}
return true;
}
return false;
}
#endif

Wyświetl plik

@ -0,0 +1,19 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h"
class IndicatorSensor : public TelemetrySensor
{
protected:
virtual void setup() override;
public:
IndicatorSensor();
virtual int32_t runOnce() override;
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
};
#endif

Wyświetl plik

@ -0,0 +1,131 @@
#include "cobs.h"
#include <stdlib.h>
#ifdef SENSECAP_INDICATOR
cobs_encode_result cobs_encode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len)
{
cobs_encode_result result = {0, COBS_ENCODE_OK};
const uint8_t *src_read_ptr = src_ptr;
const uint8_t *src_end_ptr = src_read_ptr + src_len;
uint8_t *dst_buf_start_ptr = dst_buf_ptr;
uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len;
uint8_t *dst_code_write_ptr = dst_buf_ptr;
uint8_t *dst_write_ptr = dst_code_write_ptr + 1;
uint8_t src_byte = 0;
uint8_t search_len = 1;
if ((dst_buf_ptr == NULL) || (src_ptr == NULL)) {
result.status = COBS_ENCODE_NULL_POINTER;
return result;
}
if (src_len != 0) {
for (;;) {
if (dst_write_ptr >= dst_buf_end_ptr) {
result.status = (cobs_encode_status)(result.status | (cobs_encode_status)COBS_ENCODE_OUT_BUFFER_OVERFLOW);
break;
}
src_byte = *src_read_ptr++;
if (src_byte == 0) {
*dst_code_write_ptr = search_len;
dst_code_write_ptr = dst_write_ptr++;
search_len = 1;
if (src_read_ptr >= src_end_ptr) {
break;
}
} else {
*dst_write_ptr++ = src_byte;
search_len++;
if (src_read_ptr >= src_end_ptr) {
break;
}
if (search_len == 0xFF) {
*dst_code_write_ptr = search_len;
dst_code_write_ptr = dst_write_ptr++;
search_len = 1;
}
}
}
}
if (dst_code_write_ptr >= dst_buf_end_ptr) {
result.status = (cobs_encode_status)(result.status | (cobs_encode_status)COBS_ENCODE_OUT_BUFFER_OVERFLOW);
dst_write_ptr = dst_buf_end_ptr;
} else {
*dst_code_write_ptr = search_len;
}
result.out_len = dst_write_ptr - dst_buf_start_ptr;
return result;
}
cobs_decode_result cobs_decode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len)
{
cobs_decode_result result = {0, COBS_DECODE_OK};
const uint8_t *src_read_ptr = src_ptr;
const uint8_t *src_end_ptr = src_read_ptr + src_len;
uint8_t *dst_buf_start_ptr = dst_buf_ptr;
uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len;
uint8_t *dst_write_ptr = dst_buf_ptr;
size_t remaining_bytes;
uint8_t src_byte;
uint8_t i;
uint8_t len_code;
if ((dst_buf_ptr == NULL) || (src_ptr == NULL)) {
result.status = COBS_DECODE_NULL_POINTER;
return result;
}
if (src_len != 0) {
for (;;) {
len_code = *src_read_ptr++;
if (len_code == 0) {
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_ZERO_BYTE_IN_INPUT);
break;
}
len_code--;
remaining_bytes = src_end_ptr - src_read_ptr;
if (len_code > remaining_bytes) {
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_INPUT_TOO_SHORT);
len_code = remaining_bytes;
}
remaining_bytes = dst_buf_end_ptr - dst_write_ptr;
if (len_code > remaining_bytes) {
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_OUT_BUFFER_OVERFLOW);
len_code = remaining_bytes;
}
for (i = len_code; i != 0; i--) {
src_byte = *src_read_ptr++;
if (src_byte == 0) {
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_ZERO_BYTE_IN_INPUT);
}
*dst_write_ptr++ = src_byte;
}
if (src_read_ptr >= src_end_ptr) {
break;
}
if (len_code != 0xFE) {
if (dst_write_ptr >= dst_buf_end_ptr) {
result.status = (cobs_decode_status)(result.status | (cobs_decode_status)COBS_DECODE_OUT_BUFFER_OVERFLOW);
break;
}
*dst_write_ptr++ = 0;
}
}
}
result.out_len = dst_write_ptr - dst_buf_start_ptr;
return result;
}
#endif

Wyświetl plik

@ -0,0 +1,75 @@
#ifndef COBS_H_
#define COBS_H_
#include "configuration.h"
#ifdef SENSECAP_INDICATOR
#include <stdint.h>
#include <stdlib.h>
#define COBS_ENCODE_DST_BUF_LEN_MAX(SRC_LEN) ((SRC_LEN) + (((SRC_LEN) + 253u) / 254u))
#define COBS_DECODE_DST_BUF_LEN_MAX(SRC_LEN) (((SRC_LEN) == 0) ? 0u : ((SRC_LEN)-1u))
#define COBS_ENCODE_SRC_OFFSET(SRC_LEN) (((SRC_LEN) + 253u) / 254u)
typedef enum {
COBS_ENCODE_OK = 0x00,
COBS_ENCODE_NULL_POINTER = 0x01,
COBS_ENCODE_OUT_BUFFER_OVERFLOW = 0x02
} cobs_encode_status;
typedef struct {
size_t out_len;
cobs_encode_status status;
} cobs_encode_result;
typedef enum {
COBS_DECODE_OK = 0x00,
COBS_DECODE_NULL_POINTER = 0x01,
COBS_DECODE_OUT_BUFFER_OVERFLOW = 0x02,
COBS_DECODE_ZERO_BYTE_IN_INPUT = 0x04,
COBS_DECODE_INPUT_TOO_SHORT = 0x08
} cobs_decode_status;
typedef struct {
size_t out_len;
cobs_decode_status status;
} cobs_decode_result;
#ifdef __cplusplus
extern "C" {
#endif
/* COBS-encode a string of input bytes.
*
* dst_buf_ptr: The buffer into which the result will be written
* dst_buf_len: Length of the buffer into which the result will be written
* src_ptr: The byte string to be encoded
* src_len Length of the byte string to be encoded
*
* returns: A struct containing the success status of the encoding
* operation and the length of the result (that was written to
* dst_buf_ptr)
*/
cobs_encode_result cobs_encode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len);
/* Decode a COBS byte string.
*
* dst_buf_ptr: The buffer into which the result will be written
* dst_buf_len: Length of the buffer into which the result will be written
* src_ptr: The byte string to be decoded
* src_len Length of the byte string to be decoded
*
* returns: A struct containing the success status of the decoding
* operation and the length of the result (that was written to
* dst_buf_ptr)
*/
cobs_decode_result cobs_decode(uint8_t *dst_buf_ptr, size_t dst_buf_len, const uint8_t *src_ptr, size_t src_len);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SENSECAP_INDICATOR */
#endif /* COBS_H_ */

Wyświetl plik

@ -1,6 +1,12 @@
#define I2C_SDA 39
#define I2C_SCL 40
// This board has a serial coprocessor for sensor readings
#define SENSOR_RP2040_TXD 19
#define SENSOR_RP2040_RXD 20
#define SENSOR_PORT_NUM 2
#define SENSOR_BAUD_RATE 115200
#define BUTTON_PIN 38
// #define BUTTON_NEED_PULLUP