Compare commits

...

8 Commits

Author SHA1 Message Date
Ben Meadors
394e0e1b3e T1000_E hw model 2024-07-26 06:30:28 -05:00
github-actions[bot]
755952c261 [create-pull-request] automated change (#4333)
Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
2024-07-26 06:29:05 -05:00
Ben Meadors
f645ae943d JSON serialization refactor (#4331) 2024-07-25 20:50:42 -05:00
Thomas Göttgens
4b0bbb8af1 Make STM compile again and update toolchain. (#2960)
* Make STM compile again and update toolchain. The binary is too big for the flash. WIP

* Making progress with OSFS, still WIP

* more progress, still too big. Adding RAK3172 to the equasion

* Make STM compile again and update toolchain. The binary is too big for the flash. WIP

* Making progress with OSFS, still WIP

* more progress, still too big. Adding RAK3172 to the equasion

* still too big

* minimize build

* trunk fmt

* fix a couple of symbol clashes

* trunk fmt

* down to 101% with a release vs. debug build and omitting the flash strings

* fix compilation

* fix compilation once more

* update protobufs linkage

* - Toolchain updated
- Fixed macro error

* silence compiler warning
note: do something about this assert...

* new toolkit and fix Power.cpp

* STM32WL make it fit (#4330)

* Add option to exclude I2C parts

The I2C hals and related code uses a significant amount of flash space and aren't required for a basic node.

* Add option to disable Admin and NodeInfo modules

Disabled by default in minimal build. This saves a significant amount of flash

* Disable unused hals

These use up significant flash

* Add float support for printf for debugging

Makes serial look nice for debugging

* This breaks my build for some reason

* These build flags can save a bit of flash

* Don't disable NodeInfo and Admin modules in minimal build

They fit in flash

* Don't include printf float support by default

Only useful for debugging

---------

Co-authored-by: Adam Lawson <dev@goshawk22.uk>

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Adam Lawson <dev@goshawk22.uk>
2024-07-25 20:16:21 -05:00
Ben Meadors
7ac64bd762 Trunk 2024-07-25 13:09:28 -05:00
Mark Trevor Birss
1481ce987e Fix T1000-E GPS - some changes went missing from #4303? (#4328)
* Update GPS.cpp

* Update GPS.cpp

* Update GPS.cpp

* Update GPS.cpp

* Update GPS.cpp

* Update GPS.cpp

* Update GPS.cpp

* Update GPS.cpp

* Update GPS.cpp
2024-07-25 13:05:03 -05:00
Ben Meadors
c5f2d2736d Whitespace trunk grousing 2024-07-24 21:14:58 -05:00
dylanli
a000a8d347 Support Seeed Tracker-T1000-E (#4303)
* feature-T1000-E: add Added the board definition for T1000-E

-  integrate a script for rapid dependency download that is compatible with both Linux and Windows platforms.
-  add the pin definitions for UART, SPI, GPIO, and other peripherals have been ensured to be correct.
-  add the env configuration for PlatformIO.

* refact-T1000-E: redefine T1000-E board

* feature-T1000-E: add basic sensors

* feature-T1000-E: add button init

* feat: add DRADIOLIB_GODMODE defination for use function setDioAsRfSwitch to DIO LORA RF

* feat : add gps(GNSS_Airoha) sleep mode

* feat: add behavier when rec or send message

* chore: hang IIC bus usage to avoid sensor address conflict

* feat: add sensor data acquisition

* feat : support Airoha GPS

- add disable it in FSM
- update  lookForTime and lookForLocation function

* fix: fix a bug

* version: change version to 0.9.0

* Update tracker-t1000-e.json

Remove a space

* Delete variants/tracker-t1000-e/run_once.sh

Delete not need as we will change platformio.ini

* Update platformio.ini

Update SoftDevice 7.3.0 usage in line with other lr1110 targets

Do we need to keep GODMODE ?

* fix: Button behavier incorrect bug

* fix:remove some invaild code of TextMessageModule

* fix: remove invaild comment

* version: change version to 0.9.1

- update mark's patch
- remove some invaild code and comments
- fix button behavier

* trunk format

* fix:  HELTEC_CAPSULE_SENSOR_V3 block got accidentally deleted

* fix: EnvironmentTelemetry upstream merge went awry.

* fix: Added macro definitions to ensure correct operation of LORA section

* fix :GNSS_AIROHA macro defination in line with others

* fix: upstream backmerge accidentally.

* fix: wrap macro PIN_3V3_EN BUZZER_EN_PIN GNSS_AIROHA in the TRACKER_T1000_E macro guard

---------

Co-authored-by: Mark Trevor Birss <markbirss@gmail.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
2024-07-24 21:10:38 -05:00
61 changed files with 992 additions and 1386 deletions

36
arch/stm32/stm32.ini Normal file
View File

@@ -0,0 +1,36 @@
[stm32_base]
extends = arduino_base
platform = ststm32
platform_packages = platformio/framework-arduinoststm32@https://github.com/stm32duino/Arduino_Core_STM32.git#361a7fdb67e2a7104e99b4f42a802469eef8b129
build_type = release
;board_build.flash_offset = 0x08000000
build_flags =
${arduino_base.build_flags}
-flto
-Isrc/platform/stm32wl -g
-DMESHTASTIC_MINIMIZE_BUILD
-DDEBUG_MUTE
; -DVECT_TAB_OFFSET=0x08000000
-DconfigUSE_CMSIS_RTOS_V2=1
; -DSPI_MODE_0=SPI_MODE0
-fmerge-all-constants
-ffunction-sections
-fdata-sections
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040> -<mesh/raspihttp>
board_upload.offset_address = 0x08000000
upload_protocol = stlink
lib_deps =
${env.lib_deps}
charlesbaynham/OSFS@^1.2.3
https://github.com/caveman99/Crypto.git#f61ae26a53f7a2d0ba5511625b8bf8eff3a35d5e
lib_ignore =
mathertel/OneButton
Wire

View File

@@ -1,28 +0,0 @@
[stm32wl5e_base]
platform_packages = platformio/framework-arduinoststm32 @ https://github.com/stm32duino/Arduino_Core_STM32.git#6e3f9910d0122e82a6c3438507dfac3d2fd80a39
platform = ststm32
board = generic_wl5e
framework = arduino
build_type = debug
build_flags =
${arduino_base.build_flags}
-Isrc/platform/stm32wl -g
-DconfigUSE_CMSIS_RTOS_V2=1
-DVECT_TAB_OFFSET=0x08000000
build_src_filter =
${arduino_base.build_src_filter} -<platform/esp32/> -<nimble/> -<mesh/api/> -<mesh/wifi/> -<mesh/http/> -<modules/esp32> -<mesh/eth/> -<input> -<buzz> -<modules/Telemetry> -<platform/nrf52> -<platform/portduino> -<platform/rp2040> -<mesh/raspihttp>
board_upload.offset_address = 0x08000000
upload_protocol = stlink
lib_deps =
${env.lib_deps}
https://github.com/kokke/tiny-AES-c.git#f06ac37fc31dfdaca2e0d9bec83f90d5663c319b
https://github.com/littlefs-project/littlefs.git#v2.5.1
https://github.com/stm32duino/STM32FreeRTOS.git#10.3.1
lib_ignore =
mathertel/OneButton

View File

@@ -0,0 +1,58 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v7.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DARDUINO_WIO_WM1110 -DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x8029"],
["0x239A", "0x0029"],
["0x239A", "0x002A"],
["0x239A", "0x802A"]
],
"usb_product": "T1000-E-BOOT",
"mcu": "nrf52840",
"variant": "Seeed_T1000-E",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "7.3.0",
"sd_fwid": "0x0123"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": ["bluetooth"],
"debug": {
"jlink_device": "nRF52840_xxAA",
"svd_path": "nrf52840.svd"
},
"frameworks": ["arduino"],
"name": "Seeed T1000-E",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": [
"jlink",
"nrfjprog",
"nrfutil",
"stlink",
"cmsis-dap",
"blackmagic"
],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
},
"url": "https://www.seeedstudio.com/SenseCAP-Card-Tracker-T1000-E-for-Meshtastic-p-5913.html",
"vendor": "Seeed Studio"
}

View File

@@ -1,5 +1,8 @@
{
"build": {
"arduino": {
"variant_h": "variant_RAK3172_MODULE.h"
},
"core": "stm32",
"cpu": "cortex-m4",
"extra_flags": "-DSTM32WLxx -DSTM32WLE5xx -DARDUINO_GENERIC_WLE5CCUX",

View File

@@ -29,7 +29,6 @@ volatile ButtonThread::ButtonEventType ButtonThread::btnEvent = ButtonThread::BU
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
OneButton ButtonThread::userButton; // Get reference to static member
#endif
ButtonThread::ButtonThread() : OSThread("Button")
{
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
@@ -43,7 +42,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
int pin = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN; // Resolved button pin
#if defined(HELTEC_CAPSULE_SENSOR_V3)
this->userButton = OneButton(pin, false, false);
#elif defined(BUTTON_ACTIVE_LOW) // change by WayenWeng
#elif defined(BUTTON_ACTIVE_LOW)
this->userButton = OneButton(pin, BUTTON_ACTIVE_LOW, BUTTON_ACTIVE_PULLUP);
#else
this->userButton = OneButton(pin, true, true);
@@ -53,7 +52,7 @@ ButtonThread::ButtonThread() : OSThread("Button")
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
#ifdef BUTTON_SENSE_TYPE // change by WayenWeng
#ifdef BUTTON_SENSE_TYPE
pinMode(pin, BUTTON_SENSE_TYPE);
#else
pinMode(pin, INPUT_PULLUP_SENSE);

View File

@@ -24,6 +24,30 @@ SPIClass SPI1(HSPI);
#endif // HAS_SDCARD
#if defined(ARCH_STM32WL)
uint16_t OSFS::startOfEEPROM = 1;
uint16_t OSFS::endOfEEPROM = 2048;
// 3) How do I read from the medium?
void OSFS::readNBytes(uint16_t address, unsigned int num, byte *output)
{
for (uint16_t i = address; i < address + num; i++) {
*output = EEPROM.read(i);
output++;
}
}
// 4) How to I write to the medium?
void OSFS::writeNBytes(uint16_t address, unsigned int num, const byte *input)
{
for (uint16_t i = address; i < address + num; i++) {
EEPROM.update(i, *input);
input++;
}
}
#endif
/**
* @brief Copies a file from one location to another.
*
@@ -33,7 +57,33 @@ SPIClass SPI1(HSPI);
*/
bool copyFile(const char *from, const char *to)
{
#ifdef FSCom
#ifdef ARCH_STM32WL
unsigned char cbuffer[2048];
// Var to hold the result of actions
OSFS::result r;
r = OSFS::getFile(from, cbuffer);
if (r == notfound) {
LOG_ERROR("Failed to open source file %s\n", from);
return false;
} else if (r == noerr) {
r = OSFS::newFile(to, cbuffer, true);
if (r == noerr) {
return true;
} else {
LOG_ERROR("OSFS Error %d\n", r);
return false;
}
} else {
LOG_ERROR("OSFS Error %d\n", r);
return false;
}
return true;
#elif defined(FSCom)
unsigned char cbuffer[16];
File f1 = FSCom.open(from, FILE_O_READ);
@@ -70,7 +120,13 @@ bool copyFile(const char *from, const char *to)
*/
bool renameFile(const char *pathFrom, const char *pathTo)
{
#ifdef FSCom
#ifdef ARCH_STM32WL
if (copyFile(pathFrom, pathTo) && (OSFS::deleteFile(pathFrom) == OSFS::result::NO_ERROR)) {
return true;
} else {
return false;
}
#elif defined(FSCom)
#ifdef ARCH_ESP32
// rename was fixed for ESP32 IDF LittleFS in April
return FSCom.rename(pathFrom, pathTo);

View File

@@ -15,10 +15,13 @@
#endif
#if defined(ARCH_STM32WL)
#include "platform/stm32wl/InternalFileSystem.h" // STM32WL version
#define FSCom InternalFS
#define FSBegin() FSCom.begin()
using namespace LittleFS_Namespace;
// STM32WL series 2 Kbytes (8 rows of 256 bytes)
#include <EEPROM.h>
#include <OSFS.h>
// Useful consts
const OSFS::result noerr = OSFS::result::NO_ERROR;
const OSFS::result notfound = OSFS::result::FILE_NOT_FOUND;
#endif
#if defined(ARCH_RP2040)

View File

@@ -200,7 +200,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
}
#endif
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !defined(HAS_PMU) && \
!MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
if (hasINA()) {
LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address);
return getINAVoltage();
@@ -420,7 +421,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
}
#endif
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO)
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL)
uint16_t getINAVoltage()
{
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) {

View File

@@ -259,6 +259,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MESHTASTIC_EXCLUDE_SCREEN 1
#define MESHTASTIC_EXCLUDE_MQTT 1
#define MESHTASTIC_EXCLUDE_POWERMON 1
#define MESHTASTIC_EXCLUDE_I2C 1
#endif
// Turn off all optional modules

View File

@@ -1,7 +1,8 @@
#include "ScanI2CTwoWire.h"
#if !MESHTASTIC_EXCLUDE_I2C
#include "concurrency/LockGuard.h"
#include "configuration.h"
#if defined(ARCH_PORTDUINO)
#include "linux/LinuxHardwareI2C.h"
#endif
@@ -403,3 +404,4 @@ size_t ScanI2CTwoWire::countDevices() const
{
return foundDevices.size();
}
#endif

View File

@@ -1,5 +1,8 @@
#pragma once
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_I2C
#include <map>
#include <memory>
#include <stddef.h>
@@ -56,3 +59,4 @@ class ScanI2CTwoWire : public ScanI2C
DeviceType probeOLED(ScanI2C::DeviceAddress) const;
};
#endif

View File

@@ -12,7 +12,7 @@
#include <freertos/task.h>
#endif
#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_RP2040)
#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_RP2040)
#define HAS_FREE_RTOS
#include <FreeRTOS.h>

View File

@@ -400,6 +400,13 @@ bool GPS::setup()
int msglen = 0;
if (!didSerialInit) {
#ifdef GNSS_AIROHA
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
probe(GPS_BAUDRATE);
LOG_INFO("GPS setting to %d.\n", GPS_BAUDRATE);
}
#else
#if !defined(GPS_UC6580)
if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
@@ -423,6 +430,9 @@ bool GPS::setup()
} else {
gnssModel = GNSS_MODEL_UNKNOWN;
}
#else
gnssModel = GNSS_MODEL_UC6580;
#endif
if (gnssModel == GNSS_MODEL_MTK) {
/*
@@ -774,6 +784,7 @@ bool GPS::setup()
LOG_INFO("GNSS module configuration saved!\n");
}
}
#endif
didSerialInit = true;
}
@@ -787,7 +798,6 @@ GPS::~GPS()
// we really should unregister our sleep observer
notifyDeepSleepObserver.unobserve(&notifyDeepSleep);
}
// Put the GPS hardware into a specified state
void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
{
@@ -824,6 +834,11 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
setPowerPMU(false); // Power (PMU): off
writePinStandby(true); // Standby (pin): asleep (not awake)
setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed
#ifdef GNSS_AIROHA
if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) {
digitalWrite(PIN_GPS_EN, LOW);
}
#endif
break;
case GPS_OFF:
@@ -833,6 +848,11 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
setPowerPMU(false); // Power (PMU): off
writePinStandby(true); // Standby (pin): asleep
setPowerUBLOX(false, 0); // Standby (UBLOX): asleep, indefinitely
#ifdef GNSS_AIROHA
if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) {
digitalWrite(PIN_GPS_EN, LOW);
}
#endif
break;
}
}
@@ -1162,7 +1182,7 @@ int GPS::prepareDeepSleep(void *unused)
GnssModel_t GPS::probe(int serialSpeed)
{
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040)
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)
_serial_gps->end();
_serial_gps->begin(serialSpeed);
#else
@@ -1171,7 +1191,8 @@ GnssModel_t GPS::probe(int serialSpeed)
_serial_gps->updateBaudRate(serialSpeed);
}
#endif
#ifdef GNSS_Airoha // add by WayenWeng
#ifdef GNSS_AIROHA
return GNSS_MODEL_UNKNOWN;
#else
#ifdef GPS_DEBUG
@@ -1249,7 +1270,7 @@ GnssModel_t GPS::probe(int serialSpeed)
_serial_gps->write(_message_prt, sizeof(_message_prt));
delay(500);
serialSpeed = 9600;
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040)
#if defined(ARCH_NRF52) || defined(ARCH_PORTDUINO) || defined(ARCH_RP2040) || defined(ARCH_STM32WL)
_serial_gps->end();
_serial_gps->begin(serialSpeed);
#else
@@ -1484,11 +1505,25 @@ bool GPS::factoryReset()
*/
bool GPS::lookForTime()
{
#ifdef GNSS_Airoha // add by WayenWeng
#ifdef GNSS_AIROHA
uint8_t fix = reader.fixQuality();
uint32_t now = millis();
if (fix > 0) {
if (lastFixStartMsec > 0) {
if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) {
return false;
} else {
clearBuffer();
}
} else {
lastFixStartMsec = now;
return false;
}
} else {
return false;
}
#endif
auto ti = reader.time;
auto d = reader.date;
if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
@@ -1523,13 +1558,26 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
*/
bool GPS::lookForLocation()
{
#ifdef GNSS_Airoha // add by WayenWeng
#ifdef GNSS_AIROHA
if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) {
uint8_t fix = reader.fixQuality();
uint32_t now = millis();
if (fix > 0) {
if (lastFixStartMsec > 0) {
if ((now - lastFixStartMsec) < GPS_FIX_HOLD_TIME) {
return false;
} else {
clearBuffer();
}
} else {
lastFixStartMsec = now;
return false;
}
} else {
return false;
}
}
#endif
// By default, TinyGPS++ does not parse GPGSA lines, which give us
// the 2D/3D fixType (see NMEAGPS.h)
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)
@@ -1739,6 +1787,12 @@ void GPS::toggleGpsMode()
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED;
LOG_INFO("User toggled GpsMode. Now DISABLED.\n");
#ifdef GNSS_AIROHA
if (powerState == GPS_ACTIVE) {
LOG_DEBUG("User power Off GPS\n");
digitalWrite(PIN_GPS_EN, LOW);
}
#endif
disable();
} else if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_DISABLED) {
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;

View File

@@ -69,7 +69,7 @@ class GPS : private concurrency::OSThread
#endif
private:
const int serialSpeeds[6] = {9600, 4800, 38400, 57600, 115200, 9600};
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0;
uint32_t rx_gpio = 0;
uint32_t tx_gpio = 0;
uint32_t en_gpio = 0;

View File

@@ -493,7 +493,7 @@ std::shared_ptr<GeoCoord> GeoCoord::pointAtDistance(double bearing, double range
* The bearing in string format
* @return Bearing in degrees
*/
uint GeoCoord::bearingToDegrees(const char *bearing)
unsigned int GeoCoord::bearingToDegrees(const char *bearing)
{
if (strcmp(bearing, "N") == 0)
return 0;
@@ -537,7 +537,7 @@ uint GeoCoord::bearingToDegrees(const char *bearing)
* The bearing in degrees
* @return Bearing in string format
*/
const char *GeoCoord::degreesToBearing(uint degrees)
const char *GeoCoord::degreesToBearing(unsigned int degrees)
{
if (degrees >= 348 || degrees < 11)
return "N";

View File

@@ -117,8 +117,8 @@ class GeoCoord
static float bearing(double lat1, double lon1, double lat2, double lon2);
static float rangeRadiansToMeters(double range_radians);
static float rangeMetersToRadians(double range_meters);
static uint bearingToDegrees(const char *bearing);
static const char *degreesToBearing(uint degrees);
static unsigned int bearingToDegrees(const char *bearing);
static const char *degreesToBearing(unsigned int degrees);
// Point to point conversions
int32_t distanceTo(const GeoCoord &pointB);

View File

@@ -20,7 +20,11 @@
#include "concurrency/OSThread.h"
#include "concurrency/Periodic.h"
#include "detect/ScanI2C.h"
#if !MESHTASTIC_EXCLUDE_I2C
#include "detect/ScanI2CTwoWire.h"
#include <Wire.h>
#endif
#include "detect/axpDebug.h"
#include "detect/einkScan.h"
#include "graphics/RAKled.h"
@@ -31,7 +35,6 @@
#include "shutdown.h"
#include "sleep.h"
#include "target_specific.h"
#include <Wire.h>
#include <memory>
#include <utility>
// #include <driver/rtc_io.h>
@@ -159,8 +162,10 @@ bool pauseBluetoothLogging = false;
bool pmu_found;
#if !MESHTASTIC_EXCLUDE_I2C
// Array map of sensor types with i2c address and wire as we'll find in the i2c scan
std::pair<uint8_t, TwoWire *> nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1] = {};
#endif
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
@@ -349,6 +354,7 @@ void setup()
#endif
#if !MESHTASTIC_EXCLUDE_I2C
#if defined(I2C_SDA1) && defined(ARCH_RP2040)
Wire1.setSDA(I2C_SDA1);
Wire1.setSCL(I2C_SCL1);
@@ -373,6 +379,7 @@ void setup()
#elif HAS_WIRE
Wire.begin();
#endif
#endif
#ifdef PIN_LCD_RESET
// FIXME - move this someplace better, LCD is at address 0x3F
@@ -405,6 +412,7 @@ void setup()
powerStatus->observe(&power->newStatus);
power->setup(); // Must be after status handler is installed, so that handler gets notified of the initial configuration
#if !MESHTASTIC_EXCLUDE_I2C
// We need to scan here to decide if we have a screen for nodeDB.init() and because power has been applied to
// accessories
auto i2cScanner = std::unique_ptr<ScanI2CTwoWire>(new ScanI2CTwoWire());
@@ -560,6 +568,7 @@ void setup()
SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK)
i2cScanner.reset();
#endif
#ifdef HAS_SDCARD
setupSDCard();
@@ -620,6 +629,7 @@ void setup()
screen_model = meshtastic_Config_DisplayConfig_OledType_OLED_SH1107; // keep dimension of 128x64
#endif
#if !MESHTASTIC_EXCLUDE_I2C
#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR
if (acc_info.type != ScanI2C::DeviceType::NONE) {
config.display.wake_on_tap_or_motion = true;
@@ -635,6 +645,7 @@ void setup()
ambientLightingThread = new AmbientLightingThread(rgb_found.type);
}
#endif
#endif
#ifdef T_WATCH_S3
drv.begin();
@@ -721,6 +732,7 @@ void setup()
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_NO_AXP192); // Record a hardware fault for missing hardware
#endif
#if !MESHTASTIC_EXCLUDE_I2C
// Don't call screen setup until after nodedb is setup (because we need
// the current region name)
#if defined(ST7735_CS) || defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7789_CS) || defined(HX8357_CS) || \
@@ -733,6 +745,7 @@ void setup()
#else
if (screen_found.port != ScanI2C::I2CPort::NO_I2C)
screen->setup();
#endif
#endif
screen->print("Started...\n");

View File

@@ -100,7 +100,13 @@ template <typename T> bool LR11x0Interface<T>::init()
// FIXME: May want to set depending on a definition, currently all LR1110 variant files use the DC-DC regulator option
if (res == RADIOLIB_ERR_NONE)
res = lora.setRegulatorDCDC();
#ifdef TRACKER_T1000_E
#ifdef LR11X0_DIO_RF_SWITCH_CONFIG
res = lora.setDioAsRfSwitch(LR11X0_DIO_RF_SWITCH_CONFIG);
#else
res = lora.setDioAsRfSwitch(0x03, 0x0, 0x01, 0x03, 0x02, 0x0, 0x0, 0x0);
#endif
#endif
if (res == RADIOLIB_ERR_NONE) {
if (config.lora.sx126x_rx_boosted_gain) { // the name is unfortunate but historically accurate
res = lora.setRxBoostedGainMode(true);

View File

@@ -192,9 +192,11 @@ bool NodeDB::factoryReset()
LOG_INFO("Performing factory reset!\n");
// first, remove the "/prefs" (this removes most prefs)
rmDir("/prefs");
#ifdef FSCom
if (FSCom.exists("/static/rangetest.csv") && !FSCom.remove("/static/rangetest.csv")) {
LOG_ERROR("Could not remove rangetest.csv file\n");
}
#endif
// second, install default state (this will deal with the duplicate mac address issue)
installDefaultDeviceState();
installDefaultConfig();
@@ -574,7 +576,7 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t
state = LoadFileResult::DECODE_FAILED;
} else {
LOG_INFO("Loaded %s successfully\n", filename);
state = LoadFileResult::SUCCESS;
state = LoadFileResult::LOAD_SUCCESS;
}
f.close();
} else {
@@ -582,7 +584,7 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t
}
#else
LOG_ERROR("ERROR: Filesystem not implemented\n");
state = LoadFileState::NO_FILESYSTEM;
state = LoadFileResult::NO_FILESYSTEM;
#endif
return state;
}
@@ -593,7 +595,7 @@ void NodeDB::loadFromDisk()
auto state = loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES * sizeof(meshtastic_NodeInfo),
sizeof(meshtastic_DeviceState), &meshtastic_DeviceState_msg, &devicestate);
if (state != LoadFileResult::SUCCESS) {
if (state != LoadFileResult::LOAD_SUCCESS) {
installDefaultDeviceState(); // Our in RAM copy might now be corrupt
} else {
if (devicestate.version < DEVICESTATE_MIN_VER) {
@@ -610,7 +612,7 @@ void NodeDB::loadFromDisk()
state = loadProto(configFileName, meshtastic_LocalConfig_size, sizeof(meshtastic_LocalConfig), &meshtastic_LocalConfig_msg,
&config);
if (state != LoadFileResult::SUCCESS) {
if (state != LoadFileResult::LOAD_SUCCESS) {
installDefaultConfig(); // Our in RAM copy might now be corrupt
} else {
if (config.version < DEVICESTATE_MIN_VER) {
@@ -623,7 +625,7 @@ void NodeDB::loadFromDisk()
state = loadProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, sizeof(meshtastic_LocalModuleConfig),
&meshtastic_LocalModuleConfig_msg, &moduleConfig);
if (state != LoadFileResult::SUCCESS) {
if (state != LoadFileResult::LOAD_SUCCESS) {
installDefaultModuleConfig(); // Our in RAM copy might now be corrupt
} else {
if (moduleConfig.version < DEVICESTATE_MIN_VER) {
@@ -636,7 +638,7 @@ void NodeDB::loadFromDisk()
state = loadProto(channelFileName, meshtastic_ChannelFile_size, sizeof(meshtastic_ChannelFile), &meshtastic_ChannelFile_msg,
&channelFile);
if (state != LoadFileResult::SUCCESS) {
if (state != LoadFileResult::LOAD_SUCCESS) {
installDefaultChannels(); // Our in RAM copy might now be corrupt
} else {
if (channelFile.version < DEVICESTATE_MIN_VER) {
@@ -648,7 +650,7 @@ void NodeDB::loadFromDisk()
}
state = loadProto(oemConfigFile, meshtastic_OEMStore_size, sizeof(meshtastic_OEMStore), &meshtastic_OEMStore_msg, &oemStore);
if (state == LoadFileResult::SUCCESS) {
if (state == LoadFileResult::LOAD_SUCCESS) {
LOG_INFO("Loaded OEMStore\n");
}

View File

@@ -40,7 +40,7 @@ uint32_t sinceReceived(const meshtastic_MeshPacket *p);
enum LoadFileResult {
// Successfully opened the file
SUCCESS = 1,
LOAD_SUCCESS = 1,
// File does not exist
NOT_FOUND = 2,
// Device does not have a filesystem

View File

@@ -42,7 +42,9 @@ void PhoneAPI::handleStartConfig()
if (!isConnected()) {
onConnectionChanged(true);
observe(&service.fromNumChanged);
#ifdef FSCom
observe(&xModem.packetReady);
#endif
}
// even if we were already connected - restart our state machine
@@ -62,7 +64,9 @@ void PhoneAPI::close()
state = STATE_SEND_NOTHING;
unobserve(&service.fromNumChanged);
#ifdef FSCom
unobserve(&xModem.packetReady);
#endif
releasePhonePacket(); // Don't leak phone packets on shutdown
releaseQueueStatusPhonePacket();
releaseMqttClientProxyPhonePacket();
@@ -110,7 +114,9 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
break;
case meshtastic_ToRadio_xmodemPacket_tag:
LOG_INFO("Got xmodem packet\n");
#ifdef FSCom
xModem.handlePacket(toRadioScratch.xmodemPacket);
#endif
break;
#if !MESHTASTIC_EXCLUDE_MQTT
case meshtastic_ToRadio_mqttClientProxyMessage_tag:
@@ -496,12 +502,14 @@ bool PhoneAPI::available()
if (hasPacket)
return true;
#ifdef FSCom
if (xmodemPacketForPhone.control == meshtastic_XModem_Control_NUL)
xmodemPacketForPhone = xModem.getForPhone();
if (xmodemPacketForPhone.control != meshtastic_XModem_Control_NUL) {
xModem.resetForPhone();
return true;
}
#endif
#ifdef ARCH_ESP32
#if !MESHTASTIC_EXCLUDE_STOREFORWARD

View File

@@ -23,7 +23,7 @@ static const float tcxoVoltage = 1.7;
* Wio-E5 module ONLY transmits through RFO_HP
* Receive: PA4=1, PA5=0
* Transmit(high output power, SMPS mode): PA4=0, PA5=1 */
static const RADIOLIB_PIN_TYPE rfswitch_pins[3] = {PA4, PA5, RADIOLIB_NC};
static const RADIOLIB_PIN_TYPE rfswitch_pins[5] = {PA4, PA5, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
static const Module::RfSwitchMode_t rfswitch_table[4] = {
{STM32WLx::MODE_IDLE, {LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, LOW}}, {STM32WLx::MODE_TX_HP, {LOW, HIGH}}, END_OF_MODE_TABLE};

View File

@@ -178,6 +178,8 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_HELTEC_MESH_NODE_T114 = 69,
/* Sensecap Indicator from Seeed Studio. ESP32-S3 device with TFT and RP2040 coprocessor */
meshtastic_HardwareModel_SENSECAP_INDICATOR = 70,
/* Seeed studio T1000-E tracker card. NRF52840 w/ LR1110 radio, GPS, button, buzzer, and sensors. */
meshtastic_HardwareModel_TRACKER_T1000_E = 71,
/* ------------------------------------------------------------------------------------------------------------------------------------------
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

@@ -9,8 +9,8 @@
#if HAS_WIFI
#include "mesh/wifi/WiFiAPClient.h"
#endif
#include "mqtt/JSON.h"
#include "power.h"
#include "serialization/JSON.h"
#include "sleep.h"
#include <FSCommon.h>
#include <HTTPBodyParser.hpp>

View File

@@ -1,6 +1,7 @@
#include "mesh-pb-constants.h"
#include "FSCommon.h"
#include "configuration.h"
#include "FSCommon.h"
#include "mesh-pb-constants.h"
#include <Arduino.h>
#include <assert.h>
#include <pb_decode.h>
@@ -15,6 +16,7 @@ size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc
LOG_ERROR("Panic: can't encode protobuf reason='%s'\n", PB_GET_ERROR(&stream));
assert(
0); // If this assert fails it probably means you made a field too large for the max limits specified in mesh.options
return 0;
} else {
return stream.bytes_written;
}

View File

@@ -259,11 +259,13 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
}
case meshtastic_AdminMessage_delete_file_request_tag: {
LOG_DEBUG("Client is requesting to delete file: %s\n", r->delete_file_request);
#ifdef FSCom
if (FSCom.remove(r->delete_file_request)) {
LOG_DEBUG("Successfully deleted file\n");
} else {
LOG_DEBUG("Failed to delete file\n");
}
#endif
break;
}
#ifdef ARCH_PORTDUINO

View File

@@ -1066,7 +1066,7 @@ void CannedMessageModule::loadProtoForModule()
{
if (nodeDB->loadProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size,
sizeof(meshtastic_CannedMessageModuleConfig), &meshtastic_CannedMessageModuleConfig_msg,
&cannedMessageModuleConfig) != LoadFileResult::SUCCESS) {
&cannedMessageModuleConfig) != LoadFileResult::LOAD_SUCCESS) {
installDefaultCannedMessageModuleConfig();
}
}

View File

@@ -355,7 +355,7 @@ ExternalNotificationModule::ExternalNotificationModule()
if (moduleConfig.external_notification.enabled) {
if (nodeDB->loadProto(rtttlConfigFile, meshtastic_RTTTLConfig_size, sizeof(meshtastic_RTTTLConfig),
&meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::SUCCESS) {
&meshtastic_RTTTLConfig_msg, &rtttlConfig) != LoadFileResult::LOAD_SUCCESS) {
memset(rtttlConfig.ringtone, 0, sizeof(rtttlConfig.ringtone));
strncpy(rtttlConfig.ringtone,
"24:d=32,o=5,b=565:f6,p,f6,4p,p,f6,p,f6,2p,p,b6,p,b6,p,b6,p,b6,p,b,p,b,p,b,p,b,p,b,p,b,p,b,p,b,1p.,2p.,p",

View File

@@ -7,7 +7,9 @@
#include "input/cardKbI2cImpl.h"
#include "input/kbMatrixImpl.h"
#endif
#if !MESHTASTIC_EXCLUDE_ADMIN
#include "modules/AdminModule.h"
#endif
#if !MESHTASTIC_EXCLUDE_ATAK
#include "modules/AtakPluginModule.h"
#endif
@@ -20,7 +22,9 @@
#if !MESHTASTIC_EXCLUDE_NEIGHBORINFO
#include "modules/NeighborInfoModule.h"
#endif
#if !MESHTASTIC_EXCLUDE_NODEINFO
#include "modules/NodeInfoModule.h"
#endif
#if !MESHTASTIC_EXCLUDE_GPS
#include "modules/PositionModule.h"
#endif
@@ -88,8 +92,12 @@ void setupModules()
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
inputBroker = new InputBroker();
#endif
#if !MESHTASTIC_EXCLUDE_ADMIN
adminModule = new AdminModule();
#endif
#if !MESHTASTIC_EXCLUDE_NODEINFO
nodeInfoModule = new NodeInfoModule();
#endif
#if !MESHTASTIC_EXCLUDE_GPS
positionModule = new PositionModule();
#endif
@@ -192,7 +200,9 @@ void setupModules()
#endif
#endif
} else {
#if !MESHTASTIC_EXCLUDE_ADMIN
adminModule = new AdminModule();
#endif
#if HAS_TELEMETRY
new DeviceTelemetryModule();
#endif

View File

@@ -33,9 +33,7 @@
#include "Sensor/SHT31Sensor.h"
#include "Sensor/SHT4XSensor.h"
#include "Sensor/SHTC3Sensor.h"
#ifdef T1000X_SENSOR_EN
#include "Sensor/T1000xSensor.h"
#endif
#include "Sensor/TSL2591Sensor.h"
#include "Sensor/VEML7700Sensor.h"
@@ -98,7 +96,7 @@ int32_t EnvironmentTelemetryModule::runOnce()
LOG_INFO("Environment Telemetry: Initializing\n");
// 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 T1000X_SENSOR_EN // add by WayenWeng
#ifdef T1000X_SENSOR_EN
result = t1000xSensor.runOnce();
#else
if (dfRobotLarkSensor.hasSensor())
@@ -420,7 +418,11 @@ meshtastic_MeshPacket *EnvironmentTelemetryModule::allocReply()
bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
{
meshtastic_Telemetry m = meshtastic_Telemetry_init_zero;
#ifdef T1000X_SENSOR_EN
if (t1000xSensor.getMetrics(&m)) {
#else
if (getEnvironmentTelemetry(&m)) {
#endif
LOG_INFO("(Sending): barometric_pressure=%f, current=%f, gas_resistance=%f, relative_humidity=%f, temperature=%f\n",
m.variant.environment_metrics.barometric_pressure, m.variant.environment_metrics.current,
m.variant.environment_metrics.gas_resistance, m.variant.environment_metrics.relative_humidity,

View File

@@ -7,7 +7,6 @@
class T1000xSensor : public TelemetrySensor
{
private:
protected:
virtual void setup() override;

View File

@@ -2,8 +2,8 @@
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include "buzz.h"
#include "configuration.h"
TextMessageModule *textMessageModule;
ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
@@ -12,7 +12,6 @@ ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp
auto &p = mp.decoded;
LOG_INFO("Received text msg from=0x%0x, id=0x%x, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes);
#endif
// We only store/display messages destined for us.
// Keep a copy of the most recent text message.
devicestate.rx_text_message = mp;

View File

@@ -19,6 +19,8 @@
#include <WiFi.h>
#endif
#include "Default.h"
#include "serialization/JSON.h"
#include "serialization/MeshPacketSerializer.h"
#include <assert.h>
const int reconnectMax = 5;
@@ -459,7 +461,7 @@ void MQTT::publishQueuedMessages()
#ifndef ARCH_NRF52 // JSON is not supported on nRF52, see issue #2804
if (moduleConfig.mqtt.json_enabled) {
// handle json topic
auto jsonString = this->meshPacketToJson(env->packet);
auto jsonString = MeshPacketSerializer::JsonSerialize(env->packet);
if (jsonString.length() != 0) {
std::string topicJson = jsonTopic + env->channel_id + "/" + owner.id;
LOG_INFO("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(),
@@ -520,7 +522,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket &
#ifndef ARCH_NRF52 // JSON is not supported on nRF52, see issue #2804
if (moduleConfig.mqtt.json_enabled) {
// handle json topic
auto jsonString = this->meshPacketToJson((meshtastic_MeshPacket *)&mp_decoded);
auto jsonString = MeshPacketSerializer::JsonSerialize((meshtastic_MeshPacket *)&mp_decoded);
if (jsonString.length() != 0) {
std::string topicJson = jsonTopic + channelId + "/" + owner.id;
LOG_INFO("JSON publish message to %s, %u bytes: %s\n", topicJson.c_str(), jsonString.length(),
@@ -621,304 +623,6 @@ void MQTT::perhapsReportToMap()
}
}
// converts a downstream packet into a json message
std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
{
// the created jsonObj is immutable after creation, so
// we need to do the heavy lifting before assembling it.
std::string msgType;
JSONObject jsonObj;
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
JSONObject msgPayload;
switch (mp->decoded.portnum) {
case meshtastic_PortNum_TEXT_MESSAGE_APP: {
msgType = "text";
// convert bytes to string
LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size);
char payloadStr[(mp->decoded.payload.size) + 1];
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
// check if this is a JSON payload
JSONValue *json_value = JSON::Parse(payloadStr);
if (json_value != NULL) {
LOG_INFO("text message payload is of type json\n");
// if it is, then we can just use the json object
jsonObj["payload"] = json_value;
} else {
// if it isn't, then we need to create a json object
// with the string as the value
LOG_INFO("text message payload is of type plaintext\n");
msgPayload["text"] = new JSONValue(payloadStr);
jsonObj["payload"] = new JSONValue(msgPayload);
}
break;
}
case meshtastic_PortNum_TELEMETRY_APP: {
msgType = "telemetry";
meshtastic_Telemetry scratch;
meshtastic_Telemetry *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
decoded = &scratch;
if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) {
msgPayload["battery_level"] = new JSONValue((unsigned int)decoded->variant.device_metrics.battery_level);
msgPayload["voltage"] = new JSONValue(decoded->variant.device_metrics.voltage);
msgPayload["channel_utilization"] = new JSONValue(decoded->variant.device_metrics.channel_utilization);
msgPayload["air_util_tx"] = new JSONValue(decoded->variant.device_metrics.air_util_tx);
msgPayload["uptime_seconds"] = new JSONValue((unsigned int)decoded->variant.device_metrics.uptime_seconds);
} else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) {
msgPayload["temperature"] = new JSONValue(decoded->variant.environment_metrics.temperature);
msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity);
msgPayload["barometric_pressure"] = new JSONValue(decoded->variant.environment_metrics.barometric_pressure);
msgPayload["gas_resistance"] = new JSONValue(decoded->variant.environment_metrics.gas_resistance);
msgPayload["voltage"] = new JSONValue(decoded->variant.environment_metrics.voltage);
msgPayload["current"] = new JSONValue(decoded->variant.environment_metrics.current);
msgPayload["lux"] = new JSONValue(decoded->variant.environment_metrics.lux);
msgPayload["white_lux"] = new JSONValue(decoded->variant.environment_metrics.white_lux);
msgPayload["iaq"] = new JSONValue((uint)decoded->variant.environment_metrics.iaq);
msgPayload["wind_speed"] = new JSONValue(decoded->variant.environment_metrics.wind_speed);
msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction);
msgPayload["wind_gust"] = new JSONValue(decoded->variant.environment_metrics.wind_gust);
msgPayload["wind_lull"] = new JSONValue(decoded->variant.environment_metrics.wind_lull);
} else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) {
msgPayload["voltage_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_voltage);
msgPayload["current_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_current);
msgPayload["voltage_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_voltage);
msgPayload["current_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_current);
msgPayload["voltage_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_voltage);
msgPayload["current_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_current);
}
jsonObj["payload"] = new JSONValue(msgPayload);
} else {
LOG_ERROR("Error decoding protobuf for telemetry message!\n");
}
break;
}
case meshtastic_PortNum_NODEINFO_APP: {
msgType = "nodeinfo";
meshtastic_User scratch;
meshtastic_User *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) {
decoded = &scratch;
msgPayload["id"] = new JSONValue(decoded->id);
msgPayload["longname"] = new JSONValue(decoded->long_name);
msgPayload["shortname"] = new JSONValue(decoded->short_name);
msgPayload["hardware"] = new JSONValue(decoded->hw_model);
jsonObj["payload"] = new JSONValue(msgPayload);
} else {
LOG_ERROR("Error decoding protobuf for nodeinfo message!\n");
}
break;
}
case meshtastic_PortNum_POSITION_APP: {
msgType = "position";
meshtastic_Position scratch;
meshtastic_Position *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) {
decoded = &scratch;
if ((int)decoded->time) {
msgPayload["time"] = new JSONValue((unsigned int)decoded->time);
}
if ((int)decoded->timestamp) {
msgPayload["timestamp"] = new JSONValue((unsigned int)decoded->timestamp);
}
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
if ((int)decoded->altitude) {
msgPayload["altitude"] = new JSONValue((int)decoded->altitude);
}
if ((int)decoded->ground_speed) {
msgPayload["ground_speed"] = new JSONValue((unsigned int)decoded->ground_speed);
}
if (int(decoded->ground_track)) {
msgPayload["ground_track"] = new JSONValue((unsigned int)decoded->ground_track);
}
if (int(decoded->sats_in_view)) {
msgPayload["sats_in_view"] = new JSONValue((unsigned int)decoded->sats_in_view);
}
if ((int)decoded->PDOP) {
msgPayload["PDOP"] = new JSONValue((int)decoded->PDOP);
}
if ((int)decoded->HDOP) {
msgPayload["HDOP"] = new JSONValue((int)decoded->HDOP);
}
if ((int)decoded->VDOP) {
msgPayload["VDOP"] = new JSONValue((int)decoded->VDOP);
}
if ((int)decoded->precision_bits) {
msgPayload["precision_bits"] = new JSONValue((int)decoded->precision_bits);
}
jsonObj["payload"] = new JSONValue(msgPayload);
} else {
LOG_ERROR("Error decoding protobuf for position message!\n");
}
break;
}
case meshtastic_PortNum_WAYPOINT_APP: {
msgType = "position";
meshtastic_Waypoint scratch;
meshtastic_Waypoint *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
decoded = &scratch;
msgPayload["id"] = new JSONValue((unsigned int)decoded->id);
msgPayload["name"] = new JSONValue(decoded->name);
msgPayload["description"] = new JSONValue(decoded->description);
msgPayload["expire"] = new JSONValue((unsigned int)decoded->expire);
msgPayload["locked_to"] = new JSONValue((unsigned int)decoded->locked_to);
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
jsonObj["payload"] = new JSONValue(msgPayload);
} else {
LOG_ERROR("Error decoding protobuf for position message!\n");
}
break;
}
case meshtastic_PortNum_NEIGHBORINFO_APP: {
msgType = "neighborinfo";
meshtastic_NeighborInfo scratch;
meshtastic_NeighborInfo *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg,
&scratch)) {
decoded = &scratch;
msgPayload["node_id"] = new JSONValue((unsigned int)decoded->node_id);
msgPayload["node_broadcast_interval_secs"] = new JSONValue((unsigned int)decoded->node_broadcast_interval_secs);
msgPayload["last_sent_by_id"] = new JSONValue((unsigned int)decoded->last_sent_by_id);
msgPayload["neighbors_count"] = new JSONValue(decoded->neighbors_count);
JSONArray neighbors;
for (uint8_t i = 0; i < decoded->neighbors_count; i++) {
JSONObject neighborObj;
neighborObj["node_id"] = new JSONValue((unsigned int)decoded->neighbors[i].node_id);
neighborObj["snr"] = new JSONValue((int)decoded->neighbors[i].snr);
neighbors.push_back(new JSONValue(neighborObj));
}
msgPayload["neighbors"] = new JSONValue(neighbors);
jsonObj["payload"] = new JSONValue(msgPayload);
} else {
LOG_ERROR("Error decoding protobuf for neighborinfo message!\n");
}
break;
}
case meshtastic_PortNum_TRACEROUTE_APP: {
if (mp->decoded.request_id) { // Only report the traceroute response
msgType = "traceroute";
meshtastic_RouteDiscovery scratch;
meshtastic_RouteDiscovery *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_RouteDiscovery_msg,
&scratch)) {
decoded = &scratch;
JSONArray route; // Route this message took
// Lambda function for adding a long name to the route
auto addToRoute = [](JSONArray *route, NodeNum num) {
char long_name[40] = "Unknown";
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(num);
bool name_known = node ? node->has_user : false;
if (name_known)
memcpy(long_name, node->user.long_name, sizeof(long_name));
route->push_back(new JSONValue(long_name));
};
addToRoute(&route, mp->to); // Started at the original transmitter (destination of response)
for (uint8_t i = 0; i < decoded->route_count; i++) {
addToRoute(&route, decoded->route[i]);
}
addToRoute(&route, mp->from); // Ended at the original destination (source of response)
msgPayload["route"] = new JSONValue(route);
jsonObj["payload"] = new JSONValue(msgPayload);
} else {
LOG_ERROR("Error decoding protobuf for traceroute message!\n");
}
}
break;
}
case meshtastic_PortNum_DETECTION_SENSOR_APP: {
msgType = "detection";
char payloadStr[(mp->decoded.payload.size) + 1];
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
msgPayload["text"] = new JSONValue(payloadStr);
jsonObj["payload"] = new JSONValue(msgPayload);
break;
}
#ifdef ARCH_ESP32
case meshtastic_PortNum_PAXCOUNTER_APP: {
msgType = "paxcounter";
meshtastic_Paxcount scratch;
meshtastic_Paxcount *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Paxcount_msg, &scratch)) {
decoded = &scratch;
msgPayload["wifi_count"] = new JSONValue((unsigned int)decoded->wifi);
msgPayload["ble_count"] = new JSONValue((unsigned int)decoded->ble);
msgPayload["uptime"] = new JSONValue((unsigned int)decoded->uptime);
jsonObj["payload"] = new JSONValue(msgPayload);
} else {
LOG_ERROR("Error decoding protobuf for Paxcount message!\n");
}
break;
}
#endif
case meshtastic_PortNum_REMOTE_HARDWARE_APP: {
meshtastic_HardwareMessage scratch;
meshtastic_HardwareMessage *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_HardwareMessage_msg,
&scratch)) {
decoded = &scratch;
if (decoded->type == meshtastic_HardwareMessage_Type_GPIOS_CHANGED) {
msgType = "gpios_changed";
msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value);
jsonObj["payload"] = new JSONValue(msgPayload);
} else if (decoded->type == meshtastic_HardwareMessage_Type_READ_GPIOS_REPLY) {
msgType = "gpios_read_reply";
msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value);
msgPayload["gpio_mask"] = new JSONValue((unsigned int)decoded->gpio_mask);
jsonObj["payload"] = new JSONValue(msgPayload);
}
} else {
LOG_ERROR("Error decoding protobuf for RemoteHardware message!\n");
}
break;
}
// add more packet types here if needed
default:
break;
}
} else {
LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON\n");
}
jsonObj["id"] = new JSONValue((unsigned int)mp->id);
jsonObj["timestamp"] = new JSONValue((unsigned int)mp->rx_time);
jsonObj["to"] = new JSONValue((unsigned int)mp->to);
jsonObj["from"] = new JSONValue((unsigned int)mp->from);
jsonObj["channel"] = new JSONValue((unsigned int)mp->channel);
jsonObj["type"] = new JSONValue(msgType.c_str());
jsonObj["sender"] = new JSONValue(owner.id);
if (mp->rx_rssi != 0)
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
if (mp->rx_snr != 0)
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit));
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
}
// serialize and write it to the stream
JSONValue *value = new JSONValue(jsonObj);
std::string jsonStr = value->Stringify();
LOG_INFO("serialized json message: %s\n", jsonStr.c_str());
delete value;
return jsonStr;
}
bool MQTT::isValidJsonEnvelope(JSONObject &json)
{
// if "sender" is provided, avoid processing packets we uplinked

View File

@@ -5,7 +5,7 @@
#include "concurrency/OSThread.h"
#include "mesh/Channels.h"
#include "mesh/generated/meshtastic/mqtt.pb.h"
#include "mqtt/JSON.h"
#include "serialization/JSON.h"
#if HAS_WIFI
#include <WiFiClient.h>
#if !defined(ARCH_PORTDUINO)
@@ -106,9 +106,6 @@ class MQTT : private concurrency::OSThread
/// Called when a new publish arrives from the MQTT server
void onReceive(char *topic, byte *payload, size_t length);
/// Called when a new publish arrives from the MQTT server
std::string meshPacketToJson(meshtastic_MeshPacket *mp);
void publishQueuedMessages();
void publishNodeInfo();

View File

@@ -60,6 +60,8 @@
#define HW_VENDOR meshtastic_HardwareModel_NRF52_PROMICRO_DIY
#elif defined(WIO_WM1110)
#define HW_VENDOR meshtastic_HardwareModel_WIO_WM1110
#elif defined(TRACKER_T1000_E)
#define HW_VENDOR meshtastic_HardwareModel_TRACKER_T1000_E
#elif defined(PRIVATE_HW) || defined(FEATHER_DIY)
#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
#else

View File

@@ -1,141 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 hathach for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "InternalFileSystem.h"
#include <EEPROM.h>
//--------------------------------------------------------------------+
// LFS Disk IO
//--------------------------------------------------------------------+
static inline uint32_t lba2addr(uint32_t block)
{
return ((uint32_t)LFS_FLASH_ADDR) + block * LFS_BLOCK_SIZE;
}
static int _internal_flash_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer, lfs_size_t size)
{
(void)c;
uint32_t addr = lba2addr(block) + off;
uint8_t prom;
for (int i = 0; i < size; i++) {
prom = EEPROM.read(addr + i);
memcpy((char *)buffer + i, &prom, 1);
}
return 0;
}
// Program a region in a block. The block must have previously
// been erased. Negative error codes are propagated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad.
static int _internal_flash_prog(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer, lfs_size_t size)
{
(void)c;
uint32_t addr = lba2addr(block) + off;
uint8_t prom;
for (int i = 0; i < size; i++) {
memcpy(&prom, (char *)buffer + i, 1);
EEPROM.update(addr + i, prom);
}
return 0;
}
// Erase a block. A block must be erased before being programmed.
// The state of an erased block is undefined. Negative error codes
// are propagated to the user.
// May return LFS_ERR_CORRUPT if the block should be considered bad.
static int _internal_flash_erase(const struct lfs_config *c, lfs_block_t block)
{
(void)c;
uint32_t addr = lba2addr(block);
// implement as write 0xff to whole block address
for (int i = 0; i < LFS_BLOCK_SIZE; i++) {
EEPROM.update(addr, 0xff);
}
return 0;
}
// Sync the state of the underlying block device. Negative error codes
// are propagated to the user.
static int _internal_flash_sync(const struct lfs_config *c)
{
// we don't use a ram cache, this is a noop
return 0;
}
static struct lfs_config _InternalFSConfig = {.context = NULL,
.read = _internal_flash_read,
.prog = _internal_flash_prog,
.erase = _internal_flash_erase,
.sync = _internal_flash_sync,
.read_size = LFS_CACHE_SIZE,
.prog_size = LFS_CACHE_SIZE,
.block_size = LFS_BLOCK_SIZE,
.block_count = LFS_FLASH_TOTAL_SIZE / LFS_BLOCK_SIZE,
.block_cycles =
500, // protection against wear leveling (suggested values between 100-1000)
.cache_size = LFS_CACHE_SIZE,
.lookahead_size = LFS_CACHE_SIZE,
.read_buffer = lfs_read_buffer,
.prog_buffer = lfs_prog_buffer,
.lookahead_buffer = lfs_lookahead_buffer};
InternalFileSystem InternalFS;
//--------------------------------------------------------------------+
//
//--------------------------------------------------------------------+
InternalFileSystem::InternalFileSystem(void) : LittleFS(&_InternalFSConfig) {}
bool InternalFileSystem::begin(void)
{
// failed to mount, erase all sector then format and mount again
if (!LittleFS::begin()) {
// Erase all sectors of internal flash region for Filesystem.
// implement as write 0xff to whole block address
for (uint32_t addr = LFS_FLASH_ADDR; addr < (LFS_FLASH_ADDR + LFS_FLASH_TOTAL_SIZE); addr++) {
EEPROM.update(addr, 0xff);
}
// lfs format
this->format();
// mount again if still failed, give up
if (!LittleFS::begin())
return false;
}
return true;
}

View File

@@ -1,54 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 hathach for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef INTERNALFILESYSTEM_H_
#define INTERNALFILESYSTEM_H_
#include "LittleFS.h"
// The EEPROM Library assumes our usable flash area starts at logical 0
#define LFS_FLASH_ADDR 0
// use the built in EEPROM emulation. Total Size is 2Kbyte
#define LFS_BLOCK_SIZE 128 // min. block size is 128 to fit CTZ pointers
#define LFS_CACHE_SIZE 16
#define LFS_FLASH_TOTAL_SIZE FLASH_PAGE_SIZE
static uint8_t lfs_read_buffer[LFS_CACHE_SIZE] = {0};
static uint8_t lfs_prog_buffer[LFS_CACHE_SIZE] = {0};
static uint8_t lfs_lookahead_buffer[LFS_CACHE_SIZE] = {0};
class InternalFileSystem : public LittleFS
{
public:
InternalFileSystem(void);
// overwrite to also perform low level format (sector erase of whole flash region)
bool begin(void);
};
extern InternalFileSystem InternalFS;
#endif /* INTERNALFILESYSTEM_H_ */

View File

@@ -1,258 +0,0 @@
#include <Arduino.h>
#include <string.h>
#include "LittleFS.h"
using namespace LittleFS_Namespace;
//--------------------------------------------------------------------+
// Implementation
//--------------------------------------------------------------------+
LittleFS::LittleFS(void) : LittleFS(NULL) {}
LittleFS::LittleFS(struct lfs_config *cfg)
{
memset(&_lfs, 0, sizeof(_lfs));
_lfs_cfg = cfg;
_mounted = false;
_mutex = xSemaphoreCreateMutexStatic(&this->_MutexStorageSpace);
}
LittleFS::~LittleFS() {}
// Initialize and mount the file system
// Return true if mounted successfully else probably corrupted.
// User should format the disk and try again
bool LittleFS::begin(struct lfs_config *cfg)
{
_lockFS();
bool ret;
// not a loop, just an quick way to short-circuit on error
do {
if (_mounted) {
ret = true;
break;
}
if (cfg) {
_lfs_cfg = cfg;
}
if (nullptr == _lfs_cfg) {
ret = false;
break;
}
// actually attempt to mount, and log error if one occurs
int err = lfs_mount(&_lfs, _lfs_cfg);
PRINT_LFS_ERR(err);
_mounted = (err == LFS_ERR_OK);
ret = _mounted;
} while (0);
_unlockFS();
return ret;
}
// Tear down and unmount file system
void LittleFS::end(void)
{
_lockFS();
if (_mounted) {
_mounted = false;
int err = lfs_unmount(&_lfs);
PRINT_LFS_ERR(err);
(void)err;
}
_unlockFS();
}
bool LittleFS::format(void)
{
_lockFS();
int err = LFS_ERR_OK;
bool attemptMount = _mounted;
// not a loop, just an quick way to short-circuit on error
do {
// if already mounted: umount first -> format -> remount
if (_mounted) {
_mounted = false;
err = lfs_unmount(&_lfs);
if (LFS_ERR_OK != err) {
PRINT_LFS_ERR(err);
break;
}
}
err = lfs_format(&_lfs, _lfs_cfg);
if (LFS_ERR_OK != err) {
PRINT_LFS_ERR(err);
break;
}
if (attemptMount) {
err = lfs_mount(&_lfs, _lfs_cfg);
if (LFS_ERR_OK != err) {
PRINT_LFS_ERR(err);
break;
}
_mounted = true;
}
// success!
} while (0);
_unlockFS();
return LFS_ERR_OK == err;
}
// Open a file or folder
LittleFS_Namespace::File LittleFS::open(char const *filepath, uint8_t mode)
{
// No lock is required here ... the File() object will synchronize with the mutex provided
return LittleFS_Namespace::File(filepath, mode, *this);
}
// Check if file or folder exists
bool LittleFS::exists(char const *filepath)
{
struct lfs_info info;
_lockFS();
bool ret = (0 == lfs_stat(&_lfs, filepath, &info));
_unlockFS();
return ret;
}
// Create a directory, create intermediate parent if needed
bool LittleFS::mkdir(char const *filepath)
{
bool ret = true;
const char *slash = filepath;
if (slash[0] == '/')
slash++; // skip root '/'
_lockFS();
// make intermediate parent directory(ies)
while (NULL != (slash = strchr(slash, '/'))) {
char parent[slash - filepath + 1] = {0};
memcpy(parent, filepath, slash - filepath);
int rc = lfs_mkdir(&_lfs, parent);
if (rc != LFS_ERR_OK && rc != LFS_ERR_EXIST) {
PRINT_LFS_ERR(rc);
ret = false;
break;
}
slash++;
}
// make the final requested directory
if (ret) {
int rc = lfs_mkdir(&_lfs, filepath);
if (rc != LFS_ERR_OK && rc != LFS_ERR_EXIST) {
PRINT_LFS_ERR(rc);
ret = false;
}
}
_unlockFS();
return ret;
}
// Remove a file
bool LittleFS::remove(char const *filepath)
{
_lockFS();
int err = lfs_remove(&_lfs, filepath);
PRINT_LFS_ERR(err);
_unlockFS();
return LFS_ERR_OK == err;
}
// Rename a file
bool LittleFS::rename(char const *oldfilepath, char const *newfilepath)
{
_lockFS();
int err = lfs_rename(&_lfs, oldfilepath, newfilepath);
PRINT_LFS_ERR(err);
_unlockFS();
return LFS_ERR_OK == err;
}
// Remove a folder
bool LittleFS::rmdir(char const *filepath)
{
_lockFS();
int err = lfs_remove(&_lfs, filepath);
PRINT_LFS_ERR(err);
_unlockFS();
return LFS_ERR_OK == err;
}
// Remove a folder recursively
bool LittleFS::rmdir_r(char const *filepath)
{
/* adafruit: lfs is modified to remove non-empty folder,
According to below issue, comment these 2 line won't corrupt filesystem
at least when using LFS v1. If moving to LFS v2, see tracked issue
to see if issues (such as the orphans in threaded linked list) are resolved.
https://github.com/ARMmbed/littlefs/issues/43
*/
_lockFS();
int err = lfs_remove(&_lfs, filepath);
PRINT_LFS_ERR(err);
_unlockFS();
return LFS_ERR_OK == err;
}
//------------- Debug -------------//
#if CFG_DEBUG
const char *dbg_strerr_lfs(int32_t err)
{
switch (err) {
case LFS_ERR_OK:
return "LFS_ERR_OK";
case LFS_ERR_IO:
return "LFS_ERR_IO";
case LFS_ERR_CORRUPT:
return "LFS_ERR_CORRUPT";
case LFS_ERR_NOENT:
return "LFS_ERR_NOENT";
case LFS_ERR_EXIST:
return "LFS_ERR_EXIST";
case LFS_ERR_NOTDIR:
return "LFS_ERR_NOTDIR";
case LFS_ERR_ISDIR:
return "LFS_ERR_ISDIR";
case LFS_ERR_NOTEMPTY:
return "LFS_ERR_NOTEMPTY";
case LFS_ERR_BADF:
return "LFS_ERR_BADF";
case LFS_ERR_INVAL:
return "LFS_ERR_INVAL";
case LFS_ERR_NOSPC:
return "LFS_ERR_NOSPC";
case LFS_ERR_NOMEM:
return "LFS_ERR_NOMEM";
default:
static char errcode[10];
sprintf(errcode, "%ld", err);
return errcode;
}
return NULL;
}
#endif

View File

@@ -1,85 +0,0 @@
#ifndef LITTLEFS_H_
#define LITTLEFS_H_
#include <Stream.h>
#include "lfs.h"
#include "LittleFS_File.h"
#include "FreeRTOS.h" // tied to FreeRTOS for serialization
#include "semphr.h"
class LittleFS
{
public:
LittleFS(void);
explicit LittleFS(struct lfs_config *cfg);
virtual ~LittleFS();
bool begin(struct lfs_config *cfg = NULL);
void end(void);
// Open the specified file/directory with the supplied mode (e.g. read or
// write, etc). Returns a File object for interacting with the file.
// Note that currently only one file can be open at a time.
LittleFS_Namespace::File open(char const *filename, uint8_t mode = LittleFS_Namespace::FILE_O_READ);
// Methods to determine if the requested file path exists.
bool exists(char const *filepath);
// Create the requested directory hierarchy--if intermediate directories
// do not exist they will be created.
bool mkdir(char const *filepath);
// Delete the file.
bool remove(char const *filepath);
// Rename the file.
bool rename(char const *oldfilepath, char const *newfilepath);
// Delete a folder (must be empty)
bool rmdir(char const *filepath);
// Delete a folder (recursively)
bool rmdir_r(char const *filepath);
// format file system
bool format(void);
/*------------------------------------------------------------------*/
/* INTERNAL USAGE ONLY
* Although declare as public, it is meant to be invoked by internal
* code. User should not call these directly
*------------------------------------------------------------------*/
lfs_t *_getFS(void) { return &_lfs; }
void _lockFS(void) { xSemaphoreTake(_mutex, portMAX_DELAY); }
void _unlockFS(void) { xSemaphoreGive(_mutex); }
protected:
bool _mounted;
struct lfs_config *_lfs_cfg;
lfs_t _lfs;
SemaphoreHandle_t _mutex;
private:
StaticSemaphore_t _MutexStorageSpace;
};
#if !CFG_DEBUG
#define VERIFY_LFS(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, NULL)
#define PRINT_LFS_ERR(_err)
#else
#define VERIFY_LFS(...) _GET_3RD_ARG(__VA_ARGS__, VERIFY_ERR_2ARGS, VERIFY_ERR_1ARGS)(__VA_ARGS__, dbg_strerr_lfs)
#define PRINT_LFS_ERR(_err) \
do { \
if (_err) { \
VERIFY_MESS((long int)_err, dbg_strerr_lfs); \
} \
} while (0) // LFS_ERR are of type int, VERIFY_MESS expects long_int
const char *dbg_strerr_lfs(int32_t err);
#endif
#endif /* LITTLEFS_H_ */

View File

@@ -1,362 +0,0 @@
#include <Arduino.h>
#include "LittleFS.h"
#include <lfs.h>
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
using namespace LittleFS_Namespace;
File::File(LittleFS &fs)
{
_fs = &fs;
_is_dir = false;
_name[0] = 0;
_dir_path = NULL;
_dir = NULL;
_file = NULL;
}
File::File(char const *filename, uint8_t mode, LittleFS &fs) : File(fs)
{
// public constructor calls public API open(), which will obtain the mutex
this->open(filename, mode);
}
bool File::_open_file(char const *filepath, uint8_t mode)
{
int flags = (mode == FILE_O_READ) ? LFS_O_RDONLY : (mode == FILE_O_WRITE) ? (LFS_O_RDWR | LFS_O_CREAT) : 0;
if (flags) {
_file = (lfs_file_t *)malloc(sizeof(lfs_file_t));
if (!_file)
return false;
int rc = lfs_file_open(_fs->_getFS(), _file, filepath, flags);
if (rc) {
// failed to open
PRINT_LFS_ERR(rc);
return false;
}
// move to end of file
if (mode == FILE_O_WRITE)
lfs_file_seek(_fs->_getFS(), _file, 0, LFS_SEEK_END);
_is_dir = false;
}
return true;
}
bool File::_open_dir(char const *filepath)
{
_dir = (lfs_dir_t *)malloc(sizeof(lfs_dir_t));
if (!_dir)
return false;
int rc = lfs_dir_open(_fs->_getFS(), _dir, filepath);
if (rc) {
// failed to open
PRINT_LFS_ERR(rc);
return false;
}
_is_dir = true;
_dir_path = (char *)malloc(strlen(filepath) + 1);
strcpy(_dir_path, filepath);
return true;
}
bool File::open(char const *filepath, uint8_t mode)
{
bool ret = false;
_fs->_lockFS();
ret = this->_open(filepath, mode);
_fs->_unlockFS();
return ret;
}
bool File::_open(char const *filepath, uint8_t mode)
{
bool ret = false;
// close if currently opened
if (this->isOpen())
_close();
struct lfs_info info;
int rc = lfs_stat(_fs->_getFS(), filepath, &info);
if (LFS_ERR_OK == rc) {
// file existed, open file or directory accordingly
ret = (info.type == LFS_TYPE_REG) ? _open_file(filepath, mode) : _open_dir(filepath);
} else if (LFS_ERR_NOENT == rc) {
// file not existed, only proceed with FILE_O_WRITE mode
if (mode == FILE_O_WRITE)
ret = _open_file(filepath, mode);
} else {
PRINT_LFS_ERR(rc);
}
// save bare file name
if (ret) {
char const *splash = strrchr(filepath, '/');
strncpy(_name, splash ? (splash + 1) : filepath, LFS_NAME_MAX);
}
return ret;
}
size_t File::write(uint8_t ch)
{
return write(&ch, 1);
}
size_t File::write(uint8_t const *buf, size_t size)
{
lfs_ssize_t wrcount = 0;
_fs->_lockFS();
if (!this->_is_dir) {
wrcount = lfs_file_write(_fs->_getFS(), _file, buf, size);
if (wrcount < 0) {
wrcount = 0;
}
}
_fs->_unlockFS();
return wrcount;
}
int File::read(void)
{
// this thin wrapper relies on called function to synchronize
int ret = -1;
uint8_t ch;
if (read(&ch, 1) > 0) {
ret = static_cast<int>(ch);
}
return ret;
}
int File::read(void *buf, uint16_t nbyte)
{
int ret = 0;
_fs->_lockFS();
if (!this->_is_dir) {
ret = lfs_file_read(_fs->_getFS(), _file, buf, nbyte);
}
_fs->_unlockFS();
return ret;
}
int File::peek(void)
{
int ret = -1;
_fs->_lockFS();
if (!this->_is_dir) {
uint32_t pos = lfs_file_tell(_fs->_getFS(), _file);
uint8_t ch = 0;
if (lfs_file_read(_fs->_getFS(), _file, &ch, 1) > 0) {
ret = static_cast<int>(ch);
}
(void)lfs_file_seek(_fs->_getFS(), _file, pos, LFS_SEEK_SET);
}
_fs->_unlockFS();
return ret;
}
int File::available(void)
{
int ret = 0;
_fs->_lockFS();
if (!this->_is_dir) {
uint32_t fsize = lfs_file_size(_fs->_getFS(), _file);
uint32_t pos = lfs_file_tell(_fs->_getFS(), _file);
ret = fsize - pos;
}
_fs->_unlockFS();
return ret;
}
bool File::seek(uint32_t pos)
{
bool ret = false;
_fs->_lockFS();
if (!this->_is_dir) {
ret = lfs_file_seek(_fs->_getFS(), _file, pos, LFS_SEEK_SET) >= 0;
}
_fs->_unlockFS();
return ret;
}
uint32_t File::position(void)
{
uint32_t ret = 0;
_fs->_lockFS();
if (!this->_is_dir) {
ret = lfs_file_tell(_fs->_getFS(), _file);
}
_fs->_unlockFS();
return ret;
}
uint32_t File::size(void)
{
uint32_t ret = 0;
_fs->_lockFS();
if (!this->_is_dir) {
ret = lfs_file_size(_fs->_getFS(), _file);
}
_fs->_unlockFS();
return ret;
}
bool File::truncate(uint32_t pos)
{
int32_t ret = LFS_ERR_ISDIR;
_fs->_lockFS();
if (!this->_is_dir) {
ret = lfs_file_truncate(_fs->_getFS(), _file, pos);
}
_fs->_unlockFS();
return (ret == 0);
}
bool File::truncate(void)
{
int32_t ret = LFS_ERR_ISDIR;
_fs->_lockFS();
if (!this->_is_dir) {
uint32_t pos = lfs_file_tell(_fs->_getFS(), _file);
ret = lfs_file_truncate(_fs->_getFS(), _file, pos);
}
_fs->_unlockFS();
return (ret == 0);
}
void File::flush(void)
{
_fs->_lockFS();
if (!this->_is_dir) {
lfs_file_sync(_fs->_getFS(), _file);
}
_fs->_unlockFS();
return;
}
void File::close(void)
{
_fs->_lockFS();
this->_close();
_fs->_unlockFS();
}
void File::_close(void)
{
if (this->isOpen()) {
if (this->_is_dir) {
lfs_dir_close(_fs->_getFS(), _dir);
free(_dir);
_dir = NULL;
if (this->_dir_path)
free(_dir_path);
_dir_path = NULL;
} else {
lfs_file_close(this->_fs->_getFS(), _file);
free(_file);
_file = NULL;
}
}
}
File::operator bool(void)
{
return isOpen();
}
bool File::isOpen(void)
{
return (_file != NULL) || (_dir != NULL);
}
// WARNING -- although marked as `const`, the values pointed
// to may change. For example, if the same File
// object has `open()` called with a different
// file or directory name, this same pointer will
// suddenly (unexpectedly?) have different values.
char const *File::name(void)
{
return this->_name;
}
bool File::isDirectory(void)
{
return this->_is_dir;
}
File File::openNextFile(uint8_t mode)
{
_fs->_lockFS();
File ret(*_fs);
if (this->_is_dir) {
struct lfs_info info;
int rc;
// lfs_dir_read returns 0 when reaching end of directory, 1 if found an entry
// Skip the "." and ".." entries ...
do {
rc = lfs_dir_read(_fs->_getFS(), _dir, &info);
} while (rc == 1 && (!strcmp(".", info.name) || !strcmp("..", info.name)));
if (rc == 1) {
// string cat name with current folder
char filepath[strlen(_dir_path) + 1 + strlen(info.name) + 1]; // potential for significant stack usage
strcpy(filepath, _dir_path);
if (!(_dir_path[0] == '/' && _dir_path[1] == 0))
strcat(filepath, "/"); // only add '/' if cwd is not root
strcat(filepath, info.name);
(void)ret._open(filepath, mode); // return value is ignored ... caller is expected to check isOpened()
} else if (rc < 0) {
PRINT_LFS_ERR(rc);
}
}
_fs->_unlockFS();
return ret;
}
void File::rewindDirectory(void)
{
_fs->_lockFS();
if (this->_is_dir) {
lfs_dir_rewind(_fs->_getFS(), _dir);
}
_fs->_unlockFS();
}

View File

@@ -1,82 +0,0 @@
#ifndef LITTLEFS_FILE_H_
#define LITTLEFS_FILE_H_
// Forward declaration
class LittleFS;
namespace LittleFS_Namespace
{
// avoid conflict with other FileSystem FILE_READ/FILE_WRITE
enum {
FILE_O_READ = 0,
FILE_O_WRITE = 1,
};
class File : public Stream
{
public:
explicit File(LittleFS &fs);
File(char const *filename, uint8_t mode, LittleFS &fs);
public:
bool open(char const *filename, uint8_t mode);
//------------- Stream API -------------//
virtual size_t write(uint8_t ch);
virtual size_t write(uint8_t const *buf, size_t size);
size_t write(const char *str)
{
if (str == NULL)
return 0;
return write((const uint8_t *)str, strlen(str));
}
size_t write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); }
virtual int read(void);
int read(void *buf, uint16_t nbyte);
virtual int peek(void);
virtual int available(void);
virtual void flush(void);
bool seek(uint32_t pos);
uint32_t position(void);
uint32_t size(void);
bool truncate(uint32_t pos);
bool truncate(void);
void close(void);
operator bool(void);
bool isOpen(void);
char const *name(void);
bool isDirectory(void);
File openNextFile(uint8_t mode = FILE_O_READ);
void rewindDirectory(void);
private:
LittleFS *_fs;
bool _is_dir;
union {
lfs_file_t *_file;
lfs_dir_t *_dir;
};
char *_dir_path;
char _name[LFS_NAME_MAX + 1];
bool _open(char const *filepath, uint8_t mode);
bool _open_file(char const *filepath, uint8_t mode);
bool _open_dir(char const *filepath);
void _close(void);
};
} // namespace LittleFS_Namespace
#endif /* LITTLEFS_FILE_H_ */

View File

@@ -1,33 +1,64 @@
#undef RNG
#include "AES.h"
#include "CTR.h"
#include "CryptoEngine.h"
#include "aes.hpp"
#include "configuration.h"
class STM32WLCryptoEngine : public CryptoEngine
{
CTRCommon *ctr = NULL;
public:
STM32WLCryptoEngine() {}
~STM32WLCryptoEngine() {}
virtual void setKey(const CryptoKey &k) override
{
CryptoEngine::setKey(k);
LOG_DEBUG("Installing AES%d key!\n", key.length * 8);
if (ctr) {
delete ctr;
ctr = NULL;
}
if (key.length != 0) {
if (key.length == 16)
ctr = new CTR<AES128>();
else
ctr = new CTR<AES256>();
ctr->setKey(key.bytes, key.length);
}
}
/**
* Encrypt a packet
*
* @param bytes is updated in place
*/
virtual void encrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
virtual void encrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override
{
if (key.length > 0) {
AES_ctx ctx;
initNonce(fromNode, packetNum);
AES_init_ctx_iv(&ctx, key.bytes, nonce);
AES_CTR_xcrypt_buffer(&ctx, bytes, numBytes);
initNonce(fromNode, packetId);
if (numBytes <= MAX_BLOCKSIZE) {
static uint8_t scratch[MAX_BLOCKSIZE];
memcpy(scratch, bytes, numBytes);
memset(scratch + numBytes, 0,
sizeof(scratch) - numBytes); // Fill rest of buffer with zero (in case cypher looks at it)
ctr->setIV(nonce, sizeof(nonce));
ctr->setCounterSize(4);
ctr->encrypt(bytes, scratch, numBytes);
} else {
LOG_ERROR("Packet too large for crypto engine: %d. noop encryption!\n", numBytes);
}
}
}
virtual void decrypt(uint32_t fromNode, uint64_t packetNum, size_t numBytes, uint8_t *bytes) override
virtual void decrypt(uint32_t fromNode, uint64_t packetId, size_t numBytes, uint8_t *bytes) override
{
// For CTR, the implementation is the same
encrypt(fromNode, packetNum, numBytes, bytes);
encrypt(fromNode, packetId, numBytes, bytes);
}
private:

View File

@@ -26,11 +26,3 @@ void getMacAddr(uint8_t *dmac)
}
void cpuDeepSleep(uint32_t msecToWake) {}
/* pacify libc_nano */
extern "C" {
int _gettimeofday(struct timeval *tv, void *tzvp)
{
return -1;
}
}

View File

@@ -0,0 +1,317 @@
#include "MeshPacketSerializer.h"
#include "JSON.h"
#include "NodeDB.h"
#include "mesh/generated/meshtastic/mqtt.pb.h"
#include "mesh/generated/meshtastic/telemetry.pb.h"
#include "modules/RoutingModule.h"
#include <DebugConfiguration.h>
#include <mesh-pb-constants.h>
#if defined(ARCH_ESP32)
#include "../mesh/generated/meshtastic/paxcount.pb.h"
#endif
#include "mesh/generated/meshtastic/remote_hardware.pb.h"
std::string MeshPacketSerializer::JsonSerialize(meshtastic_MeshPacket *mp, bool shouldLog)
{
// the created jsonObj is immutable after creation, so
// we need to do the heavy lifting before assembling it.
std::string msgType;
JSONObject jsonObj;
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
JSONObject msgPayload;
switch (mp->decoded.portnum) {
case meshtastic_PortNum_TEXT_MESSAGE_APP: {
msgType = "text";
// convert bytes to string
if (shouldLog)
LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size);
char payloadStr[(mp->decoded.payload.size) + 1];
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
// check if this is a JSON payload
JSONValue *json_value = JSON::Parse(payloadStr);
if (json_value != NULL) {
if (shouldLog)
LOG_INFO("text message payload is of type json\n");
// if it is, then we can just use the json object
jsonObj["payload"] = json_value;
} else {
// if it isn't, then we need to create a json object
// with the string as the value
if (shouldLog)
LOG_INFO("text message payload is of type plaintext\n");
msgPayload["text"] = new JSONValue(payloadStr);
jsonObj["payload"] = new JSONValue(msgPayload);
}
break;
}
case meshtastic_PortNum_TELEMETRY_APP: {
msgType = "telemetry";
meshtastic_Telemetry scratch;
meshtastic_Telemetry *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
decoded = &scratch;
if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) {
msgPayload["battery_level"] = new JSONValue((unsigned int)decoded->variant.device_metrics.battery_level);
msgPayload["voltage"] = new JSONValue(decoded->variant.device_metrics.voltage);
msgPayload["channel_utilization"] = new JSONValue(decoded->variant.device_metrics.channel_utilization);
msgPayload["air_util_tx"] = new JSONValue(decoded->variant.device_metrics.air_util_tx);
msgPayload["uptime_seconds"] = new JSONValue((unsigned int)decoded->variant.device_metrics.uptime_seconds);
} else if (decoded->which_variant == meshtastic_Telemetry_environment_metrics_tag) {
msgPayload["temperature"] = new JSONValue(decoded->variant.environment_metrics.temperature);
msgPayload["relative_humidity"] = new JSONValue(decoded->variant.environment_metrics.relative_humidity);
msgPayload["barometric_pressure"] = new JSONValue(decoded->variant.environment_metrics.barometric_pressure);
msgPayload["gas_resistance"] = new JSONValue(decoded->variant.environment_metrics.gas_resistance);
msgPayload["voltage"] = new JSONValue(decoded->variant.environment_metrics.voltage);
msgPayload["current"] = new JSONValue(decoded->variant.environment_metrics.current);
msgPayload["lux"] = new JSONValue(decoded->variant.environment_metrics.lux);
msgPayload["white_lux"] = new JSONValue(decoded->variant.environment_metrics.white_lux);
msgPayload["iaq"] = new JSONValue((uint)decoded->variant.environment_metrics.iaq);
msgPayload["wind_speed"] = new JSONValue(decoded->variant.environment_metrics.wind_speed);
msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction);
msgPayload["wind_gust"] = new JSONValue(decoded->variant.environment_metrics.wind_gust);
msgPayload["wind_lull"] = new JSONValue(decoded->variant.environment_metrics.wind_lull);
} else if (decoded->which_variant == meshtastic_Telemetry_power_metrics_tag) {
msgPayload["voltage_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_voltage);
msgPayload["current_ch1"] = new JSONValue(decoded->variant.power_metrics.ch1_current);
msgPayload["voltage_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_voltage);
msgPayload["current_ch2"] = new JSONValue(decoded->variant.power_metrics.ch2_current);
msgPayload["voltage_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_voltage);
msgPayload["current_ch3"] = new JSONValue(decoded->variant.power_metrics.ch3_current);
}
jsonObj["payload"] = new JSONValue(msgPayload);
} else if (shouldLog) {
LOG_ERROR("Error decoding protobuf for telemetry message!\n");
}
break;
}
case meshtastic_PortNum_NODEINFO_APP: {
msgType = "nodeinfo";
meshtastic_User scratch;
meshtastic_User *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) {
decoded = &scratch;
msgPayload["id"] = new JSONValue(decoded->id);
msgPayload["longname"] = new JSONValue(decoded->long_name);
msgPayload["shortname"] = new JSONValue(decoded->short_name);
msgPayload["hardware"] = new JSONValue(decoded->hw_model);
msgPayload["role"] = new JSONValue((int)decoded->role);
jsonObj["payload"] = new JSONValue(msgPayload);
} else if (shouldLog) {
LOG_ERROR("Error decoding protobuf for nodeinfo message!\n");
}
break;
}
case meshtastic_PortNum_POSITION_APP: {
msgType = "position";
meshtastic_Position scratch;
meshtastic_Position *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) {
decoded = &scratch;
if ((int)decoded->time) {
msgPayload["time"] = new JSONValue((unsigned int)decoded->time);
}
if ((int)decoded->timestamp) {
msgPayload["timestamp"] = new JSONValue((unsigned int)decoded->timestamp);
}
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
if ((int)decoded->altitude) {
msgPayload["altitude"] = new JSONValue((int)decoded->altitude);
}
if ((int)decoded->ground_speed) {
msgPayload["ground_speed"] = new JSONValue((unsigned int)decoded->ground_speed);
}
if (int(decoded->ground_track)) {
msgPayload["ground_track"] = new JSONValue((unsigned int)decoded->ground_track);
}
if (int(decoded->sats_in_view)) {
msgPayload["sats_in_view"] = new JSONValue((unsigned int)decoded->sats_in_view);
}
if ((int)decoded->PDOP) {
msgPayload["PDOP"] = new JSONValue((int)decoded->PDOP);
}
if ((int)decoded->HDOP) {
msgPayload["HDOP"] = new JSONValue((int)decoded->HDOP);
}
if ((int)decoded->VDOP) {
msgPayload["VDOP"] = new JSONValue((int)decoded->VDOP);
}
if ((int)decoded->precision_bits) {
msgPayload["precision_bits"] = new JSONValue((int)decoded->precision_bits);
}
jsonObj["payload"] = new JSONValue(msgPayload);
} else if (shouldLog) {
LOG_ERROR("Error decoding protobuf for position message!\n");
}
break;
}
case meshtastic_PortNum_WAYPOINT_APP: {
msgType = "position";
meshtastic_Waypoint scratch;
meshtastic_Waypoint *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
decoded = &scratch;
msgPayload["id"] = new JSONValue((unsigned int)decoded->id);
msgPayload["name"] = new JSONValue(decoded->name);
msgPayload["description"] = new JSONValue(decoded->description);
msgPayload["expire"] = new JSONValue((unsigned int)decoded->expire);
msgPayload["locked_to"] = new JSONValue((unsigned int)decoded->locked_to);
msgPayload["latitude_i"] = new JSONValue((int)decoded->latitude_i);
msgPayload["longitude_i"] = new JSONValue((int)decoded->longitude_i);
jsonObj["payload"] = new JSONValue(msgPayload);
} else if (shouldLog) {
LOG_ERROR("Error decoding protobuf for position message!\n");
}
break;
}
case meshtastic_PortNum_NEIGHBORINFO_APP: {
msgType = "neighborinfo";
meshtastic_NeighborInfo scratch;
meshtastic_NeighborInfo *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg,
&scratch)) {
decoded = &scratch;
msgPayload["node_id"] = new JSONValue((unsigned int)decoded->node_id);
msgPayload["node_broadcast_interval_secs"] = new JSONValue((unsigned int)decoded->node_broadcast_interval_secs);
msgPayload["last_sent_by_id"] = new JSONValue((unsigned int)decoded->last_sent_by_id);
msgPayload["neighbors_count"] = new JSONValue(decoded->neighbors_count);
JSONArray neighbors;
for (uint8_t i = 0; i < decoded->neighbors_count; i++) {
JSONObject neighborObj;
neighborObj["node_id"] = new JSONValue((unsigned int)decoded->neighbors[i].node_id);
neighborObj["snr"] = new JSONValue((int)decoded->neighbors[i].snr);
neighbors.push_back(new JSONValue(neighborObj));
}
msgPayload["neighbors"] = new JSONValue(neighbors);
jsonObj["payload"] = new JSONValue(msgPayload);
} else if (shouldLog) {
LOG_ERROR("Error decoding protobuf for neighborinfo message!\n");
}
break;
}
case meshtastic_PortNum_TRACEROUTE_APP: {
if (mp->decoded.request_id) { // Only report the traceroute response
msgType = "traceroute";
meshtastic_RouteDiscovery scratch;
meshtastic_RouteDiscovery *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_RouteDiscovery_msg,
&scratch)) {
decoded = &scratch;
JSONArray route; // Route this message took
// Lambda function for adding a long name to the route
auto addToRoute = [](JSONArray *route, NodeNum num) {
char long_name[40] = "Unknown";
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(num);
bool name_known = node ? node->has_user : false;
if (name_known)
memcpy(long_name, node->user.long_name, sizeof(long_name));
route->push_back(new JSONValue(long_name));
};
addToRoute(&route, mp->to); // Started at the original transmitter (destination of response)
for (uint8_t i = 0; i < decoded->route_count; i++) {
addToRoute(&route, decoded->route[i]);
}
addToRoute(&route, mp->from); // Ended at the original destination (source of response)
msgPayload["route"] = new JSONValue(route);
jsonObj["payload"] = new JSONValue(msgPayload);
} else if (shouldLog) {
LOG_ERROR("Error decoding protobuf for traceroute message!\n");
}
}
break;
}
case meshtastic_PortNum_DETECTION_SENSOR_APP: {
msgType = "detection";
char payloadStr[(mp->decoded.payload.size) + 1];
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
payloadStr[mp->decoded.payload.size] = 0; // null terminated string
msgPayload["text"] = new JSONValue(payloadStr);
jsonObj["payload"] = new JSONValue(msgPayload);
break;
}
#ifdef ARCH_ESP32
case meshtastic_PortNum_PAXCOUNTER_APP: {
msgType = "paxcounter";
meshtastic_Paxcount scratch;
meshtastic_Paxcount *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Paxcount_msg, &scratch)) {
decoded = &scratch;
msgPayload["wifi_count"] = new JSONValue((unsigned int)decoded->wifi);
msgPayload["ble_count"] = new JSONValue((unsigned int)decoded->ble);
msgPayload["uptime"] = new JSONValue((unsigned int)decoded->uptime);
jsonObj["payload"] = new JSONValue(msgPayload);
} else if (shouldLog) {
LOG_ERROR("Error decoding protobuf for Paxcount message!\n");
}
break;
}
#endif
case meshtastic_PortNum_REMOTE_HARDWARE_APP: {
meshtastic_HardwareMessage scratch;
meshtastic_HardwareMessage *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_HardwareMessage_msg,
&scratch)) {
decoded = &scratch;
if (decoded->type == meshtastic_HardwareMessage_Type_GPIOS_CHANGED) {
msgType = "gpios_changed";
msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value);
jsonObj["payload"] = new JSONValue(msgPayload);
} else if (decoded->type == meshtastic_HardwareMessage_Type_READ_GPIOS_REPLY) {
msgType = "gpios_read_reply";
msgPayload["gpio_value"] = new JSONValue((unsigned int)decoded->gpio_value);
msgPayload["gpio_mask"] = new JSONValue((unsigned int)decoded->gpio_mask);
jsonObj["payload"] = new JSONValue(msgPayload);
}
} else if (shouldLog) {
LOG_ERROR("Error decoding protobuf for RemoteHardware message!\n");
}
break;
}
// add more packet types here if needed
default:
break;
}
} else if (shouldLog) {
LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON\n");
}
jsonObj["id"] = new JSONValue((unsigned int)mp->id);
jsonObj["timestamp"] = new JSONValue((unsigned int)mp->rx_time);
jsonObj["to"] = new JSONValue((unsigned int)mp->to);
jsonObj["from"] = new JSONValue((unsigned int)mp->from);
jsonObj["channel"] = new JSONValue((unsigned int)mp->channel);
jsonObj["type"] = new JSONValue(msgType.c_str());
jsonObj["sender"] = new JSONValue(owner.id);
if (mp->rx_rssi != 0)
jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
if (mp->rx_snr != 0)
jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
if (mp->hop_start != 0 && mp->hop_limit <= mp->hop_start) {
jsonObj["hops_away"] = new JSONValue((unsigned int)(mp->hop_start - mp->hop_limit));
jsonObj["hop_start"] = new JSONValue((unsigned int)(mp->hop_start));
}
// serialize and write it to the stream
JSONValue *value = new JSONValue(jsonObj);
std::string jsonStr = value->Stringify();
if (shouldLog)
LOG_INFO("serialized json message: %s\n", jsonStr.c_str());
delete value;
return jsonStr;
}

View File

@@ -0,0 +1,8 @@
#include <meshtastic/mesh.pb.h>
#include <string>
class MeshPacketSerializer
{
public:
static std::string JsonSerialize(meshtastic_MeshPacket *mp, bool shouldLog = true);
};

View File

@@ -237,6 +237,25 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
#ifdef PIN_POWER_EN
pinMode(PIN_POWER_EN, INPUT); // power off peripherals
// pinMode(PIN_POWER_EN1, INPUT_PULLDOWN);
#endif
#ifdef TRACKER_T1000_E
#ifdef GNSS_AIROHA
digitalWrite(GPS_VRTC_EN, LOW);
digitalWrite(PIN_GPS_RESET, LOW);
digitalWrite(GPS_SLEEP_INT, LOW);
digitalWrite(GPS_RTC_INT, LOW);
pinMode(GPS_RESETB_OUT, OUTPUT);
digitalWrite(GPS_RESETB_OUT, LOW);
#endif
#ifdef BUZZER_EN_PIN
digitalWrite(BUZZER_EN_PIN, LOW);
#endif
#ifdef PIN_3V3_EN
digitalWrite(PIN_3V3_EN, LOW);
#endif
#endif
setLed(false);

View File

@@ -50,6 +50,8 @@
#include "xmodem.h"
#ifdef FSCom
XModemAdapter xModem;
XModemAdapter::XModemAdapter() {}
@@ -249,3 +251,4 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
break;
}
}
#endif

View File

@@ -38,6 +38,8 @@
#define MAXRETRANS 25
#ifdef FSCom
class XModemAdapter
{
public:
@@ -75,3 +77,4 @@ class XModemAdapter
};
extern XModemAdapter xModem;
#endif // FSCom

View File

@@ -0,0 +1,12 @@
[env:rak3172]
extends = stm32_base
board_level = extra
board = wiscore_rak3172
build_flags =
${stm32_base.build_flags}
-Ivariants/rak3172
-DHAL_DAC_MODULE_ONLY
-DSERIAL_UART_INSTANCE=1
-DPIN_SERIAL_RX=PB7
-DPIN_SERIAL_TX=PB6
upload_port = stlink

View File

@@ -0,0 +1,12 @@
/*
This variant is a work in progress.
Do not expect a working Meshtastic device with this target.
*/
#ifndef _VARIANT_RAK3172_
#define _VARIANT_RAK3172_
#define USE_STM32WLx
#define MAX_NUM_NODES 10
#endif

View File

@@ -0,0 +1,16 @@
; tracker-t1000-e v0.9.1
[env:tracker-t1000-e]
extends = nrf52840_base
board = tracker-t1000-e
; board_level = extra
; platform = https://github.com/maxgerhardt/platform-nordicnrf52#cac6fcf943a41accd2aeb4f3659ae297a73f422e
build_flags = ${nrf52840_base.build_flags} -Ivariants/tracker-t1000-e -Isrc/platform/nrf52/softdevice -Isrc/platform/nrf52/softdevice/nrf52 -DTRACKER_T1000_E -DRADIOLIB_GODMODE
-L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard"
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
board_build.ldscript = src/platform/nrf52/nrf52840_s140_v7.ld
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/tracker-t1000-e>
lib_deps =
${nrf52840_base.lib_deps}
debug_tool = jlink
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
upload_protocol = nrfutil

View File

@@ -0,0 +1,64 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "variant.h"
#include "nrf.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
const uint32_t g_ADigitalPinMap[] = {
// P0
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
// P1
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
void initVariant()
{
// LED1 & LED2
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
pinMode(PIN_3V3_EN, OUTPUT);
digitalWrite(PIN_3V3_EN, HIGH);
pinMode(PIN_3V3_ACC_EN, OUTPUT);
digitalWrite(PIN_3V3_ACC_EN, LOW);
pinMode(BUZZER_EN_PIN, OUTPUT);
digitalWrite(BUZZER_EN_PIN, HIGH);
pinMode(PIN_GPS_EN, OUTPUT);
digitalWrite(PIN_GPS_EN, LOW);
pinMode(GPS_VRTC_EN, OUTPUT);
digitalWrite(GPS_VRTC_EN, HIGH);
pinMode(PIN_GPS_RESET, OUTPUT);
digitalWrite(PIN_GPS_RESET, LOW);
pinMode(GPS_SLEEP_INT, OUTPUT);
digitalWrite(GPS_SLEEP_INT, HIGH);
pinMode(GPS_RTC_INT, OUTPUT);
digitalWrite(GPS_RTC_INT, LOW);
pinMode(GPS_RESETB_OUT, INPUT);
}

View File

@@ -0,0 +1,150 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _VARIANT_TRACKER_T1000_E_
#define _VARIANT_TRACKER_T1000_E_
/** Master clock frequency */
#define VARIANT_MCK (64000000ul)
#define USE_LFXO // Board uses 32khz crystal for LF
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "WVariant.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// Number of pins defined in PinDescription array
#define PINS_COUNT (48)
#define NUM_DIGITAL_PINS (48)
#define NUM_ANALOG_INPUTS (6)
#define NUM_ANALOG_OUTPUTS (0)
#define PIN_3V3_EN (32 + 6) // P1.6, Power to Sensors
#define PIN_3V3_ACC_EN (32 + 7) // P1.7, Power to Acc
#define PIN_LED1 (0 + 24) // P0.24
#define LED_PIN PIN_LED1
#define LED_BUILTIN -1
#define LED_BLUE -1 // Actually green
#define LED_STATE_ON 1 // State when LED is lit
#define BUTTON_PIN (0 + 6) // P0.6
#define BUTTON_ACTIVE_LOW false
#define BUTTON_ACTIVE_PULLUP false
#define BUTTON_SENSE_TYPE 0x6
#define HAS_WIRE 1
#define WIRE_INTERFACES_COUNT 1
// unused pins
#define PIN_WIRE_SDA (0 + 9) // P0.26
#define PIN_WIRE_SCL (0 + 10) // P0.27
/*
* Serial interfaces
*/
#define PIN_SERIAL1_RX (0 + 14) // P0.14
#define PIN_SERIAL1_TX (0 + 13) // P0.13
#define PIN_SERIAL2_RX (0 + 17) // P0.17
#define PIN_SERIAL2_TX (0 + 16) // P0.16
#define SPI_INTERFACES_COUNT 1
#define PIN_SPI_MISO (32 + 8) // P1.08
#define PIN_SPI_MOSI (32 + 9) // P1.09
#define PIN_SPI_SCK (0 + 11) // P0.11
#define PIN_SPI_NSS (0 + 12) // P0.12
#define LORA_RESET (32 + 10) // P1.10 // RST
#define LORA_DIO1 (32 + 1) // P1.01 // IRQ
#define LORA_DIO2 (0 + 7) // P0.07 // BUSY
#define LORA_SCK PIN_SPI_SCK
#define LORA_MISO PIN_SPI_MISO
#define LORA_MOSI PIN_SPI_MOSI
#define LORA_CS PIN_SPI_NSS
// supported modules list
#define USE_LR1110
#define LR1110_IRQ_PIN LORA_DIO1
#define LR1110_NRESER_PIN LORA_RESET
#define LR1110_BUSY_PIN LORA_DIO2
#define LR1110_SPI_NSS_PIN LORA_CS
#define LR1110_SPI_SCK_PIN LORA_SCK
#define LR1110_SPI_MOSI_PIN LORA_MOSI
#define LR1110_SPI_MISO_PIN LORA_MISO
#define LR11X0_DIO3_TCXO_VOLTAGE 1.6
#define LR11X0_DIO_AS_RF_SWITCH
#define LR11X0_DIO_RF_SWITCH_CONFIG 0x0f, 0x0, 0x09, 0x0B, 0x0A, 0x0, 0x4, 0x0
#define HAS_GPS 1
#define GNSS_AIROHA
#define GPS_RX_PIN PIN_SERIAL1_RX
#define GPS_TX_PIN PIN_SERIAL1_TX
#define GPS_BAUDRATE 115200
#define PIN_GPS_EN (32 + 11) // P1.11
#define GPS_EN_ACTIVE HIGH
#define PIN_GPS_RESET (32 + 15) // P1.15
#define GPS_RESET_MODE HIGH
#define GPS_VRTC_EN (0 + 8) // P0.8, awlays high
#define GPS_SLEEP_INT (32 + 12) // P1.12, awlays high
#define GPS_RTC_INT (0 + 15) // P0.15, normal is LOW, wake by HIGH
#define GPS_RESETB_OUT (32 + 14) // P1.14, awlays input pull_up
#define GPS_FIX_HOLD_TIME 15000 // ms
#define BATTERY_PIN 2
#define ADC_MULTIPLIER (2.0F)
#define ADC_RESOLUTION 14
#define BATTERY_SENSE_RESOLUTION_BITS 12
#undef AREF_VOLTAGE
#define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
// Buzzer
#define BUZZER_EN_PIN (32 + 5) // P1.05, awlays high
#define PIN_BUZZER (0 + 25) // P0.25, pwm output
#define T1000X_SENSOR_EN
#define T1000X_VCC_PIN (0 + 4) // P0.4
#define T1000X_NTC_PIN (0 + 31) // P0.31
#define T1000X_LUX_PIN (0 + 29) // P0.29
#ifdef __cplusplus
}
#endif
/*----------------------------------------------------------------------------
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
#endif // _VARIANT_TRACKER_T1000_E_

View File

@@ -1,11 +1,34 @@
[env:wio-e5]
extends = stm32wl5e_base
extends = stm32_base
board_level = extra
board = lora_e5_dev_board
build_flags =
${stm32wl5e_base.build_flags}
${stm32_base.build_flags}
-Ivariants/wio-e5
-DHAL_DAC_MODULE_ONLY
-DSERIAL_UART_INSTANCE=1
-DPIN_SERIAL_RX=PB7
-DPIN_SERIAL_TX=PB6
-DHAL_DAC_MODULE_ONLY
-DHAL_ADC_MODULE_DISABLED
-DHAL_COMP_MODULE_DISABLED
-DHAL_CRC_MODULE_DISABLED
-DHAL_CRYP_MODULE_DISABLED
-DHAL_GTZC_MODULE_DISABLED
-DHAL_HSEM_MODULE_DISABLED
-DHAL_I2C_MODULE_DISABLED
-DHAL_I2S_MODULE_DISABLED
-DHAL_IPCC_MODULE_DISABLED
-DHAL_IRDA_MODULE_DISABLED
-DHAL_IWDG_MODULE_DISABLED
-DHAL_LPTIM_MODULE_DISABLED
-DHAL_PKA_MODULE_DISABLED
-DHAL_RNG_MODULE_DISABLED
-DHAL_RTC_MODULE_DISABLED
-DHAL_SMARTCARD_MODULE_DISABLED
-DHAL_SMBUS_MODULE_DISABLED
-DHAL_TIM_MODULE_DISABLED
-DHAL_WWDG_MODULE_DISABLED
-DHAL_EXTI_MODULE_DISABLED
; -D PIO_FRAMEWORK_ARDUINO_NANOLIB_FLOAT_PRINTF
upload_port = stlink

View File

@@ -13,5 +13,6 @@ Do not expect a working Meshtastic device with this target.
#define _VARIANT_WIOE5_
#define USE_STM32WLx
#define MAX_NUM_NODES 10
#endif

View File

@@ -106,7 +106,7 @@ extern "C" {
#define LR11X0_DIO_RF_SWITCH_CONFIG 0x0f, 0x0, 0x09, 0x0B, 0x0A, 0x0, 0x4, 0x0
#define HAS_GPS 1
#define GNSS_Airoha
#define GNSS_AIROHA
#define GPS_RX_PIN PIN_SERIAL1_RX
#define GPS_TX_PIN PIN_SERIAL1_TX