Compare commits

...

13 Commits

Author SHA1 Message Date
Thomas Göttgens
01b3c7017e
Merge f084a8a11d into 46c7d74760 2025-06-07 23:09:14 +02:00
github-actions[bot]
46c7d74760
Upgrade trunk (#6968)
Some checks are pending
CI / build-esp32-c3 (push) Blocked by required conditions
CI / build-esp32-c6 (push) Blocked by required conditions
CI / build-nrf52 (push) Blocked by required conditions
CI / build-rpi2040 (push) Blocked by required conditions
CI / build-stm32 (push) Blocked by required conditions
CI / build-debian-src (push) Waiting to run
CI / package-pio-deps-native-tft (push) Waiting to run
CI / test-native (push) Waiting to run
CI / docker-deb-amd64 (push) Waiting to run
CI / docker-deb-amd64-tft (push) Waiting to run
CI / docker-alp-amd64 (push) Waiting to run
CI / docker-alp-amd64-tft (push) Waiting to run
CI / docker-deb-arm64 (push) Waiting to run
CI / docker-deb-armv7 (push) Waiting to run
CI / gather-artifacts (esp32) (push) Blocked by required conditions
CI / gather-artifacts (esp32c3) (push) Blocked by required conditions
CI / gather-artifacts (esp32c6) (push) Blocked by required conditions
CI / gather-artifacts (esp32s3) (push) Blocked by required conditions
CI / gather-artifacts (nrf52840) (push) Blocked by required conditions
CI / gather-artifacts (rp2040) (push) Blocked by required conditions
CI / gather-artifacts (stm32) (push) Blocked by required conditions
CI / release-artifacts (push) Blocked by required conditions
CI / release-firmware (esp32) (push) Blocked by required conditions
CI / release-firmware (esp32c3) (push) Blocked by required conditions
CI / release-firmware (esp32c6) (push) Blocked by required conditions
CI / release-firmware (esp32s3) (push) Blocked by required conditions
CI / release-firmware (nrf52840) (push) Blocked by required conditions
CI / release-firmware (rp2040) (push) Blocked by required conditions
CI / release-firmware (stm32) (push) Blocked by required conditions
CI / publish-firmware (push) Blocked by required conditions
Co-authored-by: sachaw <11172820+sachaw@users.noreply.github.com>
2025-06-07 07:58:01 -05:00
Tom
15d2ae17f8
Add note to hydra to note that the button pin has no pull-up (#6979)
Add note to hydra to note that the button pin has no pull-up. Use an external resistor or remove the `#define`.
2025-06-07 06:55:58 -05:00
github-actions[bot]
91579c4650
[create-pull-request] automated change (#6980)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2025-06-07 06:55:25 -05:00
Andrew Yong
79b710a108
fix: Respect LED_STATE_ON for power and user LED (#6976)
Signed-off-by: Andrew Yong <me@ndoo.sg>
2025-06-07 06:44:54 -05:00
todd-herbert
ba296db701
Add InkHUD driver for WeAct Studio 2.9" display module (#6963)
Some checks failed
CI / build-esp32-c6 (push) Blocked by required conditions
CI / build-nrf52 (push) Blocked by required conditions
CI / build-rpi2040 (push) Blocked by required conditions
CI / build-stm32 (push) Blocked by required conditions
CI / build-debian-src (push) Waiting to run
CI / package-pio-deps-native-tft (push) Waiting to run
CI / test-native (push) Waiting to run
CI / docker-deb-amd64 (push) Waiting to run
CI / docker-deb-amd64-tft (push) Waiting to run
CI / docker-alp-amd64 (push) Waiting to run
CI / docker-alp-amd64-tft (push) Waiting to run
CI / docker-deb-arm64 (push) Waiting to run
CI / docker-deb-armv7 (push) Waiting to run
CI / gather-artifacts (esp32) (push) Blocked by required conditions
CI / gather-artifacts (esp32c3) (push) Blocked by required conditions
CI / gather-artifacts (esp32c6) (push) Blocked by required conditions
CI / gather-artifacts (esp32s3) (push) Blocked by required conditions
CI / gather-artifacts (nrf52840) (push) Blocked by required conditions
CI / gather-artifacts (rp2040) (push) Blocked by required conditions
CI / gather-artifacts (stm32) (push) Blocked by required conditions
CI / release-artifacts (push) Blocked by required conditions
CI / release-firmware (esp32) (push) Blocked by required conditions
CI / release-firmware (esp32c3) (push) Blocked by required conditions
CI / release-firmware (esp32c6) (push) Blocked by required conditions
CI / release-firmware (esp32s3) (push) Blocked by required conditions
CI / release-firmware (nrf52840) (push) Blocked by required conditions
CI / release-firmware (rp2040) (push) Blocked by required conditions
CI / release-firmware (stm32) (push) Blocked by required conditions
CI / publish-firmware (push) Blocked by required conditions
Semgrep Full Scan / semgrep-full (push) Has been cancelled
* Driver for WeAct Studio 2.9" ePaper module

* Clarify that flex connector marking is not a unique id

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2025-06-06 17:35:47 +12:00
Thomas Göttgens
f084a8a11d
Merge branch 'master' into indicator-comms 2025-06-05 14:35:04 +02:00
Thomas Göttgens
37857941bf
Merge branch 'master' into indicator-comms 2025-05-23 15:53:16 +02:00
Thomas Göttgens
d544b41ab7
Merge branch 'master' into indicator-comms 2025-03-31 11:09:44 +02:00
Thomas Göttgens
8c53ce82f2 don't build FakeUART on other platforms 2025-03-04 11:11:25 +01:00
Thomas Göttgens
7ee95f2a0c Merge branch 'indicator-comms' of github.com:meshtastic/firmware into indicator-comms 2025-03-04 10:39:35 +01:00
Thomas Göttgens
65b50babee get sensor and NMEA data from indicator. Will test tomorrow, don't merge yet. 2025-03-04 01:56:56 +01:00
Thomas Göttgens
3c30821337 get sensor and NMEA data from indicator. Will test tomorrow, don't merge yet. 2025-03-04 01:53:18 +01:00
30 changed files with 575 additions and 351 deletions

View File

@ -9,7 +9,7 @@ plugins:
lint: lint:
enabled: enabled:
- checkov@3.2.436 - checkov@3.2.436
- renovate@40.41.0 - renovate@40.42.2
- prettier@3.5.3 - prettier@3.5.3
- trufflehog@3.88.35 - trufflehog@3.88.35
- yamllint@1.37.1 - yamllint@1.37.1

@ -1 +1 @@
Subproject commit 24c7a3d287a4bd269ce191827e5dabd8ce8f57a7 Subproject commit db60f07ac298b6161ca553b3868b542cceadcac4

94
src/gps/FakeUART.cpp Normal file
View File

@ -0,0 +1,94 @@
#include "FakeUART.h"
#ifdef SENSECAP_INDICATOR
FakeUART::FakeUART() {}
void FakeUART::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms,
uint8_t rxfifo_full_thrhd)
{
baudrate = baud;
FakeBuf.clear();
}
void FakeUART::end()
{
FakeBuf.clear();
}
int FakeUART::available()
{
return FakeBuf.size();
}
int FakeUART::peek()
{
unsigned char ret;
if (FakeBuf.peek(ret))
return ret;
return -1;
}
int FakeUART::read()
{
unsigned char ret;
if (FakeBuf.pop(ret))
return ret;
return -1;
}
void FakeUART::flush()
{
FakeBuf.clear();
}
uint32_t FakeUART::baudRate()
{
return baudrate;
}
void FakeUART::updateBaudRate(unsigned long speed)
{
baudrate = speed;
}
size_t FakeUART::setRxBufferSize(size_t size)
{
return size;
}
size_t FakeUART::write(const char *buffer)
{
return write((char *)buffer, strlen(buffer));
}
size_t FakeUART::write(uint8_t *buffer, size_t size)
{
return write((char *)buffer, size);
}
size_t FakeUART::write(char *buffer, size_t size)
{
meshtastic_InterdeviceMessage message = meshtastic_InterdeviceMessage_init_zero;
if (size > sizeof(message.data.nmea)) {
size = sizeof(message.data.nmea); // Truncate if buffer is too large
}
memcpy(message.data.nmea, buffer, size);
sensecapIndicator.send_uplink(message);
return size;
}
size_t FakeUART::stuff_buffer(const char *buffer, size_t size)
{
// push buffer in a loop to FakeBuf
for (size_t i = 0; i < size; i++) {
if (!FakeBuf.push(buffer[i])) {
return i;
}
}
return size;
}
FakeUART *FakeSerial;
#endif

44
src/gps/FakeUART.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#ifndef FAKEUART_H
#define FAKEUART_H
#ifdef SENSECAP_INDICATOR
#include "../IndicatorSerial.h"
#include <RingBuf.h>
#include <Stream.h>
#include <inttypes.h>
class FakeUART : public Stream
{
public:
FakeUART();
void begin(unsigned long baud, uint32_t config = 0x800001c, int8_t rxPin = -1, int8_t txPin = -1, bool invert = false,
unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 112);
void end();
int available();
int peek();
int read();
void flush();
uint32_t baudRate();
void updateBaudRate(unsigned long speed);
size_t setRxBufferSize(size_t size);
size_t write(const char *buffer);
size_t write(char *buffer, size_t size);
size_t write(uint8_t *buffer, size_t size);
size_t stuff_buffer(const char *buffer, size_t size);
virtual size_t write(uint8_t c) { return write(&c, 1); }
private:
unsigned long baudrate = 115200;
RingBuf<unsigned char, 2048> FakeBuf;
};
extern FakeUART *FakeSerial;
#endif // SENSECAP_INDICATOR
#endif // FAKEUART_H

View File

@ -40,7 +40,9 @@ template <typename T, std::size_t N> std::size_t array_count(const T (&)[N])
} }
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) #if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
#if defined(RAK2560) #if defined(SENSECAP_INDICATOR)
FakeUART *GPS::_serial_gps = nullptr;
#elif defined(RAK2560)
HardwareSerial *GPS::_serial_gps = &Serial2; HardwareSerial *GPS::_serial_gps = &Serial2;
#else #else
HardwareSerial *GPS::_serial_gps = &Serial1; HardwareSerial *GPS::_serial_gps = &Serial1;

View File

@ -11,6 +11,10 @@
#include "input/UpDownInterruptImpl1.h" #include "input/UpDownInterruptImpl1.h"
#include "modules/PositionModule.h" #include "modules/PositionModule.h"
#ifdef SENSECAP_INDICATOR
#include "FakeUART.h"
#endif
// Allow defining the polarity of the ENABLE output. default is active high // Allow defining the polarity of the ENABLE output. default is active high
#ifndef GPS_EN_ACTIVE #ifndef GPS_EN_ACTIVE
#define GPS_EN_ACTIVE 1 #define GPS_EN_ACTIVE 1
@ -188,7 +192,9 @@ class GPS : private concurrency::OSThread
CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep); CallbackObserver<GPS, void *> notifyDeepSleepObserver = CallbackObserver<GPS, void *>(this, &GPS::prepareDeepSleep);
/** If !NULL we will use this serial port to construct our GPS */ /** If !NULL we will use this serial port to construct our GPS */
#if defined(ARCH_RP2040) #if defined(SENSECAP_INDICATOR)
static FakeUART *_serial_gps;
#elif defined(ARCH_RP2040)
static SerialUART *_serial_gps; static SerialUART *_serial_gps;
#else #else
static HardwareSerial *_serial_gps; static HardwareSerial *_serial_gps;

View File

@ -5,7 +5,7 @@ E-Ink display driver
- Manufacturer: DKE - Manufacturer: DKE
- Size: 2.13 inch - Size: 2.13 inch
- Resolution: 122px x 250px - Resolution: 122px x 250px
- Flex connector marking: FPC-7528B - Flex connector marking (not a unique identifier): FPC-7528B
Note: this is from an older generation of DKE panels, which still used Solomon Systech controller ICs. Note: this is from an older generation of DKE panels, which still used Solomon Systech controller ICs.
DKE's website suggests that the latest DEPG0213BN displays may use Fitipower controllers instead. DKE's website suggests that the latest DEPG0213BN displays may use Fitipower controllers instead.

View File

@ -5,7 +5,7 @@ E-Ink display driver
- Manufacturer: DKE - Manufacturer: DKE
- Size: 2.9 inch - Size: 2.9 inch
- Resolution: 128px x 296px - Resolution: 128px x 296px
- Flex connector marking: FPC-7519 rev.b - Flex connector marking (not a unique identifier): FPC-7519 rev.b
*/ */

View File

@ -5,7 +5,7 @@ E-Ink display driver
- Manufacturer: Goodisplay - Manufacturer: Goodisplay
- Size: 1.54 inch - Size: 1.54 inch
- Resolution: 200px x 200px - Resolution: 200px x 200px
- Flex connector marking: FPC-B001 - Flex connector marking (not a unique identifier): FPC-B001
*/ */

View File

@ -5,7 +5,9 @@ E-Ink display driver
- Manufacturer: Goodisplay - Manufacturer: Goodisplay
- Size: 2.13 inch - Size: 2.13 inch
- Resolution: 250px x 122px - Resolution: 250px x 122px
- Flex connector marking: FPC-A002 - Flex connector marking (not a unique identifier):
- FPC-A002
- FPC-A005 20.06.15 TRX
*/ */

View File

@ -5,7 +5,7 @@ E-Ink display driver
- Manufacturer: Holitech - Manufacturer: Holitech
- Size: 4.2 inch - Size: 4.2 inch
- Resolution: 400px x 300px - Resolution: 400px x 300px
- Flex connector marking: HINK-E042A07-FPC-A1 - Flex connector marking (not a unique identifier): HINK-E042A07-FPC-A1
- Silver sticker with QR code, marked: HE042A87 - Silver sticker with QR code, marked: HE042A87
Note: as of Feb. 2025, these panels are used for "WeActStudio 4.2in B&W" display modules Note: as of Feb. 2025, these panels are used for "WeActStudio 4.2in B&W" display modules

View File

@ -5,7 +5,6 @@ E-Ink display driver
- Manufacturer: WISEVAST - Manufacturer: WISEVAST
- Size: 2.13 inch - Size: 2.13 inch
- Resolution: 122px x 255px - Resolution: 122px x 255px
- Flex connector marking: Soldering connector, no connector is needed
*/ */

View File

@ -5,7 +5,7 @@ E-Ink display driver
- Manufacturer: Wisevast - Manufacturer: Wisevast
- Size: 2.13 inch - Size: 2.13 inch
- Resolution: 122px x 250px - Resolution: 122px x 250px
- Flex connector marking: HINK-E0213A162-FPC-A0 (Hidden, printed on back-side) - Flex connector marking (not a unique identifier): HINK-E0213A162-FPC-A0 (Hidden, printed on back-side)
Note: this display uses an uncommon controller IC, Fitipower JD79656. Note: this display uses an uncommon controller IC, Fitipower JD79656.
It is implemented as a "one-off", directly inheriting the EInk base class, unlike SSD16XX displays. It is implemented as a "one-off", directly inheriting the EInk base class, unlike SSD16XX displays.

View File

@ -0,0 +1,59 @@
#include "./ZJY128296_029EAAMFGN.h"
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
using namespace NicheGraphics::Drivers;
// Map the display controller IC's output to the connected panel
void ZJY128296_029EAAMFGN::configScanning()
{
// "Driver output control"
// Scan gates from 0 to 295 (vertical resolution 296px)
sendCommand(0x01);
sendData(0x27); // Number of gates (295, bits 0-7)
sendData(0x01); // Number of gates (295, bit 8)
sendData(0x00); // (Do not invert scanning order)
}
// Specify which information is used to control the sequence of voltages applied to move the pixels
// - For this display, configUpdateSequence() specifies that a suitable LUT will be loaded from
// the controller IC's OTP memory, when the update procedure begins.
void ZJY128296_029EAAMFGN::configWaveform()
{
sendCommand(0x3C); // Border waveform:
sendData(0x05); // Screen border should follow LUT1 waveform (actively drive pixels white)
sendCommand(0x18); // Temperature sensor:
sendData(0x80); // Use internal temperature sensor to select an appropriate refresh waveform
}
void ZJY128296_029EAAMFGN::configUpdateSequence()
{
switch (updateType) {
case FAST:
sendCommand(0x22); // Set "update sequence"
sendData(0xFF); // Will load LUT from OTP memory, Display mode 2 "differential refresh"
break;
case FULL:
default:
sendCommand(0x22); // Set "update sequence"
sendData(0xF7); // Will load LUT from OTP memory
break;
}
}
// Once the refresh operation has been started,
// begin periodically polling the display to check for completion, using the normal Meshtastic threading code
// Only used when refresh is "async"
void ZJY128296_029EAAMFGN::detachFromUpdate()
{
switch (updateType) {
case FAST:
return beginPolling(50, 300); // At least 300ms for fast refresh
case FULL:
default:
return beginPolling(100, 2000); // At least 2 seconds for full refresh
}
}
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS

View File

@ -0,0 +1,44 @@
/*
E-Ink display driver
- ZJY128296-029EAAMFGN
- Manufacturer: Zhongjingyuan
- Size: 2.9 inch
- Resolution: 128px x 296px
- Flex connector label (not a unique identifier): FPC-A005 20.06.15 TRX
Note: as of Feb. 2025, these panels are used for "WeActStudio 2.9in B&W" display modules
*/
#pragma once
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
#include "configuration.h"
#include "./SSD16XX.h"
namespace NicheGraphics::Drivers
{
class ZJY128296_029EAAMFGN : public SSD16XX
{
// Display properties
private:
static constexpr uint32_t width = 128;
static constexpr uint32_t height = 296;
static constexpr UpdateTypes supported = (UpdateTypes)(FULL | FAST);
public:
ZJY128296_029EAAMFGN() : SSD16XX(width, height, supported) {}
protected:
void configScanning() override;
void configWaveform() override;
void configUpdateSequence() override;
void detachFromUpdate() override;
};
} // namespace NicheGraphics::Drivers
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS

View File

@ -22,6 +22,10 @@
#include "error.h" #include "error.h"
#include "power.h" #include "power.h"
#ifdef SENSECAP_INDICATOR // on the indicator run the additional serial port for the RP2040
#include "IndicatorSerial.h"
#endif
#if !MESHTASTIC_EXCLUDE_I2C #if !MESHTASTIC_EXCLUDE_I2C
#include "detect/ScanI2CTwoWire.h" #include "detect/ScanI2CTwoWire.h"
#include <Wire.h> #include <Wire.h>
@ -337,12 +341,12 @@ void setup()
#ifdef LED_POWER #ifdef LED_POWER
pinMode(LED_POWER, OUTPUT); pinMode(LED_POWER, OUTPUT);
digitalWrite(LED_POWER, HIGH); digitalWrite(LED_POWER, LED_STATE_ON);
#endif #endif
#ifdef USER_LED #ifdef USER_LED
pinMode(USER_LED, OUTPUT); pinMode(USER_LED, OUTPUT);
digitalWrite(USER_LED, LOW); digitalWrite(USER_LED, HIGH ^ LED_STATE_ON);
#endif #endif
#if defined(T_DECK) #if defined(T_DECK)
@ -771,6 +775,11 @@ void setup()
buttonThread = new ButtonThread(); buttonThread = new ButtonThread();
#endif #endif
// If we have an indicator, start process to service secondary port
#ifdef SENSECAP_INDICATOR
sensecapIndicator.begin(Serial2);
#endif
// only play start melody when role is not tracker or sensor // only play start melody when role is not tracker or sensor
if (config.power.is_power_saving == true && if (config.power.is_power_saving == true &&
IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TRACKER, IS_ONE_OF(config.device.role, meshtastic_Config_DeviceConfig_Role_TRACKER,

View File

@ -0,0 +1,151 @@
#ifdef SENSECAP_INDICATOR
#include "IndicatorSerial.h"
#include "../modules/Telemetry/Sensor/IndicatorSensor.h"
#include "FakeUART.h"
#include <HardwareSerial.h>
#include <pb_decode.h>
#include <pb_encode.h>
extern IndicatorSensor indicatorSensor;
SensecapIndicator sensecapIndicator;
SensecapIndicator::SensecapIndicator() : OSThread("SensecapIndicator") {}
void SensecapIndicator::begin(HardwareSerial serial)
{
if (!running) {
_serial = serial;
_serial.setRxBufferSize(PB_BUFSIZE);
_serial.begin(115200);
running = true;
LOG_DEBUG("Start communication thread");
}
}
int32_t SensecapIndicator::runOnce()
{
if (running) {
size_t bytes_read = 0;
// See if there are any more bytes to add to our buffer.
size_t space_left = PB_BUFSIZE - pb_rx_size;
bytes_read = serial_check((char *)pb_rx_buf + pb_rx_size, space_left);
pb_rx_size += bytes_read;
check_packet();
return (10);
} else {
LOG_DEBUG("Not running");
return (1000);
}
}
bool SensecapIndicator::send_uplink(meshtastic_InterdeviceMessage message)
{
pb_tx_buf[0] = MT_MAGIC_0;
pb_tx_buf[1] = MT_MAGIC_1;
pb_ostream_t stream = pb_ostream_from_buffer(pb_tx_buf + MT_HEADER_SIZE, PB_BUFSIZE);
if (!pb_encode(&stream, meshtastic_InterdeviceMessage_fields, &message)) {
LOG_DEBUG("pb_encode failed");
return false;
}
// Store the payload length in the header
pb_tx_buf[2] = stream.bytes_written / 256;
pb_tx_buf[3] = stream.bytes_written % 256;
bool rv = send((const char *)pb_tx_buf, MT_HEADER_SIZE + stream.bytes_written);
return rv;
}
size_t SensecapIndicator::serial_check(char *buf, size_t space_left)
{
size_t bytes_read = 0;
while (_serial.available()) {
char c = _serial.read();
*buf++ = c;
if (++bytes_read >= space_left) {
LOG_DEBUG("Serial overflow: %d > %d", bytes_read, space_left);
break;
}
}
return bytes_read;
}
void SensecapIndicator::check_packet()
{
if (pb_rx_size < MT_HEADER_SIZE) {
// We don't even have a header yet
delay(NO_NEWS_PAUSE);
return;
}
if (pb_rx_buf[0] != MT_MAGIC_0 || pb_rx_buf[1] != MT_MAGIC_1) {
LOG_DEBUG("Got bad magic");
memset(pb_rx_buf, 0, PB_BUFSIZE);
pb_rx_size = 0;
return;
}
uint16_t payload_len = pb_rx_buf[2] << 8 | pb_rx_buf[3];
if (payload_len > PB_BUFSIZE) {
LOG_DEBUG("Got packet claiming to be ridiculous length");
return;
}
if ((size_t)(payload_len + 4) > pb_rx_size) {
delay(NO_NEWS_PAUSE);
return;
}
// We have a complete packet, handle it
handle_packet(payload_len);
}
bool SensecapIndicator::handle_packet(size_t payload_len)
{
meshtastic_InterdeviceMessage message = meshtastic_InterdeviceMessage_init_zero;
// Decode the protobuf and shift forward any remaining bytes in the buffer
// (which, if present, belong to the packet that we're going to process on the
// next loop)
pb_istream_t stream = pb_istream_from_buffer(pb_rx_buf + MT_HEADER_SIZE, payload_len);
bool status = pb_decode(&stream, meshtastic_InterdeviceMessage_fields, &message);
memmove(pb_rx_buf, pb_rx_buf + MT_HEADER_SIZE + payload_len, PB_BUFSIZE - MT_HEADER_SIZE - payload_len);
pb_rx_size -= MT_HEADER_SIZE + payload_len;
if (!status) {
LOG_DEBUG("Decoding failed");
return false;
}
switch (message.which_data) {
case meshtastic_InterdeviceMessage_sensor_tag:
indicatorSensor.stuff_buffer(message.data.sensor);
return true;
break;
case meshtastic_InterdeviceMessage_nmea_tag:
// send String to NMEA processing
FakeSerial->stuff_buffer(message.data.nmea, strlen(message.data.nmea));
return true;
break;
default:
// the other messages really only flow downstream
LOG_DEBUG("Got a message of unexpected type");
return false;
}
}
bool SensecapIndicator::send(const char *buf, size_t len)
{
size_t wrote = _serial.write(buf, len);
if (wrote == len)
return true;
return false;
}
#endif // SENSECAP_INDICATOR

View File

@ -0,0 +1,48 @@
#pragma once
#ifndef INDICATORSERIAL_H
#define INDICATORSERIAL_H
#ifdef SENSECAP_INDICATOR
#include "concurrency/OSThread.h"
#include "configuration.h"
#include "mesh/generated/meshtastic/interdevice.pb.h"
// Magic number at the start of all MT packets
#define MT_MAGIC_0 0x94
#define MT_MAGIC_1 0xc3
// The header is the magic number plus a 16-bit payload-length field
#define MT_HEADER_SIZE 4
// Wait this many msec if there's nothing new on the channel
#define NO_NEWS_PAUSE 25
#define PB_BUFSIZE meshtastic_InterdeviceMessage_size + MT_HEADER_SIZE
class SensecapIndicator : public concurrency::OSThread
{
public:
SensecapIndicator();
void begin(HardwareSerial serial);
int32_t runOnce() override;
bool send_uplink(meshtastic_InterdeviceMessage message);
private:
pb_byte_t pb_tx_buf[PB_BUFSIZE];
pb_byte_t pb_rx_buf[PB_BUFSIZE];
size_t pb_rx_size = 0; // Number of bytes currently in the buffer
HardwareSerial _serial = Serial2;
bool running = false;
size_t serial_check(char *buf, size_t space_left);
void check_packet();
bool handle_packet(size_t payload_len);
bool send(const char *buf, size_t len);
};
extern SensecapIndicator sensecapIndicator;
#endif // SENSECAP_INDICATOR
#endif // INDICATORSERIAL_H

View File

@ -65,6 +65,8 @@ PB_BIND(meshtastic_Config_SessionkeyConfig, meshtastic_Config_SessionkeyConfig,

View File

@ -88,6 +88,23 @@ typedef enum _meshtastic_Config_DeviceConfig_RebroadcastMode {
meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY = 5 meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY = 5
} meshtastic_Config_DeviceConfig_RebroadcastMode; } meshtastic_Config_DeviceConfig_RebroadcastMode;
/* Defines buzzer behavior for audio feedback */
typedef enum _meshtastic_Config_DeviceConfig_BuzzerMode {
/* Default behavior.
Buzzer is enabled for all audio feedback including button presses and alerts. */
meshtastic_Config_DeviceConfig_BuzzerMode_ALL_ENABLED = 0,
/* Disabled.
All buzzer audio feedback is disabled. */
meshtastic_Config_DeviceConfig_BuzzerMode_DISABLED = 1,
/* Notifications Only.
Buzzer is enabled only for notifications and alerts, but not for button presses.
External notification config determines the specifics of the notification behavior. */
meshtastic_Config_DeviceConfig_BuzzerMode_NOTIFICATIONS_ONLY = 2,
/* Non-notification system buzzer tones only.
Buzzer is enabled only for non-notification tones such as button presses, startup, shutdown, but not for alerts. */
meshtastic_Config_DeviceConfig_BuzzerMode_SYSTEM_ONLY = 3
} meshtastic_Config_DeviceConfig_BuzzerMode;
/* Bit field of boolean configuration options, indicating which optional /* Bit field of boolean configuration options, indicating which optional
fields to include when assembling POSITION messages. fields to include when assembling POSITION messages.
Longitude, latitude, altitude, speed, heading, and DOP Longitude, latitude, altitude, speed, heading, and DOP
@ -335,6 +352,9 @@ typedef struct _meshtastic_Config_DeviceConfig {
char tzdef[65]; char tzdef[65];
/* If true, disable the default blinking LED (LED_PIN) behavior on the device */ /* If true, disable the default blinking LED (LED_PIN) behavior on the device */
bool led_heartbeat_disabled; bool led_heartbeat_disabled;
/* Controls buzzer behavior for audio feedback
Defaults to ENABLED */
meshtastic_Config_DeviceConfig_BuzzerMode buzzer_mode;
} meshtastic_Config_DeviceConfig; } meshtastic_Config_DeviceConfig;
/* Position Config */ /* Position Config */
@ -618,6 +638,10 @@ extern "C" {
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY #define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_RebroadcastMode)(meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY+1)) #define _meshtastic_Config_DeviceConfig_RebroadcastMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_RebroadcastMode)(meshtastic_Config_DeviceConfig_RebroadcastMode_CORE_PORTNUMS_ONLY+1))
#define _meshtastic_Config_DeviceConfig_BuzzerMode_MIN meshtastic_Config_DeviceConfig_BuzzerMode_ALL_ENABLED
#define _meshtastic_Config_DeviceConfig_BuzzerMode_MAX meshtastic_Config_DeviceConfig_BuzzerMode_SYSTEM_ONLY
#define _meshtastic_Config_DeviceConfig_BuzzerMode_ARRAYSIZE ((meshtastic_Config_DeviceConfig_BuzzerMode)(meshtastic_Config_DeviceConfig_BuzzerMode_SYSTEM_ONLY+1))
#define _meshtastic_Config_PositionConfig_PositionFlags_MIN meshtastic_Config_PositionConfig_PositionFlags_UNSET #define _meshtastic_Config_PositionConfig_PositionFlags_MIN meshtastic_Config_PositionConfig_PositionFlags_UNSET
#define _meshtastic_Config_PositionConfig_PositionFlags_MAX meshtastic_Config_PositionConfig_PositionFlags_SPEED #define _meshtastic_Config_PositionConfig_PositionFlags_MAX meshtastic_Config_PositionConfig_PositionFlags_SPEED
#define _meshtastic_Config_PositionConfig_PositionFlags_ARRAYSIZE ((meshtastic_Config_PositionConfig_PositionFlags)(meshtastic_Config_PositionConfig_PositionFlags_SPEED+1)) #define _meshtastic_Config_PositionConfig_PositionFlags_ARRAYSIZE ((meshtastic_Config_PositionConfig_PositionFlags)(meshtastic_Config_PositionConfig_PositionFlags_SPEED+1))
@ -669,6 +693,7 @@ extern "C" {
#define meshtastic_Config_DeviceConfig_role_ENUMTYPE meshtastic_Config_DeviceConfig_Role #define meshtastic_Config_DeviceConfig_role_ENUMTYPE meshtastic_Config_DeviceConfig_Role
#define meshtastic_Config_DeviceConfig_rebroadcast_mode_ENUMTYPE meshtastic_Config_DeviceConfig_RebroadcastMode #define meshtastic_Config_DeviceConfig_rebroadcast_mode_ENUMTYPE meshtastic_Config_DeviceConfig_RebroadcastMode
#define meshtastic_Config_DeviceConfig_buzzer_mode_ENUMTYPE meshtastic_Config_DeviceConfig_BuzzerMode
#define meshtastic_Config_PositionConfig_gps_mode_ENUMTYPE meshtastic_Config_PositionConfig_GpsMode #define meshtastic_Config_PositionConfig_gps_mode_ENUMTYPE meshtastic_Config_PositionConfig_GpsMode
@ -692,7 +717,7 @@ extern "C" {
/* Initializer values for message structs */ /* Initializer values for message structs */
#define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}} #define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}}
#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} #define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0, _meshtastic_Config_DeviceConfig_BuzzerMode_MIN}
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} #define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN}
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, "", 0, 0} #define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, "", 0, 0}
@ -703,7 +728,7 @@ extern "C" {
#define meshtastic_Config_SecurityConfig_init_default {{0, {0}}, {0, {0}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}}, 0, 0, 0, 0} #define meshtastic_Config_SecurityConfig_init_default {{0, {0}}, {0, {0}}, 0, {{0, {0}}, {0, {0}}, {0, {0}}}, 0, 0, 0, 0}
#define meshtastic_Config_SessionkeyConfig_init_default {0} #define meshtastic_Config_SessionkeyConfig_init_default {0}
#define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}} #define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}}
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0} #define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0, "", 0, _meshtastic_Config_DeviceConfig_BuzzerMode_MIN}
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN} #define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN}
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0} #define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, "", 0, 0} #define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, "", 0, 0}
@ -726,6 +751,7 @@ extern "C" {
#define meshtastic_Config_DeviceConfig_disable_triple_click_tag 10 #define meshtastic_Config_DeviceConfig_disable_triple_click_tag 10
#define meshtastic_Config_DeviceConfig_tzdef_tag 11 #define meshtastic_Config_DeviceConfig_tzdef_tag 11
#define meshtastic_Config_DeviceConfig_led_heartbeat_disabled_tag 12 #define meshtastic_Config_DeviceConfig_led_heartbeat_disabled_tag 12
#define meshtastic_Config_DeviceConfig_buzzer_mode_tag 13
#define meshtastic_Config_PositionConfig_position_broadcast_secs_tag 1 #define meshtastic_Config_PositionConfig_position_broadcast_secs_tag 1
#define meshtastic_Config_PositionConfig_position_broadcast_smart_enabled_tag 2 #define meshtastic_Config_PositionConfig_position_broadcast_smart_enabled_tag 2
#define meshtastic_Config_PositionConfig_fixed_position_tag 3 #define meshtastic_Config_PositionConfig_fixed_position_tag 3
@ -849,7 +875,8 @@ X(a, STATIC, SINGULAR, BOOL, double_tap_as_button_press, 8) \
X(a, STATIC, SINGULAR, BOOL, is_managed, 9) \ X(a, STATIC, SINGULAR, BOOL, is_managed, 9) \
X(a, STATIC, SINGULAR, BOOL, disable_triple_click, 10) \ X(a, STATIC, SINGULAR, BOOL, disable_triple_click, 10) \
X(a, STATIC, SINGULAR, STRING, tzdef, 11) \ X(a, STATIC, SINGULAR, STRING, tzdef, 11) \
X(a, STATIC, SINGULAR, BOOL, led_heartbeat_disabled, 12) X(a, STATIC, SINGULAR, BOOL, led_heartbeat_disabled, 12) \
X(a, STATIC, SINGULAR, UENUM, buzzer_mode, 13)
#define meshtastic_Config_DeviceConfig_CALLBACK NULL #define meshtastic_Config_DeviceConfig_CALLBACK NULL
#define meshtastic_Config_DeviceConfig_DEFAULT NULL #define meshtastic_Config_DeviceConfig_DEFAULT NULL
@ -995,7 +1022,7 @@ extern const pb_msgdesc_t meshtastic_Config_SessionkeyConfig_msg;
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size #define MESHTASTIC_MESHTASTIC_CONFIG_PB_H_MAX_SIZE meshtastic_Config_size
#define meshtastic_Config_BluetoothConfig_size 10 #define meshtastic_Config_BluetoothConfig_size 10
#define meshtastic_Config_DeviceConfig_size 98 #define meshtastic_Config_DeviceConfig_size 100
#define meshtastic_Config_DisplayConfig_size 32 #define meshtastic_Config_DisplayConfig_size 32
#define meshtastic_Config_LoRaConfig_size 85 #define meshtastic_Config_LoRaConfig_size 85
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20 #define meshtastic_Config_NetworkConfig_IpV4Config_size 20

View File

@ -55,6 +55,8 @@ typedef enum _meshtastic_Language {
meshtastic_Language_SLOVENIAN = 15, meshtastic_Language_SLOVENIAN = 15,
/* Ukrainian */ /* Ukrainian */
meshtastic_Language_UKRAINIAN = 16, meshtastic_Language_UKRAINIAN = 16,
/* Bulgarian */
meshtastic_Language_BULGARIAN = 17,
/* Simplified Chinese (experimental) */ /* Simplified Chinese (experimental) */
meshtastic_Language_SIMPLIFIED_CHINESE = 30, meshtastic_Language_SIMPLIFIED_CHINESE = 30,
/* Traditional Chinese (experimental) */ /* Traditional Chinese (experimental) */

View File

@ -360,7 +360,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg;
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
/* meshtastic_NodeDatabase_size depends on runtime parameters */ /* meshtastic_NodeDatabase_size depends on runtime parameters */
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size
#define meshtastic_BackupPreferences_size 2269 #define meshtastic_BackupPreferences_size 2271
#define meshtastic_ChannelFile_size 718 #define meshtastic_ChannelFile_size 718
#define meshtastic_DeviceState_size 1722 #define meshtastic_DeviceState_size 1722
#define meshtastic_NodeInfoLite_size 196 #define meshtastic_NodeInfoLite_size 196

View File

@ -187,7 +187,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalConfig_size #define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalConfig_size
#define meshtastic_LocalConfig_size 745 #define meshtastic_LocalConfig_size 747
#define meshtastic_LocalModuleConfig_size 669 #define meshtastic_LocalModuleConfig_size 669
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -258,6 +258,12 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK = 100, meshtastic_HardwareModel_SEEED_WIO_TRACKER_L1_EINK = 100,
/* Reserved ID for future and past use */ /* Reserved ID for future and past use */
meshtastic_HardwareModel_QWANTZ_TINY_ARMS = 101, meshtastic_HardwareModel_QWANTZ_TINY_ARMS = 101,
/* *
Lilygo T-Deck Pro */
meshtastic_HardwareModel_T_DECK_PRO = 102,
/* *
Lilygo TLora Pager */
meshtastic_HardwareModel_T_LORA_PAGER = 103,
/* ------------------------------------------------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------------------------------------------------
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
------------------------------------------------------------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------------------------------------------------------------ */

View File

@ -2,63 +2,21 @@
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(SENSECAP_INDICATOR) #if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && defined(SENSECAP_INDICATOR)
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "IndicatorSensor.h" #include "IndicatorSensor.h"
#include "IndicatorSerial.h"
#include "TelemetrySensor.h" #include "TelemetrySensor.h"
#include "serialization/cobs.h"
#include <Adafruit_Sensor.h> #include <Adafruit_Sensor.h>
#include <driver/uart.h> #include <driver/uart.h>
IndicatorSensor::IndicatorSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SENSOR_UNSET, "Indicator") {} IndicatorSensor::IndicatorSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_SENSOR_UNSET, "Indicator") {}
#define SENSOR_BUF_SIZE (512) static int cmd_send(meshtastic_MessageType cmd, uint32_t value)
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 send_buf[32] = {0}; meshtastic_InterdeviceMessage message = meshtastic_InterdeviceMessage_init_zero;
uint8_t send_data[32] = {0};
if (len > 31) { message.data.sensor.type = cmd;
return -1; message.data.sensor.data.uint32_value = value;
} return sensecapIndicator.send_uplink(message);
uint8_t index = 1;
send_data[0] = cmd;
if (len > 0 && p_data != NULL) {
memcpy(&send_data[1], p_data, len);
index += len;
}
cobs_encode_result ret = cobs_encode(send_buf, sizeof(send_buf), send_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, send_buf, ret.out_len + 1);
}
return -1;
} }
int32_t IndicatorSensor::runOnce() int32_t IndicatorSensor::runOnce()
@ -70,97 +28,64 @@ int32_t IndicatorSensor::runOnce()
void IndicatorSensor::setup() void IndicatorSensor::setup()
{ {
uart_config_t uart_config = { cmd_send(meshtastic_MessageType_POWER_ON, 0);
.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 // measure and send only once every minute, for the phone API
const char *interval = ultoa(60000, buffer, 10); cmd_send(meshtastic_MessageType_COLLECT_INTERVAL, 60000);
cmd_send(PKT_TYPE_CMD_COLLECT_INTERVAL, interval, strlen(interval) + 1);
} }
bool IndicatorSensor::getMetrics(meshtastic_Telemetry *measurement) bool IndicatorSensor::getMetrics(meshtastic_Telemetry *measurement)
{ {
cobs_decode_result ret; meshtastic_SensorData data = meshtastic_SensorData_init_zero;
int len = uart_read_bytes(SENSOR_PORT_NUM, buf, (SENSOR_BUF_SIZE - 1), 100 / portTICK_PERIOD_MS);
float value = 0.0; if (ringBuf.pop(data)) {
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]); switch (data.type) {
case meshtastic_MessageType_SCD41_CO2: {
if (ret.out_len > 1 && ret.status == COBS_DECODE_OK) {
value = 0.0;
uint8_t pkt_type = data[0];
switch (pkt_type) {
case PKT_TYPE_SENSOR_SCD41_CO2: {
memcpy(&value, &data[1], sizeof(value));
// LOG_DEBUG("CO2: %.1f", value); // LOG_DEBUG("CO2: %.1f", value);
cmd_send(PKT_TYPE_ACK, ACK_PKT_PARA, 4);
break; break;
} }
case PKT_TYPE_SENSOR_AHT20_TEMP: { case meshtastic_MessageType_AHT20_TEMP: {
memcpy(&value, &data[1], sizeof(value));
// LOG_DEBUG("Temp: %.1f", 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.has_temperature = true;
measurement->variant.environment_metrics.temperature = value; measurement->variant.environment_metrics.temperature = data.data.float_value;
break; break;
} }
case PKT_TYPE_SENSOR_AHT20_HUMIDITY: { case meshtastic_MessageType_AHT20_HUMIDITY: {
memcpy(&value, &data[1], sizeof(value));
// LOG_DEBUG("Humidity: %.1f", 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.has_relative_humidity = true;
measurement->variant.environment_metrics.relative_humidity = value; measurement->variant.environment_metrics.relative_humidity = data.data.float_value;
break; break;
} }
case PKT_TYPE_SENSOR_TVOC_INDEX: { case meshtastic_MessageType_TVOC_INDEX: {
memcpy(&value, &data[1], sizeof(value));
// LOG_DEBUG("Tvoc: %.1f", 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.has_iaq = true;
measurement->variant.environment_metrics.iaq = value; measurement->variant.environment_metrics.iaq = data.data.float_value;
break; break;
} }
default: default:
break; break;
} }
}
p_buf_start = p_buf_end + 1; // next message
}
return true; return true;
} }
return false; return false;
} }
size_t IndicatorSensor::stuff_buffer(meshtastic_SensorData message)
{
return ringBuf.push(message) ? 1 : 0;
}
#endif #endif

View File

@ -2,8 +2,10 @@
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR #if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
#include "../mesh/generated/meshtastic/interdevice.pb.h"
#include "../mesh/generated/meshtastic/telemetry.pb.h" #include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "TelemetrySensor.h" #include "TelemetrySensor.h"
#include <RingBuf.h>
class IndicatorSensor : public TelemetrySensor class IndicatorSensor : public TelemetrySensor
{ {
@ -14,6 +16,10 @@ class IndicatorSensor : public TelemetrySensor
IndicatorSensor(); IndicatorSensor();
virtual int32_t runOnce() override; virtual int32_t runOnce() override;
virtual bool getMetrics(meshtastic_Telemetry *measurement) override; virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
size_t stuff_buffer(meshtastic_SensorData message);
private:
RingBuf<meshtastic_SensorData, 16> ringBuf;
}; };
#endif #endif

View File

@ -1,129 +0,0 @@
#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};
if (!dst_buf_ptr || !src_ptr) {
result.status = COBS_ENCODE_NULL_POINTER;
return result;
}
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 search_len = 1;
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;
}
uint8_t 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};
if (!dst_buf_ptr || !src_ptr) {
result.status = COBS_DECODE_NULL_POINTER;
return result;
}
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;
const uint8_t *dst_buf_end_ptr = dst_buf_start_ptr + dst_buf_len;
uint8_t *dst_write_ptr = dst_buf_ptr;
if (src_len != 0) {
for (;;) {
uint8_t 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--;
size_t 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 (uint8_t i = len_code; i != 0; i--) {
uint8_t 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

View File

@ -1,75 +0,0 @@
#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_ */

View File

@ -9,6 +9,8 @@
#define GPS_POWER_TOGGLE // Moved definition from platformio.ini to here #define GPS_POWER_TOGGLE // Moved definition from platformio.ini to here
#define BUTTON_PIN 39 // The middle button GPIO on the T-Beam #define BUTTON_PIN 39 // The middle button GPIO on the T-Beam
// Note: On the ESP32 base version, gpio34-39 are input-only, and do not have internal pull-ups.
// If 39 is not being used for a button, it is suggested to remove the #define.
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO35_CHANNEL #define ADC_CHANNEL ADC1_GPIO35_CHANNEL
#define ADC_MULTIPLIER 1.85 // (R1 = 470k, R2 = 680k) #define ADC_MULTIPLIER 1.85 // (R1 = 470k, R2 = 680k)

View File

@ -9,7 +9,7 @@ board_check = true
board_build.partitions = default_8MB.csv board_build.partitions = default_8MB.csv
upload_protocol = esptool upload_protocol = esptool
build_flags = ${esp32_base.build_flags} build_flags = ${esp32s3_base.build_flags}
-Ivariants/seeed-sensecap-indicator -Ivariants/seeed-sensecap-indicator
-DSENSECAP_INDICATOR -DSENSECAP_INDICATOR
-DCONFIG_ARDUHAL_LOG_COLORS -DCONFIG_ARDUHAL_LOG_COLORS
@ -27,7 +27,7 @@ lib_deps = ${esp32s3_base.lib_deps}
https://github.com/mverch67/LovyanGFX/archive/4c76238c1344162a234ae917b27651af146d6fb2.zip https://github.com/mverch67/LovyanGFX/archive/4c76238c1344162a234ae917b27651af146d6fb2.zip
earlephilhower/ESP8266Audio@^1.9.9 earlephilhower/ESP8266Audio@^1.9.9
earlephilhower/ESP8266SAM@^1.0.1 earlephilhower/ESP8266SAM@^1.0.1
locoduino/RingBuffer@^1.0.5
[env:seeed-sensecap-indicator-tft] [env:seeed-sensecap-indicator-tft]
extends = env:seeed-sensecap-indicator extends = env:seeed-sensecap-indicator