Compare commits

...

23 Commits

Author SHA1 Message Date
Ben Meadors
7f7c5cbd62 Triple GPS state (#3157)
* Triple state GPS refactoring

* Skip probe

* Move GPS toggle into the GPSThread

* Consolidate

* make all happy (including me)

* corrected screen texts

* NOT_PRESENT guard in main.cpp

---------

Co-authored-by: mverch67 <manuel.verch@gmx.de>
2024-02-01 15:24:39 -06:00
GUVWAF
0c0a3c4b55 Fix: mark packet sent to MQTT as ACKed only after we sent it out via LoRa (#3155)
* Fix: mark packet via MQTT as ACKed only after we sent it out via LoRa

* Don't need to check for broadcast, DMs also get implicit ACKs

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-31 14:04:52 -06:00
github-actions[bot]
bf762bc58d [create-pull-request] automated change (#3156)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-31 13:47:17 -06:00
Ben Meadors
84e578323e Update version.properties 2024-01-31 13:46:48 -06:00
Ben Meadors
bdbe42dfd0 Update version.properties 2024-01-31 12:58:04 -06:00
github-actions[bot]
4f64c4f7b9 [create-pull-request] automated change (#3154)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-30 20:01:00 -06:00
Jonathan Bennett
af5ac32048 Re-order GPS check to eliminate TOO old message (#3152) 2024-01-30 17:44:08 -06:00
Ken McGuire
9586c68c65 GPS updates (#3142)
* Portduino multiple logging levels

* Fixes based on GPSFan work

* Fix derped logic

* Correct size field for AID message

* Reformat to add comments, beginning of GPS rework

* Update PM2 message for Neo-6

* Correct ECO mode logic as ECO mode is only for Neo-6

* Cleanup ubx.h add a few more comments

---------

Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-30 17:38:31 -06:00
Artem
ca45888f3e feat(variants): Add support for TXCO on TLORA_V2_1_6 devices (#3124)
* feat(variants): Add support for TXCO on TLORA_V2_1_6 devices

* chore: remove long comment

* feat(variants): Add tlora-v2-1-1_6-tcxo to build matrix

* feat(variants): Use RADIOLIB_NC as DIO1 pin for tlora_v2_1_16 with TXCO

* Use generic naming scheme, add variant to build envs

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: code8buster <20384924+code8buster@users.noreply.github.com>
2024-01-30 07:06:47 -06:00
Andre K
1e4ecea6fc update to Meshtastic_nRF52_factory_erase_v2 (#3146) 2024-01-29 20:07:09 -06:00
code8buster
d1ea589757 Allow NRF52 ADC overrides; begin simplifying analog battery logic (#3134)
* Isolate esp32 adc logic gymnastics, try simplifying getBattVoltage

* Set sense resolution for pico platforms

* try silencing cppcheck when variant has no battery pin

* ADC channel for esp-idf calibration

* Missed an rp2040 device

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-29 06:14:21 -06:00
GUVWAF
af52dcecdf Restrict MQTT JSON downlink messages (#3141)
Channel needs to be named "mqtt"
"from" field should be set to the node number of the transmitter

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-29 06:13:56 -06:00
Ben Meadors
0ae4622393 Admin message to delete file (#3144)
* Protos

* Delete file admin message
2024-01-29 06:10:48 -06:00
Jonathan Bennett
a49740cd56 Adds i2c device configuration to native (#3143) 2024-01-28 20:15:29 -06:00
GUVWAF
417feee47f Fix: return failure when PhoneAPI times out (#3136)
* Add debug options for RP2040

* Rename: "observed" should be plural: "observables"

* PhoneAPI: return failure on timeout
In `onNotify()`, when disconnected, PhoneAPI removed itself from the list of observers that was looped through in `notifyObservers()`. We should exit that loop in that case.
2024-01-28 07:53:39 -06:00
Jonathan Bennett
d604a76c73 Use correct define for native gos (#3133) 2024-01-26 09:06:15 -06:00
Ken McGuire
ac9c5f81b9 Add CircutMess Chatter 2 (#3125)
* Add Chatter 2 default_envs

* Add Chatter 2 to varients

* Add Chatter 2 specific code to esp32 platform code

* Parameterize TFT_INVERT for Chatter 2 and specify setRotation to 1

* Fix formatting to make Trunk happy

* Remove commented out #define USE_LCC68

* Fix formatting again

* Add chatter2 to the CI matrix

---------

Co-authored-by: code8buster <20384924+code8buster@users.noreply.github.com>
2024-01-26 08:40:16 -06:00
Andre K
d6fa190025 fix: allow MQTT encryption_enabled with json_enabled (#3126)
* fix: allow MQTT `encryption_enabled` with `json_enabled`

* fix: copy decoded MeshPacket and release memory after use

* fix: use `packetPool` allocCopy and release methods

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-01-25 08:42:34 -06:00
Manuel
f2c04c5504 fix MQTT crash (#3127) 2024-01-24 14:01:50 -06:00
Jonathan Bennett
4ae5443c3b Don't ever delete own node from DB (#3122) 2024-01-22 20:13:27 -06:00
Jonathan Bennett
6b5101ec67 Portduino logging enhancements (#3121)
* Portduino logging enhancements

* Extra debugging for SPI device
2024-01-22 01:27:06 -06:00
Jonathan Bennett
062c646814 TinyGPS fix for empty terms (#3120) 2024-01-21 19:13:54 -06:00
github-actions[bot]
bccc0d47eb [create-pull-request] automated change (#3119)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-01-20 19:11:21 -06:00
58 changed files with 687 additions and 343 deletions

View File

@@ -64,6 +64,7 @@ jobs:
- board: tlora-v1
- board: tlora_v1_3
- board: tlora-v2-1-1_6
- board: tlora-v2-1-1_6-tcxo
- board: tlora-v2-1-1_8
- board: tbeam
- board: heltec-ht62-esp32c3-sx1262
@@ -79,6 +80,7 @@ jobs:
- board: m5stack-core
- board: m5stack-coreink
- board: nano-g1-explorer
- board: chatter2
uses: ./.github/workflows/build_esp32.yml
with:
board: ${{ matrix.board }}
@@ -245,7 +247,7 @@ jobs:
id: version
- name: Move files up
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat ./firmware-raspbian-*/release/meshtasticd_linux_aarch64 ./firmware-raspbian-*/bin/config-dist.yaml
run: mv -b -t ./ ./*tbeam-2*/littlefs*.bin ./*tbeam-2*/bleota.bin ./*tbeam-s3*/bleota-s3.bin ./**/firmware*.bin ./*t-echo*/Meshtastic_nRF52_factory_erase_v2.uf2 ./**/firmware-*.uf2 ./**/firmware-*-ota.zip ./**/*.elf ./*native*/*device-*.sh ./*native*/*device-*.bat ./firmware-raspbian-*/release/meshtasticd_linux_aarch64 ./firmware-raspbian-*/bin/config-dist.yaml
- name: Repackage in single firmware zip
uses: actions/upload-artifact@v3

View File

@@ -1,6 +1,6 @@
; The Portduino based sim environment on top of any host OS, all hardware will be simulated
[portduino_base]
platform = https://github.com/meshtastic/platform-native.git#04435d06e39916a6c019d511518d8e95c659dfbd
platform = https://github.com/meshtastic/platform-native.git#a28dd5a9ccd5c48a9bede46037855ff83915d74b
framework = arduino
build_src_filter =

Binary file not shown.

View File

@@ -60,6 +60,11 @@ GPIO:
GPS:
# SerialPath: /dev/ttyS0
### Specify I2C device, or leave blank for none
I2C:
# I2CDevice: /dev/i2c-1
### Set up SPI displays here. Note that I2C displays are generally auto-detected.
Display:
@@ -95,3 +100,8 @@ Touchscreen:
Input:
# KeyboardDevice: /dev/input/event0
###
Logging:
LogLevel: info # debug, info, warn, error

View File

@@ -10,10 +10,12 @@ default_envs = tbeam
;default_envs = heltec-v2_0
;default_envs = heltec-v2_1
;default_envs = heltec-wireless-tracker
;default_envs = chatter2
;default_envs = tlora-v1
;default_envs = tlora_v1_3
;default_envs = tlora-v2
;default_envs = tlora-v2-1-1_6
;default_envs = tlora-v2-1-1_6-tcxo
;default_envs = tlora-t3s3-v1
;default_envs = lora-relay-v1 # nrf board
;default_envs = t-echo
@@ -73,7 +75,7 @@ lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#ee628ee6c9588d4c56c9e3da35f0fc9448ad54a8 ; ESP8266_SSD1306
mathertel/OneButton@^2.5.0 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
https://github.com/meshtastic/TinyGPSPlus.git#076e8d2c8fb702d9be5b08c55b93ff76f8af7e61
https://github.com/meshtastic/TinyGPSPlus.git#2044b2c51e91ab4cd8cc93b15e40658cd808dd06
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
nanopb/Nanopb@^0.4.7
erriez/ErriezCRC32@^1.0.1

View File

@@ -193,15 +193,7 @@ class ButtonThread : public concurrency::OSThread
static void userButtonMultiPressed()
{
if (!config.device.disable_triple_click && (gps != nullptr)) {
config.position.gps_enabled = !(config.position.gps_enabled);
if (config.position.gps_enabled) {
LOG_DEBUG("Flag set to true to restore power\n");
gps->enable();
} else {
LOG_DEBUG("Flag set to false for gps power\n");
gps->disable();
}
gps->toggleGpsMode();
}
}

View File

@@ -10,12 +10,12 @@ template <class T> class Observable;
*/
template <class T> class Observer
{
std::list<Observable<T> *> observed;
std::list<Observable<T> *> observables;
public:
virtual ~Observer();
/// Stop watching the obserable
/// Stop watching the observable
void unobserve(Observable<T> *o);
/// Start watching a specified observable
@@ -86,21 +86,21 @@ template <class T> class Observable
template <class T> Observer<T>::~Observer()
{
for (typename std::list<Observable<T> *>::const_iterator iterator = observed.begin(); iterator != observed.end();
for (typename std::list<Observable<T> *>::const_iterator iterator = observables.begin(); iterator != observables.end();
++iterator) {
(*iterator)->removeObserver(this);
}
observed.clear();
observables.clear();
}
template <class T> void Observer<T>::unobserve(Observable<T> *o)
{
o->removeObserver(this);
observed.remove(o);
observables.remove(o);
}
template <class T> void Observer<T>::observe(Observable<T> *o)
{
observed.push_back(o);
observables.push_back(o);
o->addObserver(this);
}
}

View File

@@ -164,7 +164,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
#endif
#ifndef BATTERY_SENSE_SAMPLES
#define BATTERY_SENSE_SAMPLES 30
#define BATTERY_SENSE_SAMPLES \
30 // Set the number of samples, it has an effect of increasing sensitivity in complex electromagnetic environment.
#endif
#ifdef BATTERY_PIN
@@ -176,66 +177,71 @@ class AnalogBatteryLevel : public HasBatteryLevel
if (millis() - last_read_time_ms > min_read_interval) {
last_read_time_ms = millis();
// Set the number of samples, it has an effect of increasing sensitivity, especially in complex electromagnetic
// environment.
uint32_t raw = 0;
#ifdef ARCH_ESP32
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
#ifdef ADC_CTRL
if (heltec_version == 5) {
pinMode(ADC_CTRL, OUTPUT);
digitalWrite(ADC_CTRL, HIGH);
delay(10);
}
#endif
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += adc1_get_raw(adc_channel);
}
#ifdef ADC_CTRL
if (heltec_version == 5) {
digitalWrite(ADC_CTRL, LOW);
}
#endif
#else // ADC2
int32_t adc_buf = 0;
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
// ADC2 wifi bug workaround, see
// https://github.com/espressif/arduino-esp32/issues/102
WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, RTC_reg_b);
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV);
adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf);
raw += adc_buf;
}
#endif // BAT_MEASURE_ADC_UNIT
#else // !ARCH_ESP32
float scaled = 0;
#ifdef ARCH_ESP32 // ADC block for espressif platforms
raw = espAdcRead();
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
scaled *= operativeAdcMultiplier;
#else // block for all other platforms
for (uint32_t i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += analogRead(BATTERY_PIN);
}
#endif
raw = raw / BATTERY_SENSE_SAMPLES;
float scaled;
#ifdef ARCH_ESP32
scaled = esp_adc_cal_raw_to_voltage(raw, adc_characs);
scaled *= operativeAdcMultiplier;
#else
#ifndef VBAT_RAW_TO_SCALED
scaled = 1000.0 * operativeAdcMultiplier * (AREF_VOLTAGE / 1024.0) * raw;
#else
scaled = VBAT_RAW_TO_SCALED(raw); // defined in variant.h
#endif // VBAT RAW TO SCALED
#endif // ARCH_ESP32
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
#endif
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled));
last_read_value = scaled;
return scaled;
} else {
return last_read_value;
}
#else
return 0;
#endif // BATTERY_PIN
return 0;
}
#if defined(ARCH_ESP32) && !defined(HAS_PMU) && defined(BATTERY_PIN)
/**
* ESP32 specific function for getting calibrated ADC reads
*/
uint32_t espAdcRead()
{
uint32_t raw = 0;
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
#ifdef ADC_CTRL
if (heltec_version == 5) {
pinMode(ADC_CTRL, OUTPUT);
digitalWrite(ADC_CTRL, HIGH);
delay(10);
}
#endif
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += adc1_get_raw(adc_channel);
}
#ifdef ADC_CTRL
if (heltec_version == 5) {
digitalWrite(ADC_CTRL, LOW);
}
#endif
#else // ADC2
int32_t adc_buf = 0;
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
// ADC2 wifi bug workaround, see
// https://github.com/espressif/arduino-esp32/issues/102
WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, RTC_reg_b);
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV);
adc2_get_raw(adc_channel, ADC_WIDTH_BIT_12, &adc_buf);
raw += adc_buf;
}
#endif // BAT_MEASURE_ADC_UNIT
raw = raw / BATTERY_SENSE_SAMPLES;
return raw;
}
#endif
/**
* return true if there is a battery installed in this unit
*/
@@ -894,4 +900,4 @@ bool Power::axpChipInit()
#else
return false;
#endif
}
}

View File

@@ -10,6 +10,10 @@
#include <sys/time.h>
#include <time.h>
#ifdef ARCH_PORTDUINO
#include "platform/portduino/PortduinoGlue.h"
#endif
/**
* A printer that doesn't go anywhere
*/
@@ -68,7 +72,15 @@ size_t RedirectablePrint::vprintf(const char *format, va_list arg)
size_t RedirectablePrint::log(const char *logLevel, const char *format, ...)
{
if (moduleConfig.serial.override_console_serial_port && strcmp(logLevel, "DEBUG") == 0) {
#ifdef ARCH_PORTDUINO
if (settingsMap[logoutputlevel] < level_debug && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0)
return 0;
else if (settingsMap[logoutputlevel] < level_info && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_INFO) == 0)
return 0;
else if (settingsMap[logoutputlevel] < level_warn && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_WARN) == 0)
return 0;
#endif
if (moduleConfig.serial.override_console_serial_port && strcmp(logLevel, MESHTASTIC_LOG_LEVEL_DEBUG) == 0) {
return 0;
}
size_t r = 0;

View File

@@ -16,7 +16,7 @@
#define GPS_RESET_MODE HIGH
#endif
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(aLinuxInputImpl)
#if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
HardwareSerial *GPS::_serial_gps = &Serial1;
#else
HardwareSerial *GPS::_serial_gps = NULL;
@@ -251,17 +251,9 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
bool GPS::setup()
{
int msglen = 0;
bool isProblematicGPS = false;
if (!didSerialInit) {
#if !defined(GPS_UC6580)
#ifdef HAS_PMU
// The T-Beam 1.2 has issues with the GPS
if (HW_VENDOR == meshtastic_HardwareModel_TBEAM && PMU->getChipModel() == XPOWERS_AXP2101) {
gnssModel = GNSS_MODEL_UBLOX;
isProblematicGPS = true;
}
#endif
#if defined(RAK4630) && defined(PIN_3V3_EN)
// If we are using the RAK4630 and we have no other peripherals on the I2C bus or module interest in 3V3_S,
@@ -380,7 +372,7 @@ bool GPS::setup()
LOG_WARN("Unable to set GPS update rate.\n");
}
msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_GGL), _message_GGL);
msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_GLL), _message_GLL);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x01, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable NMEA GGL.\n");
@@ -416,6 +408,12 @@ bool GPS::setup()
LOG_WARN("Unable to enable NMEA GGA.\n");
}
msglen = makeUBXPacket(0x06, 0x01, sizeof(_message_AID), _message_AID);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x01, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to disable UBX-AID.\n");
}
if (uBloxProtocolVersion >= 18) {
msglen = makeUBXPacket(0x06, 0x86, sizeof(_message_PMS), _message_PMS);
_serial_gps->write(UBXscratch, msglen);
@@ -423,36 +421,31 @@ bool GPS::setup()
LOG_WARN("Unable to enable powersaving for GPS.\n");
}
} else {
if (!(isProblematicGPS)) {
if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode has only been tested on this hardware
msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving mode for GPS.\n");
}
msglen = makeUBXPacket(0x06, 0x3B, 44, _message_CFG_PM2);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x3B, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving details for GPS.\n");
}
} else {
msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving ECO mode for GPS.\n");
}
if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode is only for Neo-6
msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving ECO mode for Neo-6.\n");
}
msglen = makeUBXPacket(0x06, 0x3B, 44, _message_CFG_PM2);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x3B, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving details for GPS.\n");
}
} else {
msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving mode for GPS.\n");
}
}
}
// The T-beam 1.2 has issues.
if (!(isProblematicGPS)) {
msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x09, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to save GNSS module configuration.\n");
} else {
LOG_INFO("GNSS module configuration saved!\n");
}
msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
_serial_gps->write(UBXscratch, msglen);
if (getACK(0x06, 0x09, 2000) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to save GNSS module configuration.\n");
} else {
LOG_INFO("GNSS module configuration saved!\n");
}
}
didSerialInit = true;
@@ -611,7 +604,7 @@ uint32_t GPS::getSleepTime() const
uint32_t t = config.position.gps_update_interval;
// We'll not need the GPS thread to wake up again after first acq. with fixed position.
if (!config.position.gps_enabled || config.position.fixed_position)
if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED || config.position.fixed_position)
t = UINT32_MAX; // Sleep forever now
if (t == UINT32_MAX)
@@ -632,21 +625,24 @@ void GPS::publishUpdate()
// Notify any status instances that are observing us
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), isPowerSaving(), p);
newStatus.notifyObservers(&status);
if (config.position.gps_enabled)
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
positionModule->handleNewPosition();
}
}
}
int32_t GPS::runOnce()
{
if (!GPSInitFinished) {
if (!_serial_gps)
if (!_serial_gps || config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT) {
LOG_INFO("GPS set to not-present. Skipping probe.\n");
return disable();
}
if (!setup())
return 2000; // Setup failed, re-run in two seconds
// We have now loaded our saved preferences from flash
if (config.position.gps_enabled == false) {
if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
return disable();
}
// ONCE we will factory reset the GPS for bug #327
@@ -669,7 +665,7 @@ int32_t GPS::runOnce()
// if we have received valid NMEA claim we are connected
setConnected();
} else {
if ((config.position.gps_enabled == 1) && (gnssModel == GNSS_MODEL_UBLOX)) {
if ((config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) && (gnssModel == GNSS_MODEL_UBLOX)) {
// reset the GPS on next bootup
if (devicestate.did_gps_reset && (millis() - lastWakeStartMsec > 60000) && !hasFlow()) {
LOG_DEBUG("GPS is not communicating, trying factory reset on next bootup.\n");
@@ -682,7 +678,8 @@ int32_t GPS::runOnce()
// At least one GPS has a bad habit of losing its mind from time to time
if (rebootsSeen > 2) {
rebootsSeen = 0;
gps->factoryReset();
LOG_DEBUG("Would normally factoryReset()\n");
// gps->factoryReset();
}
// If we are overdue for an update, turn on the GPS and at least publish the current status
@@ -908,7 +905,7 @@ GPS *GPS::createGps()
int8_t _rx_gpio = config.position.rx_gpio;
int8_t _tx_gpio = config.position.tx_gpio;
int8_t _en_gpio = config.position.gps_en_gpio;
#if defined(HAS_GPS) && !defined(ARCH_ESP32)
#if HAS_GPS && !defined(ARCH_ESP32)
_rx_gpio = 1; // We only specify GPS serial ports on ESP32. Otherwise, these are just flags.
_tx_gpio = 1;
#endif
@@ -1104,7 +1101,7 @@ bool GPS::lookForLocation()
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
fixType = atoi(gsafixtype.value()); // will set to zero if no data
// LOG_DEBUG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
// LOG_DEBUG("FIX QUAL=%d, TYPE=%d\n", fixQual, fixType);
#endif
// check if GPS has an acceptable lock
@@ -1121,6 +1118,10 @@ bool GPS::lookForLocation()
reader.date.age(), reader.time.age());
#endif // GPS_EXTRAVERBOSE
// Is this a new point or are we re-reading the previous one?
if (!reader.location.isUpdated())
return false;
// check if a complete GPS solution set is available for reading
// tinyGPSDatum::age() also includes isValid() test
// FIXME
@@ -1133,10 +1134,6 @@ bool GPS::lookForLocation()
return false;
}
// Is this a new point or are we re-reading the previous one?
if (!reader.location.isUpdated())
return false;
// We know the solution is fresh and valid, so just read the data
auto loc = reader.location.value();
@@ -1286,4 +1283,17 @@ int32_t GPS::disable()
setAwake(false);
return INT32_MAX;
}
void GPS::toggleGpsMode()
{
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED;
LOG_DEBUG("Flag set to false for gps power. GpsMode: DISABLED\n");
disable();
} else if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_DISABLED) {
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
LOG_DEBUG("Flag set to true to restore power. GpsMode: ENABLED\n");
enable();
}
}

View File

@@ -103,11 +103,12 @@ class GPS : private concurrency::OSThread
static const uint8_t _message_JAM[];
static const uint8_t _message_NAVX5[];
static const uint8_t _message_1HZ[];
static const uint8_t _message_GGL[];
static const uint8_t _message_GLL[];
static const uint8_t _message_GSA[];
static const uint8_t _message_GSV[];
static const uint8_t _message_VTG[];
static const uint8_t _message_RMC[];
static const uint8_t _message_AID[];
static const uint8_t _message_GGA[];
static const uint8_t _message_PMS[];
static const uint8_t _message_SAVE[];
@@ -132,6 +133,9 @@ class GPS : private concurrency::OSThread
// Disable the thread
int32_t disable() override;
// toggle between enabled/disabled
void toggleGpsMode();
void setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime);
/// Returns true if we have acquired GPS lock.
@@ -143,7 +147,7 @@ class GPS : private concurrency::OSThread
/// Return true if we are connected to a GPS
bool isConnected() const { return hasGPS; }
bool isPowerSaving() const { return !config.position.gps_enabled; }
bool isPowerSaving() const { return config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED; }
// Empty the input buffer as quickly as possible
void clearBuffer();

View File

@@ -10,24 +10,32 @@ const uint8_t GPS::_message_CFG_RXM_PSM[] PROGMEM = {
0x01 // Power save mode
};
// only for Neo-6
const uint8_t GPS::_message_CFG_RXM_ECO[] PROGMEM = {
0x08, // Reserved
0x04 // eco mode
};
const uint8_t GPS::_message_CFG_PM2[] PROGMEM = {
0x01, 0x06, 0x00, 0x00, // version, Reserved
0x0E, 0x81, 0x43, 0x01, // flags
0x01, // version
0x00, // Reserved 1, set to 0x06 by u-Center
0x00, // Reserved 2
0x00, // Reserved 1
0x00, 0x11, 0x03, 0x00, // flags-> cyclic mode, wait for normal fix ok, do not wake to update RTC or EPH, doNotEnterOff,
// LimitPeakCurrent
0xE8, 0x03, 0x00, 0x00, // update period 1000 ms
0x10, 0x27, 0x00, 0x00, // search period 10s
0x00, 0x00, 0x00, 0x00, // Grod offset 0
0x00, 0x00, 0x00, 0x00, // Grid offset 0
0x01, 0x00, // onTime 1 second
0x00, 0x00, // min search time 0
0x2C, 0x01, // reserved
0x00, 0x00, 0x4F, 0xC1, // reserved
0x03, 0x00, 0x87, 0x02, // reserved
0x00, 0x00, 0xFF, 0x00, // reserved
0x01, 0x00, 0xD6, 0x4D // reserved
0x00, 0x00, // 0x2C, 0x01, // reserved 4
0x00, 0x00, // 0x00, 0x00, // reserved 5
0x00, 0x00, 0x00, 0x00, // 0x4F, 0xC1, 0x03, 0x00, // reserved 6
0x00, 0x00, 0x00, 0x00, // 0x87, 0x02, 0x00, 0x00, // reserved 7
0x00, // 0xFF, // reserved 8
0x00, // 0x00, // reserved 9
0x00, 0x00, // 0x00, 0x00, // reserved 10
0x00, 0x00, 0x00, 0x00 // 0x64, 0x40, 0x01, 0x00 // reserved 11
};
const uint8_t GPS::_message_GNSS_7[] = {
@@ -56,52 +64,59 @@ const uint8_t GPS::_message_GNSS[] = {
0x01, 0x01, 0x03, 0x00, 0x01, 0x00, 0x01, 0x01, // SBAS
0x06, 0x08, 0x0e, 0x00, 0x01, 0x00, 0x01, 0x01 // GLONASS
};
// Enable jamming/interference monitor
// Enable interference resistance, because we are using LoRa, WiFi and Bluetooth on same board,
// and we need to reduce interference from them
// For Neo-6
const uint8_t GPS::_message_JAM[] = {
// bbThreshold (Broadband jamming detection threshold) is set to 0x3F (63 in decimal)
// cwThreshold (CW jamming detection threshold) is set to 0x10 (16 in decimal)
// algorithmBits (Reserved algorithm settings) is set to 0x16B156 as recommended
// enable (Enable interference detection) is set to 1 (enabled)
0x3F, 0x10, 0xB1, 0x56, // config: Interference config word
// generalBits (General settings) is set to 0x31E as recommended
// antSetting (Antenna setting, 0=unknown, 1=passive, 2=active) is set to 0 (unknown)
// ToDo: Set to 1 (passive) or 2 (active) if known, for example from UBX-MON-HW, or from board info
// enable2 (Set to 1 to scan auxiliary bands, u-blox 8 / u-blox M8 only, otherwise ignored) is set to 1
// (enabled)
0x1E, 0x03, 0x00, 0x01 // config2: Extra settings for jamming/interference monitor
0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable = 1, reserved bits 0x16B156
0x1e, 0x03, 0x00, 0x00 // config2 antennaSetting Unknown = 0, reserved 3, = 0x00,0x00, reserved 2 = 0x31E
};
/* // WIP GPS reconfig
// For Neo-6, Max-7 and Neo-7
const uint8_t GPS::_message_JAM_6_7[] = {
0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable = 1, reserved bits 0x16B156
0x1e, 0x03, 0x00, 0x00 // config2 antennaSetting Unknown = 0, reserved 3, = 0x00,0x00, reserved 2 = 0x31E
};
// For M8
const uint8_t GPS::_message_JAM_8[] = {
0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable1 = 1, reserved bits 0x16B156
0x1e, 0x43, 0x00, 0x00 // config2 antennaSetting Unknown = 0, enable2 = 1, generalBits = 0x31E
};
*/
// Configure navigation engine expert settings:
// there are many variations of what were Reserved fields for the Neo-6 in later versions
// ToDo: check UBX-MON-VER for module type and protocol version
// For the Neo-6
const uint8_t GPS::_message_NAVX5[] = {
0x00, 0x00, // msgVer (0 for this version)
// minMax flag = 1: apply min/max SVs settings
// minCno flag = 1: apply minimum C/N0 setting
// initial3dfix flag = 0: apply initial 3D fix settings
// aop flag = 1: apply aopCfg (useAOP flag) settings (AssistNow Autonomous)
0x1B, 0x00, // mask1 (First parameters bitmask)
// adr flag = 0: apply ADR sensor fusion on/off setting (useAdr flag)
// If firmware is not ADR/UDR, enabling this flag will fail configuration
// ToDo: check this with UBX-MON-VER
0x00, 0x00, 0x00, 0x00, // mask2 (Second parameters bitmask)
0x00, 0x00, // Reserved
0x03, // minSVs (Minimum number of satellites for navigation) = 3
0x10, // maxSVs (Maximum number of satellites for navigation) = 16
0x06, // minCNO (Minimum satellite signal level for navigation) = 6 dBHz
0x00, // Reserved
0x00, // iniFix3D (Initial fix must be 3D) = 0 (disabled)
0x00, 0x00, // Reserved
0x00, // ackAiding (Issue acknowledgements for assistance message input) = 0 (disabled)
0x00, 0x00, // Reserved
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved
0x00, // Reserved
0x01, // aopCfg (AssistNow Autonomous configuration) = 1 (enabled)
0x00, 0x00, // Reserved
0x00, 0x00, // Reserved
0x00, 0x00, 0x00, 0x00, // Reserved
0x00, 0x00, 0x00, // Reserved
0x01, // useAdr (Enable/disable ADR sensor fusion) = 1 (enabled)
0x00, 0x00, // msgVer (0 for this version)
0x4c, 0x66, // mask1
0x00, 0x00, 0x00, 0x00, // Reserved 0
0x00, // Reserved 1
0x00, // Reserved 2
0x03, // minSVs (Minimum number of satellites for navigation) = 3
0x10, // maxSVs (Maximum number of satellites for navigation) = 16
0x06, // minCNO (Minimum satellite signal level for navigation) = 6 dBHz
0x00, // Reserved 5
0x00, // iniFix3D (Initial fix must be 3D) (0 = false 1 = true)
0x00, // Reserved 6
0x00, // Reserved 7
0x00, // Reserved 8
0x00, 0x00, // wknRollover 0 = firmware default
0x00, 0x00, 0x00, 0x00, // Reserved 9
0x00, // Reserved 10
0x00, // Reserved 11
0x00, // usePPP (Precice Point Positioning) (0 = false, 1 = true)
0x01, // useAOP (AssistNow Autonomous configuration) = 1 (enabled)
0x00, // Reserved 12
0x00, // Reserved 13
0x00, 0x00, // aopOrbMaxErr = 0 to reset to firmware default
0x00, // Reserved 14
0x00, // Reserved 15
0x00, 0x00, // Reserved 3
0x00, 0x00, 0x00, 0x00 // Reserved 4
};
// Set GPS update rate to 1Hz
@@ -111,58 +126,88 @@ const uint8_t GPS::_message_NAVX5[] = {
const uint8_t GPS::_message_1HZ[] = {
0xE8, 0x03, // Measurement Rate (1000ms for 1Hz)
0x01, 0x00, // Navigation rate, always 1 in GPS mode
0x01, 0x00, // Time reference
0x01, 0x00 // Time reference
};
// Disable GGL. GGL - Geographic position (latitude and longitude), which provides the current geographical
// Disable GLL. GLL - Geographic position (latitude and longitude), which provides the current geographical
// coordinates.
const uint8_t GPS::_message_GGL[] = {
0xF0, 0x01, // NMEA ID for GLL
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x00, // Disable
0x01, 0x01, 0x01, 0x01 // Reserved
const uint8_t GPS::_message_GLL[] = {
0xF0, 0x01, // NMEA ID for GLL
0x00, // Rate for DDC
0x00, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Enable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and
// the DOP (Dilution of Precision)
const uint8_t GPS::_message_GSA[] = {
0xF0, 0x02, // NMEA ID for GSA
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x01, // Enable
0x01, 0x01, 0x01, 0x01 // Reserved
0xF0, 0x02, // NMEA ID for GSA
0x00, // Rate for DDC
0x01, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Disable GSV. GSV - Satellites in view, details the number and location of satellites in view.
const uint8_t GPS::_message_GSV[] = {
0xF0, 0x03, // NMEA ID for GSV
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x00, // Disable
0x01, 0x01, 0x01, 0x01 // Reserved
0xF0, 0x03, // NMEA ID for GSV
0x00, // Rate for DDC
0x00, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to
// the ground.
const uint8_t GPS::_message_VTG[] = {
0xF0, 0x05, // NMEA ID for VTG
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x00, // Disable
0x01, 0x01, 0x01, 0x01 // Reserved
0xF0, 0x05, // NMEA ID for VTG
0x00, // Rate for DDC
0x00, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data.
const uint8_t GPS::_message_RMC[] = {
0xF0, 0x04, // NMEA ID for RMC
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x01, // Enable
0x01, 0x01, 0x01, 0x01 // Reserved
0xF0, 0x04, // NMEA ID for RMC
0x00, // Rate for DDC
0x01, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data.
const uint8_t GPS::_message_GGA[] = {
0xF0, 0x00, // NMEA ID for GGA
0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI
0x01, // Enable
0x01, 0x01, 0x01, 0x01 // Reserved
0xF0, 0x00, // NMEA ID for GGA
0x00, // Rate for DDC
0x01, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// Disable UBX-AID-ALPSRV as it may confuse TinyGPS. The Neo-6 seems to send this message
// whether the AID Autonomous is enabled or not
const uint8_t GPS::_message_AID[] = {
0x0B, 0x32, // NMEA ID for UBX-AID-ALPSRV
0x00, // Rate for DDC
0x00, // Rate for UART1
0x00, // Rate for UART2
0x00, // Rate for USB
0x00, // Rate for SPI
0x00 // Reserved
};
// The Power Management configuration allows the GPS module to operate in different power modes for optimized
@@ -176,17 +221,18 @@ const uint8_t GPS::_message_GGA[] = {
// is set to Interval; otherwise, it must be set to '0'. The 'onTime' field specifies the duration of the ON phase
// and must be smaller than the period. It is only valid when the powerSetupValue is set to Interval; otherwise,
// it must be set to '0'.
// This command applies to M8 and higher products
const uint8_t GPS::_message_PMS[] = {
0x00, // Version (0)
0x03, // Power setup value
0x03, // Power setup value 3 = Agresssive 1Hz
0x00, 0x00, // period: not applicable, set to 0
0x00, 0x00, // onTime: not applicable, set to 0
0x97, 0x6F // reserved, generated by u-center
0x00, 0x00 // reserved, generated by u-center
};
const uint8_t GPS::_message_SAVE[] = {
0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
0x0F // deviceMask: BBR, Flash, EEPROM, and SPI Flash
};
0x17 // deviceMask: BBR, Flash, EEPROM, and SPI Flash
};

View File

@@ -558,15 +558,20 @@ static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus
}
}
// Draw status when gps is disabled by PMU
// Draw status when GPS is disabled or not present
static void drawGPSpowerstat(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{
String displayLine = "GPS disabled";
int16_t xPos = display->getStringWidth(displayLine);
if (!config.position.gps_enabled) {
display->drawString(x + xPos, y, displayLine);
String displayLine;
int pos;
if (y < FONT_HEIGHT_SMALL) { // Line 1: use short string
displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "No GPS" : "GPS off";
pos = SCREEN_WIDTH - display->getStringWidth(displayLine);
} else {
displayLine = config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT ? "GPS not present"
: "GPS is disabled";
pos = (SCREEN_WIDTH - display->getStringWidth(displayLine)) / 2;
}
display->drawString(x + pos, y, displayLine);
}
static void drawGPSAltitude(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
@@ -594,7 +599,7 @@ static void drawGPScoordinates(OLEDDisplay *display, int16_t x, int16_t y, const
String displayLine = "";
if (!gps->getIsConnected() && !config.position.fixed_position) {
displayLine = "No GPS Module";
displayLine = "No GPS present";
display->drawString(x + (SCREEN_WIDTH - (display->getStringWidth(displayLine))) / 2, y, displayLine);
} else if (!gps->getHasLock() && !config.position.fixed_position) {
displayLine = "No GPS Lock";
@@ -1549,7 +1554,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus);
}
// Display GPS status
if (!config.position.gps_enabled) {
if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
drawGPSpowerstat(display, x, y + 2, gpsStatus);
} else {
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
@@ -1777,7 +1782,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
char chUtil[13];
snprintf(chUtil, sizeof(chUtil), "ChUtil %2.0f%%", airTime->channelUtilizationPercent());
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil);
if (config.position.gps_enabled) {
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
// Line 3
if (config.display.gps_format !=
meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude
@@ -1786,10 +1791,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
// Line 4
drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
} else {
drawGPSpowerstat(display, x - (SCREEN_WIDTH / 4), y + FONT_HEIGHT_SMALL * 2, gpsStatus);
#ifdef GPS_POWER_TOGGLE
display->drawString(x + 30, (y + FONT_HEIGHT_SMALL * 3), " by button");
#endif
drawGPSpowerstat(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
}
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
#ifdef SHOW_REDRAWS

View File

@@ -19,6 +19,10 @@
#define TFT_BL ST7735_BACKLIGHT_EN
#endif
#ifndef TFT_INVERT
#define TFT_INVERT true
#endif
class LGFX : public lgfx::LGFX_Device
{
lgfx::Panel_ST7735S _panel_instance;
@@ -68,7 +72,7 @@ class LGFX : public lgfx::LGFX_Device
cfg.dummy_read_pixel = 8; // Number of bits for dummy read before pixel readout
cfg.dummy_read_bits = 1; // Number of bits for dummy read before non-pixel data read
cfg.readable = true; // Set to true if data can be read
cfg.invert = true; // Set to true if the light/darkness of the panel is reversed
cfg.invert = TFT_INVERT; // Set to true if the light/darkness of the panel is reversed
cfg.rgb_order = false; // Set to true if the panel's red and blue are swapped
cfg.dlen_16bit =
false; // Set to true for panels that transmit data length in 16-bit units with 16-bit parallel or SPI
@@ -598,7 +602,7 @@ bool TFTDisplay::connect()
tft->setRotation(1);
tft->setSwapBytes(true);
// tft->fillScreen(TFT_BLACK);
#elif defined(T_DECK) || defined(PICOMPUTER_S3)
#elif defined(T_DECK) || defined(PICOMPUTER_S3) || defined(CHATTER_2)
tft->setRotation(1); // T-Deck has the TFT in landscape
#elif defined(T_WATCH_S3)
tft->setRotation(2); // T-Watch S3 left-handed orientation

View File

@@ -248,6 +248,11 @@ void setup()
digitalWrite(PIN_EINK_PWR_ON, HIGH);
#endif
#if defined(LORA_TCXO_GPIO)
pinMode(LORA_TCXO_GPIO, OUTPUT);
digitalWrite(LORA_TCXO_GPIO, HIGH);
#endif
#ifdef ST7735_BL_V03 // Heltec Wireless Tracker PCB Change Detect/Hack
rtc_clk_32k_enable(true);
@@ -363,6 +368,13 @@ void setup()
Wire.begin();
#elif defined(I2C_SDA) && !defined(ARCH_RP2040)
Wire.begin(I2C_SDA, I2C_SCL);
#elif defined(ARCH_PORTDUINO)
if (settingsStrings[i2cdev] != "") {
LOG_INFO("Using %s as I2C device.\n", settingsStrings[i2cdev]);
Wire.begin(settingsStrings[i2cdev].c_str());
} else {
LOG_INFO("No I2C device configured, skipping.\n");
}
#elif HAS_WIRE
Wire.begin();
#endif
@@ -408,8 +420,9 @@ void setup()
// 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());
#ifdef HAS_WIRE
LOG_INFO("Scanning for i2c devices...\n");
#endif
#if defined(I2C_SDA1) && defined(ARCH_RP2040)
Wire1.setSDA(I2C_SDA1);
@@ -429,6 +442,11 @@ void setup()
#elif defined(I2C_SDA) && !defined(ARCH_RP2040)
Wire.begin(I2C_SDA, I2C_SCL);
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
#elif defined(ARCH_PORTDUINO)
if (settingsStrings[i2cdev] != "") {
LOG_INFO("Scanning for i2c devices...\n");
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
}
#elif HAS_WIRE
i2cScanner->scanPort(ScanI2C::I2CPort::WIRE);
#endif
@@ -667,7 +685,8 @@ void setup()
readFromRTC(); // read the main CPU RTC at first (in case we can't get GPS time)
// If we're taking on the repeater role, ignore GPS
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER) {
if (config.device.role != meshtastic_Config_DeviceConfig_Role_REPEATER &&
config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT) {
gps = GPS::createGps();
}
if (gps) {
@@ -717,6 +736,7 @@ void setup()
#ifdef ARCH_PORTDUINO
if (settingsMap[use_sx1262]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate sx1262 radio on SPI port %s\n", settingsStrings[spidev].c_str());
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
@@ -730,6 +750,7 @@ void setup()
}
} else if (settingsMap[use_rf95]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate rf95 radio on SPI port %s\n", settingsStrings[spidev].c_str());
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
@@ -744,6 +765,7 @@ void setup()
}
} else if (settingsMap[use_sx1280]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate sx1280 radio on SPI port %s\n", settingsStrings[spidev].c_str());
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);

View File

@@ -15,6 +15,7 @@ Channels channels;
const char *Channels::adminChannel = "admin";
const char *Channels::gpioChannel = "gpio";
const char *Channels::serialChannel = "serial";
const char *Channels::mqttChannel = "mqtt";
uint8_t xorHash(const uint8_t *p, size_t len)
{
@@ -313,4 +314,4 @@ bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
int16_t Channels::setActiveByIndex(ChannelIndex channelIndex)
{
return setCrypto(channelIndex);
}
}

View File

@@ -32,7 +32,7 @@ class Channels
Channels() {}
/// Well known channel names
static const char *adminChannel, *gpioChannel, *serialChannel;
static const char *adminChannel, *gpioChannel, *serialChannel, *mqttChannel;
const meshtastic_ChannelSettings &getPrimary() { return getByIndex(getPrimaryIndex()).settings; }
@@ -139,4 +139,4 @@ class Channels
};
/// Singleton channel table
extern Channels channels;
extern Channels channels;

View File

@@ -108,8 +108,9 @@ void MeshService::loop()
(void)sendQueueStatusToPhone(qs, 0, 0);
}
if (oldFromNum != fromNum) { // We don't want to generate extra notifies for multiple new packets
fromNumChanged.notifyObservers(fromNum);
oldFromNum = fromNum;
int result = fromNumChanged.notifyObservers(fromNum);
if (result == 0) // If any observer returns non-zero, we will try again
oldFromNum = fromNum;
}
}

View File

@@ -182,7 +182,16 @@ void NodeDB::installDefaultConfig()
#else
config.device.disable_triple_click = true;
#endif
config.position.gps_enabled = true;
#if !HAS_GPS || defined(T_DECK)
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT;
#elif !defined(GPS_RX_PIN)
if (config.position.rx_gpio == 0)
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT;
else
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_DISABLED;
#else
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
#endif
config.position.position_broadcast_smart_enabled = true;
config.position.broadcast_smart_minimum_distance = 100;
config.position.broadcast_smart_minimum_interval_secs = 30;
@@ -454,6 +463,11 @@ void NodeDB::init()
memcpy(devicestate.node_remote_hardware_pins, empty, sizeof(empty));
}
if (config.position.gps_enabled) {
config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_ENABLED;
config.position.gps_enabled = 0;
}
saveToDisk(saveWhat);
}
@@ -879,10 +893,11 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
if ((*numMeshNodes >= MAX_NUM_NODES) || (memGet.getFreeHeap() < meshtastic_NodeInfoLite_size * 3)) {
if (screen)
screen->print("warning: node_db_lite full! erasing oldest entry\n");
LOG_INFO("warning: node_db_lite full! erasing oldest entry\n");
// look for oldest node and erase it
uint32_t oldest = UINT32_MAX;
int oldestIndex = -1;
for (int i = 0; i < *numMeshNodes; i++) {
for (int i = 1; i < *numMeshNodes; i++) {
if (meshNodes[i].last_heard < oldest) {
oldest = meshNodes[i].last_heard;
oldestIndex = i;
@@ -926,4 +941,4 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co
LOG_ERROR("A critical failure occurred, portduino is exiting...");
exit(2);
#endif
}
}

View File

@@ -62,15 +62,17 @@ void PhoneAPI::close()
}
}
void PhoneAPI::checkConnectionTimeout()
bool PhoneAPI::checkConnectionTimeout()
{
if (isConnected()) {
bool newContact = checkIsConnected();
if (!newContact) {
LOG_INFO("Lost phone connection\n");
close();
return true;
}
}
return false;
}
/**
@@ -461,8 +463,8 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p)
/// If the mesh service tells us fromNum has changed, tell the phone
int PhoneAPI::onNotify(uint32_t newValue)
{
checkConnectionTimeout(); // a handy place to check if we've heard from the phone (since the BLE version doesn't call this
// from idle)
bool timeout = checkConnectionTimeout(); // a handy place to check if we've heard from the phone (since the BLE version
// doesn't call this from idle)
if (state == STATE_SEND_PACKETS) {
LOG_INFO("Telling client we have new packets %u\n", newValue);
@@ -471,5 +473,5 @@ int PhoneAPI::onNotify(uint32_t newValue)
LOG_DEBUG("(Client not yet interested in packets)\n");
}
return 0;
return timeout ? -1 : 0; // If we timed out, MeshService should stop iterating through observers as we just removed one
}

View File

@@ -108,8 +108,8 @@ class PhoneAPI
/// Hookable to find out when connection changes
virtual void onConnectionChanged(bool connected) {}
/// If we haven't heard from the other side in a while then say not connected
void checkConnectionTimeout();
/// If we haven't heard from the other side in a while then say not connected. Returns true if timeout occurred
bool checkConnectionTimeout();
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() = 0;
@@ -142,4 +142,4 @@ class PhoneAPI
/// If the mesh service tells us fromNum has changed, tell the phone
virtual int onNotify(uint32_t newValue) override;
};
};

View File

@@ -248,28 +248,21 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
// If the packet is not yet encrypted, do so now
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
if (moduleConfig.mqtt.enabled) {
LOG_INFO("Should encrypt MQTT?: %d\n", moduleConfig.mqtt.encryption_enabled);
// the packet is currently in a decrypted state. send it now if they want decrypted packets
if (mqtt && !moduleConfig.mqtt.encryption_enabled)
mqtt->onSend(*p, chIndex);
}
meshtastic_MeshPacket *p_decoded = packetPool.allocCopy(*p);
auto encodeResult = perhapsEncode(p);
if (encodeResult != meshtastic_Routing_Error_NONE) {
packetPool.release(p_decoded);
abortSendAndNak(encodeResult, p);
return encodeResult; // FIXME - this isn't a valid ErrorCode
}
if (moduleConfig.mqtt.enabled) {
// the packet is now encrypted.
// check if we should send encrypted packets to mqtt
if (mqtt && moduleConfig.mqtt.encryption_enabled)
mqtt->onSend(*p, chIndex);
LOG_INFO("Should encrypt MQTT?: %d\n", moduleConfig.mqtt.encryption_enabled);
if (mqtt)
mqtt->onSend(*p, *p_decoded, chIndex);
}
packetPool.release(p_decoded);
}
assert(iface); // This should have been detected already in sendLocal (or we just received a packet from outside)

View File

@@ -134,6 +134,8 @@ typedef struct _meshtastic_AdminMessage {
/* Enter (UF2) DFU mode
Only implemented on NRF52 currently */
bool enter_dfu_mode_request;
/* Delete the file by the specified path from the device */
char delete_file_request[201];
/* Set the owner for this node */
meshtastic_User set_owner;
/* Set channels (using the new API).
@@ -228,6 +230,7 @@ extern "C" {
#define meshtastic_AdminMessage_get_node_remote_hardware_pins_request_tag 19
#define meshtastic_AdminMessage_get_node_remote_hardware_pins_response_tag 20
#define meshtastic_AdminMessage_enter_dfu_mode_request_tag 21
#define meshtastic_AdminMessage_delete_file_request_tag 22
#define meshtastic_AdminMessage_set_owner_tag 32
#define meshtastic_AdminMessage_set_channel_tag 33
#define meshtastic_AdminMessage_set_config_tag 34
@@ -266,6 +269,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_ham_mode,set_ham_mode),
X(a, STATIC, ONEOF, BOOL, (payload_variant,get_node_remote_hardware_pins_request,get_node_remote_hardware_pins_request), 19) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,get_node_remote_hardware_pins_response,get_node_remote_hardware_pins_response), 20) \
X(a, STATIC, ONEOF, BOOL, (payload_variant,enter_dfu_mode_request,enter_dfu_mode_request), 21) \
X(a, STATIC, ONEOF, STRING, (payload_variant,delete_file_request,delete_file_request), 22) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_owner,set_owner), 32) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_channel,set_channel), 33) \
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,set_config,set_config), 34) \

View File

@@ -45,3 +45,4 @@ PB_BIND(meshtastic_Config_BluetoothConfig, meshtastic_Config_BluetoothConfig, AU

View File

@@ -108,6 +108,15 @@ typedef enum _meshtastic_Config_PositionConfig_PositionFlags {
meshtastic_Config_PositionConfig_PositionFlags_SPEED = 512
} meshtastic_Config_PositionConfig_PositionFlags;
typedef enum _meshtastic_Config_PositionConfig_GpsMode {
/* GPS is present but disabled */
meshtastic_Config_PositionConfig_GpsMode_DISABLED = 0,
/* GPS is present and enabled */
meshtastic_Config_PositionConfig_GpsMode_ENABLED = 1,
/* GPS is not present on the device */
meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT = 2
} meshtastic_Config_PositionConfig_GpsMode;
typedef enum _meshtastic_Config_NetworkConfig_AddressMode {
/* obtain ip address via DHCP */
meshtastic_Config_NetworkConfig_AddressMode_DHCP = 0,
@@ -300,6 +309,8 @@ typedef struct _meshtastic_Config_PositionConfig {
uint32_t broadcast_smart_minimum_interval_secs;
/* (Re)define PIN_GPS_EN for your board. */
uint32_t gps_en_gpio;
/* Set where GPS is enabled, disabled, or not present */
meshtastic_Config_PositionConfig_GpsMode gps_mode;
} meshtastic_Config_PositionConfig;
/* Power Config\
@@ -507,6 +518,10 @@ extern "C" {
#define _meshtastic_Config_PositionConfig_PositionFlags_MAX meshtastic_Config_PositionConfig_PositionFlags_SPEED
#define _meshtastic_Config_PositionConfig_PositionFlags_ARRAYSIZE ((meshtastic_Config_PositionConfig_PositionFlags)(meshtastic_Config_PositionConfig_PositionFlags_SPEED+1))
#define _meshtastic_Config_PositionConfig_GpsMode_MIN meshtastic_Config_PositionConfig_GpsMode_DISABLED
#define _meshtastic_Config_PositionConfig_GpsMode_MAX meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT
#define _meshtastic_Config_PositionConfig_GpsMode_ARRAYSIZE ((meshtastic_Config_PositionConfig_GpsMode)(meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT+1))
#define _meshtastic_Config_NetworkConfig_AddressMode_MIN meshtastic_Config_NetworkConfig_AddressMode_DHCP
#define _meshtastic_Config_NetworkConfig_AddressMode_MAX meshtastic_Config_NetworkConfig_AddressMode_STATIC
#define _meshtastic_Config_NetworkConfig_AddressMode_ARRAYSIZE ((meshtastic_Config_NetworkConfig_AddressMode)(meshtastic_Config_NetworkConfig_AddressMode_STATIC+1))
@@ -543,6 +558,7 @@ extern "C" {
#define meshtastic_Config_DeviceConfig_role_ENUMTYPE meshtastic_Config_DeviceConfig_Role
#define meshtastic_Config_DeviceConfig_rebroadcast_mode_ENUMTYPE meshtastic_Config_DeviceConfig_RebroadcastMode
#define meshtastic_Config_PositionConfig_gps_mode_ENUMTYPE meshtastic_Config_PositionConfig_GpsMode
#define meshtastic_Config_NetworkConfig_address_mode_ENUMTYPE meshtastic_Config_NetworkConfig_AddressMode
@@ -562,7 +578,7 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_Config_init_default {0, {meshtastic_Config_DeviceConfig_init_default}}
#define meshtastic_Config_DeviceConfig_init_default {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0}
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_PositionConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN}
#define meshtastic_Config_PowerConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_NetworkConfig_init_default {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_default, ""}
#define meshtastic_Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
@@ -571,7 +587,7 @@ extern "C" {
#define meshtastic_Config_BluetoothConfig_init_default {0, _meshtastic_Config_BluetoothConfig_PairingMode_MIN, 0}
#define meshtastic_Config_init_zero {0, {meshtastic_Config_DeviceConfig_init_zero}}
#define meshtastic_Config_DeviceConfig_init_zero {_meshtastic_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0, _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN, 0, 0, 0, 0}
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_PositionConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _meshtastic_Config_PositionConfig_GpsMode_MIN}
#define meshtastic_Config_PowerConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0}
#define meshtastic_Config_NetworkConfig_init_zero {0, "", "", "", 0, _meshtastic_Config_NetworkConfig_AddressMode_MIN, false, meshtastic_Config_NetworkConfig_IpV4Config_init_zero, ""}
#define meshtastic_Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
@@ -602,6 +618,7 @@ extern "C" {
#define meshtastic_Config_PositionConfig_broadcast_smart_minimum_distance_tag 10
#define meshtastic_Config_PositionConfig_broadcast_smart_minimum_interval_secs_tag 11
#define meshtastic_Config_PositionConfig_gps_en_gpio_tag 12
#define meshtastic_Config_PositionConfig_gps_mode_tag 13
#define meshtastic_Config_PowerConfig_is_power_saving_tag 1
#define meshtastic_Config_PowerConfig_on_battery_shutdown_after_secs_tag 2
#define meshtastic_Config_PowerConfig_adc_multiplier_override_tag 3
@@ -704,7 +721,8 @@ X(a, STATIC, SINGULAR, UINT32, rx_gpio, 8) \
X(a, STATIC, SINGULAR, UINT32, tx_gpio, 9) \
X(a, STATIC, SINGULAR, UINT32, broadcast_smart_minimum_distance, 10) \
X(a, STATIC, SINGULAR, UINT32, broadcast_smart_minimum_interval_secs, 11) \
X(a, STATIC, SINGULAR, UINT32, gps_en_gpio, 12)
X(a, STATIC, SINGULAR, UINT32, gps_en_gpio, 12) \
X(a, STATIC, SINGULAR, UENUM, gps_mode, 13)
#define meshtastic_Config_PositionConfig_CALLBACK NULL
#define meshtastic_Config_PositionConfig_DEFAULT NULL
@@ -810,7 +828,7 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
#define meshtastic_Config_LoRaConfig_size 80
#define meshtastic_Config_NetworkConfig_IpV4Config_size 20
#define meshtastic_Config_NetworkConfig_size 196
#define meshtastic_Config_PositionConfig_size 60
#define meshtastic_Config_PositionConfig_size 62
#define meshtastic_Config_PowerConfig_size 40
#define meshtastic_Config_size 199
@@ -818,4 +836,4 @@ extern const pb_msgdesc_t meshtastic_Config_BluetoothConfig_msg;
} /* extern "C" */
#endif
#endif
#endif

View File

@@ -316,7 +316,7 @@ extern const pb_msgdesc_t meshtastic_NodeRemoteHardwarePin_msg;
#define meshtastic_DeviceState_size 17062
#define meshtastic_NodeInfoLite_size 153
#define meshtastic_NodeRemoteHardwarePin_size 29
#define meshtastic_OEMStore_size 3244
#define meshtastic_OEMStore_size 3246
#define meshtastic_PositionLite_size 28
#ifdef __cplusplus

View File

@@ -180,7 +180,7 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
#define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg
/* Maximum encoded size of messages (where known) */
#define meshtastic_LocalConfig_size 467
#define meshtastic_LocalConfig_size 469
#define meshtastic_LocalModuleConfig_size 631
#ifdef __cplusplus

View File

@@ -71,6 +71,8 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_SENSELORA_RP2040 = 27,
/* Makerfabs SenseLoRA Industrial Monitor (ESP32-S3 + RFM96) */
meshtastic_HardwareModel_SENSELORA_S3 = 28,
/* Canary Radio Company - CanaryOne: https://canaryradio.io/products/canaryone */
meshtastic_HardwareModel_CANARYONE = 29,
/* ---------------------------------------------------------------------------
Less common/prototype boards listed here (needs one more byte over the air)
--------------------------------------------------------------------------- */

View File

@@ -3,6 +3,7 @@
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerFSM.h"
#include <FSCommon.h>
#ifdef ARCH_ESP32
#include "BleOta.h"
#endif
@@ -194,6 +195,15 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
#endif
break;
}
case meshtastic_AdminMessage_delete_file_request_tag: {
LOG_DEBUG("Client is requesting to delete file: %s\n", r->delete_file_request);
if (FSCom.remove(r->delete_file_request)) {
LOG_DEBUG("Successfully deleted file\n");
} else {
LOG_DEBUG("Failed to delete file\n");
}
break;
}
#ifdef ARCH_PORTDUINO
case meshtastic_AdminMessage_exit_simulator_tag:
LOG_INFO("Exiting simulator\n");

View File

@@ -204,6 +204,8 @@ int32_t PositionModule::runOnce()
}
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
if (node == nullptr)
return RUNONCE_INTERVAL;
// We limit our GPS broadcasts to a max rate
uint32_t now = millis();

View File

@@ -17,7 +17,6 @@
#include "mesh/wifi/WiFiAPClient.h"
#include <WiFi.h>
#endif
#include "mqtt/JSON.h"
#include <assert.h>
const int reconnectMax = 5;
@@ -49,8 +48,6 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
payloadStr[length] = 0; // null terminated string
JSONValue *json_value = JSON::Parse(payloadStr);
if (json_value != NULL) {
LOG_INFO("JSON Received on MQTT, parsing..\n");
// check if it is a valid envelope
JSONObject json;
json = json_value->AsObject();
@@ -61,22 +58,21 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
ptr = strtok(NULL, "/");
}
meshtastic_Channel sendChannel = channels.getByName(ptr);
LOG_DEBUG("Found Channel name: %s (Index %d)\n", channels.getGlobalId(sendChannel.index), sendChannel.index);
// We allow downlink JSON packets only on a channel named "mqtt"
if (strncasecmp(channels.getGlobalId(sendChannel.index), Channels::mqttChannel, strlen(Channels::mqttChannel)) == 0 &&
sendChannel.settings.downlink_enabled) {
if (isValidJsonEnvelope(json)) {
// this is a valid envelope
if (json["type"]->AsString().compare("sendtext") == 0 && json["payload"]->IsString()) {
std::string jsonPayloadStr = json["payload"]->AsString();
LOG_INFO("JSON payload %s, length %u\n", jsonPayloadStr.c_str(), jsonPayloadStr.length());
if ((json.find("sender") != json.end()) && (json.find("payload") != json.end()) &&
(json.find("type") != json.end()) && json["type"]->IsString() &&
(json["type"]->AsString().compare("sendtext") == 0)) {
// this is a valid envelope
if (json["payload"]->IsString() && json["type"]->IsString() &&
(json["sender"]->AsString().compare(owner.id) != 0)) {
std::string jsonPayloadStr = json["payload"]->AsString();
LOG_INFO("JSON payload %s, length %u\n", jsonPayloadStr.c_str(), jsonPayloadStr.length());
// construct protobuf data packet using TEXT_MESSAGE, send it to the mesh
meshtastic_MeshPacket *p = router->allocForSending();
p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP;
p->channel = sendChannel.index;
if (sendChannel.settings.downlink_enabled) {
// construct protobuf data packet using TEXT_MESSAGE, send it to the mesh
meshtastic_MeshPacket *p = router->allocForSending();
p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP;
p->channel = sendChannel.index;
if (json.find("to") != json.end() && json["to"]->IsNumber())
p->to = json["to"]->AsNumber();
if (jsonPayloadStr.length() <= sizeof(p->decoded.payload.bytes)) {
memcpy(p->decoded.payload.bytes, jsonPayloadStr.c_str(), jsonPayloadStr.length());
p->decoded.payload.size = jsonPayloadStr.length();
@@ -85,61 +81,63 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
} else {
LOG_WARN("Received MQTT json payload too long, dropping\n");
}
} else {
LOG_WARN("Received MQTT json payload on channel %s, but downlink is disabled, dropping\n",
sendChannel.settings.name);
}
} else {
LOG_DEBUG("JSON Ignoring downlink message we originally sent.\n");
}
} else if ((json.find("sender") != json.end()) && (json.find("payload") != json.end()) &&
(json.find("type") != json.end()) && json["type"]->IsString() &&
(json["type"]->AsString().compare("sendposition") == 0)) {
// invent the "sendposition" type for a valid envelope
if (json["payload"]->IsObject() && json["type"]->IsString() &&
(json["sender"]->AsString().compare(owner.id) != 0)) {
JSONObject posit;
posit = json["payload"]->AsObject(); // get nested JSON Position
meshtastic_Position pos = meshtastic_Position_init_default;
pos.latitude_i = posit["latitude_i"]->AsNumber();
pos.longitude_i = posit["longitude_i"]->AsNumber();
pos.altitude = posit["altitude"]->AsNumber();
pos.time = posit["time"]->AsNumber();
} else if (json["type"]->AsString().compare("sendposition") == 0 && json["payload"]->IsObject()) {
// invent the "sendposition" type for a valid envelope
JSONObject posit;
posit = json["payload"]->AsObject(); // get nested JSON Position
meshtastic_Position pos = meshtastic_Position_init_default;
if (posit.find("latitude_i") != posit.end() && posit["latitude_i"]->IsNumber())
pos.latitude_i = posit["latitude_i"]->AsNumber();
if (posit.find("longitude_i") != posit.end() && posit["longitude_i"]->IsNumber())
pos.longitude_i = posit["longitude_i"]->AsNumber();
if (posit.find("altitude") != posit.end() && posit["altitude"]->IsNumber())
pos.altitude = posit["altitude"]->AsNumber();
if (posit.find("time") != posit.end() && posit["time"]->IsNumber())
pos.time = posit["time"]->AsNumber();
// construct protobuf data packet using POSITION, send it to the mesh
meshtastic_MeshPacket *p = router->allocForSending();
p->decoded.portnum = meshtastic_PortNum_POSITION_APP;
p->channel = sendChannel.index;
if (sendChannel.settings.downlink_enabled) {
// construct protobuf data packet using POSITION, send it to the mesh
meshtastic_MeshPacket *p = router->allocForSending();
p->decoded.portnum = meshtastic_PortNum_POSITION_APP;
p->channel = sendChannel.index;
if (json.find("to") != json.end() && json["to"]->IsNumber())
p->to = json["to"]->AsNumber();
p->decoded.payload.size =
pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes),
&meshtastic_Position_msg, &pos); // make the Data protobuf from position
service.sendToMesh(p, RX_SRC_LOCAL);
} else {
LOG_WARN("Received MQTT json payload on channel %s, but downlink is disabled, dropping\n",
sendChannel.settings.name);
LOG_DEBUG("JSON Ignoring downlink message with unsupported type.\n");
}
} else {
LOG_DEBUG("JSON Ignoring downlink message we originally sent.\n");
LOG_ERROR("JSON Received payload on MQTT but not a valid envelope.\n");
}
} else {
LOG_ERROR("JSON Received payload on MQTT but not a valid envelope\n");
LOG_WARN("JSON downlink received on channel not called 'mqtt' or without downlink enabled.\n");
}
} else {
// no json, this is an invalid payload
LOG_ERROR("Invalid MQTT service envelope, topic %s, len %u!\n", topic, length);
LOG_ERROR("JSON Received payload on MQTT but not a valid JSON\n");
}
delete json_value;
} else {
if (!pb_decode_from_bytes(payload, length, &meshtastic_ServiceEnvelope_msg, &e)) {
if (length == 0) {
LOG_WARN("Empty MQTT payload received, topic %s!\n", topic);
return;
} else if (!pb_decode_from_bytes(payload, length, &meshtastic_ServiceEnvelope_msg, &e)) {
LOG_ERROR("Invalid MQTT service envelope, topic %s, len %u!\n", topic, length);
return;
} else {
if (strcmp(e.gateway_id, owner.id) == 0)
LOG_INFO("Ignoring downlink message we originally sent.\n");
else {
meshtastic_Channel ch = channels.getByName(e.channel_id);
if (strcmp(e.gateway_id, owner.id) == 0) {
// Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message.
// We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node
// receives it when we get our own packet back. Then we'll stop our retransmissions.
if (e.packet && getFrom(e.packet) == nodeDB.getNodeNum())
routingModule->sendAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index);
else
LOG_INFO("Ignoring downlink message we originally sent.\n");
} else {
// Find channel by channel_id and check downlink_enabled
meshtastic_Channel ch = channels.getByName(e.channel_id);
if (strcmp(e.channel_id, channels.getGlobalId(ch.index)) == 0 && e.packet && ch.settings.downlink_enabled) {
LOG_INFO("Received MQTT topic %s, len=%u\n", topic, length);
meshtastic_MeshPacket *p = packetPool.allocCopy(*e.packet);
@@ -463,7 +461,7 @@ void MQTT::publishQueuedMessages()
}
}
void MQTT::onSend(const meshtastic_MeshPacket &mp, ChannelIndex chIndex)
void MQTT::onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket &mp_decoded, ChannelIndex chIndex)
{
if (mp.via_mqtt)
return; // Don't send messages that came from MQTT back into MQTT
@@ -483,7 +481,13 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, ChannelIndex chIndex)
meshtastic_ServiceEnvelope *env = mqttPool.allocZeroed();
env->channel_id = (char *)channelId;
env->gateway_id = owner.id;
env->packet = (meshtastic_MeshPacket *)&mp;
if (moduleConfig.mqtt.encryption_enabled) {
env->packet = (meshtastic_MeshPacket *)&mp;
} else {
env->packet = (meshtastic_MeshPacket *)&mp_decoded;
}
LOG_DEBUG("MQTT onSend - Publishing portnum %i message\n", env->packet->decoded.portnum);
if (moduleConfig.mqtt.proxy_to_client_enabled || this->isConnectedDirectly()) {
@@ -498,7 +502,7 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, ChannelIndex chIndex)
if (moduleConfig.mqtt.json_enabled) {
// handle json topic
auto jsonString = this->meshPacketToJson((meshtastic_MeshPacket *)&mp);
auto jsonString = this->meshPacketToJson((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(),
@@ -507,11 +511,6 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp, ChannelIndex chIndex)
}
}
// Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message.
// We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node
// receives it when we're connected to the broker. Then we'll stop our retransmissions.
if (getFrom(&mp) == nodeDB.getNodeNum())
routingModule->sendAckNak(meshtastic_Routing_Error_NONE, getFrom(&mp), mp.id, chIndex);
} else {
LOG_INFO("MQTT not connected, queueing packet\n");
if (mqttQueue.numFree() == 0) {
@@ -809,4 +808,14 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
delete value;
return jsonStr;
}
bool MQTT::isValidJsonEnvelope(JSONObject &json)
{
// if "sender" is provided, avoid processing packets we uplinked
return (json.find("sender") != json.end() ? (json["sender"]->AsString().compare(owner.id) != 0) : true) &&
(json.find("from") != json.end()) && json["from"]->IsNumber() &&
(json["from"]->AsNumber() == nodeDB.getNodeNum()) && // only accept message if the "from" is us
(json.find("type") != json.end()) && json["type"]->IsString() && // should specify a type
(json.find("payload") != json.end()); // should have a payload
}

View File

@@ -5,6 +5,7 @@
#include "concurrency/OSThread.h"
#include "mesh/Channels.h"
#include "mesh/generated/meshtastic/mqtt.pb.h"
#include "mqtt/JSON.h"
#if HAS_WIFI
#include <WiFiClient.h>
#define HAS_NETWORKING 1
@@ -48,14 +49,14 @@ class MQTT : private concurrency::OSThread
MQTT();
/**
* Publish a packet on the glboal MQTT server.
* Publish a packet on the global MQTT server.
* This hook must be called **after** the packet is encrypted (including the channel being changed to a hash).
* @param chIndex the index of the channel for this message
*
* Note: for messages we are forwarding on the mesh that we can't find the channel for (because we don't have the keys), we
* can not forward those messages to the cloud - because no way to find a global channel ID.
*/
void onSend(const meshtastic_MeshPacket &mp, ChannelIndex chIndex);
void onSend(const meshtastic_MeshPacket &mp, const meshtastic_MeshPacket &mp_decoded, ChannelIndex chIndex);
/** Attempt to connect to server if necessary
*/
@@ -100,6 +101,9 @@ class MQTT : private concurrency::OSThread
void publishStatus();
void publishQueuedMessages();
// returns true if this is a valid JSON envelope which we accept on downlink
bool isValidJsonEnvelope(JSONObject &json);
/// Return 0 if sleep is okay, veto sleep if we are connected to pubsub server
// int preflightSleepCb(void *unused = NULL) { return pubSub.connected() ? 1 : 0; }
};

View File

@@ -125,6 +125,8 @@
#define HW_VENDOR meshtastic_HardwareModel_SENSELORA_S3
#elif defined(HELTEC_HT62)
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_HT62
#elif defined(CHATTER_2)
#define HW_VENDOR meshtastic_HardwareModel_CHATTER_2
#endif
// -----------------------------------------------------------------------------

View File

@@ -175,7 +175,8 @@ void cpuDeepSleep(uint32_t msecToWake)
some current will flow through these external and internal resistors, increasing deep
sleep current above the minimal possible value.
Note: we don't isolate pins that are used for the LORA, LED, i2c, spi or the wake button
Note: we don't isolate pins that are used for the LORA, LED, i2c, or ST7735 Display for the Chatter2, spi or the wake
button(s), maybe we should not include any other GPIOs...
*/
#if SOC_RTCIO_HOLD_SUPPORTED
static const uint8_t rtcGpios[] = {/* 0, */ 2,
@@ -184,9 +185,9 @@ void cpuDeepSleep(uint32_t msecToWake)
13,
/* 14, */ /* 15, */
#endif
/* 25, */ 26, /* 27, */
32, 33, 34, 35,
36, 37
/* 25, */ /* 26, */ /* 27, */
/* 32, */ /* 33, */ 34, 35,
/* 36, */ 37
/* 38, 39 */};
for (int i = 0; i < sizeof(rtcGpios); i++)

View File

@@ -81,6 +81,7 @@ void portduinoSetup()
YAML::Node yamlConfig;
if (configPath != nullptr) {
std::cout << "Using " << configPath << " as config file" << std::endl;
try {
yamlConfig = YAML::LoadFile(configPath);
} catch (YAML::Exception e) {
@@ -88,6 +89,7 @@ void portduinoSetup()
exit(EXIT_FAILURE);
}
} else if (access("config.yaml", R_OK) == 0) {
std::cout << "Using local config.yaml as config file" << std::endl;
try {
yamlConfig = YAML::LoadFile("config.yaml");
} catch (YAML::Exception e) {
@@ -95,6 +97,7 @@ void portduinoSetup()
exit(EXIT_FAILURE);
}
} else if (access("/etc/meshtasticd/config.yaml", R_OK) == 0) {
std::cout << "Using /etc/meshtasticd/config.yaml as config file" << std::endl;
try {
yamlConfig = YAML::LoadFile("/etc/meshtasticd/config.yaml");
} catch (YAML::Exception e) {
@@ -105,24 +108,21 @@ void portduinoSetup()
std::cout << "No 'config.yaml' found, running simulated." << std::endl;
// Set the random seed equal to TCPPort to have a different seed per instance
randomSeed(TCPPort);
/* Aren't all pins defaulted to simulated?
auto fakeBusy = new SimGPIOPin(SX126X_BUSY, "fakeBusy");
fakeBusy->writePin(LOW);
fakeBusy->setSilent(true);
gpioBind(fakeBusy);
auto cs = new SimGPIOPin(SX126X_CS, "fakeLoraCS");
cs->setSilent(true);
gpioBind(cs);
gpioBind(new SimGPIOPin(SX126X_RESET, "fakeLoraReset"));
gpioBind(new SimGPIOPin(LORA_DIO1, "fakeLoraIrq"));
*/
return;
}
try {
if (yamlConfig["Logging"]) {
if (yamlConfig["Logging"]["LogLevel"].as<std::string>("info") == "debug") {
settingsMap[logoutputlevel] = level_debug;
} else if (yamlConfig["Logging"]["LogLevel"].as<std::string>("info") == "info") {
settingsMap[logoutputlevel] = level_info;
} else if (yamlConfig["Logging"]["LogLevel"].as<std::string>("info") == "warn") {
settingsMap[logoutputlevel] = level_warn;
} else if (yamlConfig["Logging"]["LogLevel"].as<std::string>("info") == "error") {
settingsMap[logoutputlevel] = level_error;
}
}
if (yamlConfig["Lora"]) {
settingsMap[use_sx1262] = false;
settingsMap[use_rf95] = false;
@@ -158,6 +158,9 @@ void portduinoSetup()
settingsMap[has_gps] = 1;
}
}
if (yamlConfig["I2C"]) {
settingsStrings[i2cdev] = yamlConfig["I2C"]["I2CDevice"].as<std::string>("");
}
settingsMap[displayPanel] = no_screen;
if (yamlConfig["Display"]) {
if (yamlConfig["Display"]["Panel"].as<std::string>("") == "ST7789")

View File

@@ -16,6 +16,7 @@ enum configNames {
user,
gpiochip,
spidev,
i2cdev,
has_gps,
touchscreenModule,
touchscreenCS,
@@ -31,10 +32,12 @@ enum configNames {
displayOffsetX,
displayOffsetY,
displayInvert,
keyboardDevice
keyboardDevice,
logoutputlevel
};
enum { no_screen, st7789, st7735, st7735s };
enum { no_touchscreen, xpt2046 };
enum { level_error, level_warn, level_info, level_debug };
extern std::map<configNames, int> settingsMap;
extern std::map<configNames, std::string> settingsStrings;

View File

@@ -0,0 +1,13 @@
; CircuitMess Chatter 2 based on ESP32-WROOM-32 (38 pins) devkit & DeeamLNK DL-LLCC68 or Heltec HT RA62 SX1262/SX1268 module
[env:chatter2]
extends = esp32_base
board = esp32doit-devkit-v1
board_level = extra
build_flags =
${esp32_base.build_flags}
-D CHATTER_2
-I variants/chatter2
lib_deps =
${esp32_base.lib_deps}
lovyan03/LovyanGFX@^1.1.8

118
variants/chatter2/variant.h Normal file
View File

@@ -0,0 +1,118 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Have custom connections or functionality? Configure them in this section //
// //
//////////////////////////////////////////////////////////////////////////////////
// Debugging
// #define GPS_DEBUG
// #define GPS_EXTRAVERBOSE
// Lora
#define USE_LLCC68 // Original Chatter2 with LLCC68 module
#define USE_SX1262 // Added for when Lora module is swapped for HT-RA62
#define SX126X_CS 14 // module's NSS pin
#define LORA_SCK 16 // module's SCK pin
#define LORA_MOSI 5 // module's MOSI pin
#define LORA_MISO 17 // module's MISO pin
#define SX126X_RESET RADIOLIB_NC // module's NRST pin
#define SX126X_BUSY 4 // module's BUSY pin works for both LLCC68 and RA-62 with cut & jumper
#define SX126X_DIO1 18 // module's DIO1 pin
#define SX126X_DIO2_AS_RF_SWITCH // module's DIO2 pin
#define SX126X_DIO3_TCXO_VOLTAGE 1.8 // module's DIO pin
#define SX126X_TXEN RADIOLIB_NC
#define SX126X_RXEN RADIOLIB_NC
// Status
// #define LED_PIN 1
// External notification
// FIXME: Check if EXT_NOTIFY_OUT actualy has any effect and removes the need for setting the external notication pin in the
// app/preferences
// #define EXT_NOTIFY_OUT 2 // The GPIO pin that acts as the external notification output (here we connect an LED to it)
// Buzzer
#define PIN_BUZZER 19
// Buttons
#define BUTTON_PIN 36 // Use the WAKE button as the user button
// I2C
// #define I2C_SCL 27
// #define I2C_SDA 26
#define SX126X_MAX_POWER 22 // SX126xInterface.cpp defaults to 22 if not defined, but here we define it for good practice
// Display
#define HAS_SCREEN 1 // Assume no screen present by default to prevent crash...
// ST7735S TFT LCD
#define ST7735S 1 // there are different (sub-)versions of ST7735
#define ST7735_CS -1
#define ST7735_RS 33 // DC
#define ST7735_SDA 26 // MOSI
#define ST7735_SCK 27
#define ST7735_RESET 15
#define ST7735_MISO -1
#define ST7735_BUSY -1
#define ST7735_BL 32
#define ST7735_SPI_HOST HSPI_HOST // SPI2_HOST for S3, auto may work too
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
#define TFT_HEIGHT 160
#define TFT_WIDTH 128
#define TFT_OFFSET_X 0
#define TFT_OFFSET_Y 0
#define TFT_INVERT false
#define SCREEN_ROTATE
#define SCREEN_TRANSITION_FRAMERATE 5 // fps
#define DISPLAY_FORCE_SMALL_FONTS
// Battery
#define BATTERY_PIN 34 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO34_CHANNEL
#define ADC_ATTENUATION \
ADC_ATTEN_DB_2_5 // 2_5-> 100mv-1250mv, 11-> 150mv-3100mv for ESP32
// ESP32-S2/C3/S3 are different
// lower dB for lower voltage rnage
#define ADC_MULTIPLIER \
5.0 // VBATT---10k--pin34---2.5K---GND
// Chatter2 uses 3 AAA cells
#define BAT_FULLVOLT 4800 // with the 5.0 divider, input to BATTERY_PIN is 900mv
#define BAT_EMPTYVOLT 3300
#undef EXT_PWR_DETECT
// GPS
// FIXME: unsure what to define HAS_GPS as if GPS isn't always present
#define HAS_GPS 1 // Don't need to set this to 0 to prevent a crash as it doesn't crash if GPS not found, will probe by default
// #define PIN_GPS_EN 15
// #define GPS_EN_ACTIVE 1
#undef GPS_TX_PIN
#undef GPS_RX_PIN
#define GPS_TX_PIN 13
#define GPS_RX_PIN 2
/////////////////////////////////////////////////////////////////////////////////
// //
// You should have no need to modify the code below, nor in pins_arduino.h //
// //
/////////////////////////////////////////////////////////////////////////////////
#define LORA_CS SX126X_CS // FIXME: for some reason both are used in /src
// Many of the below values would only be used if USE_RF95 was defined, but it's not as we aren't actually using an RF95, just
// that the 4 pins above are named like it If they aren't used they don't need to be defined and doing so cause confusion to those
// adapting this file LORA_RESET value is never used in src (as we are not using RF95), so no need to define LORA_DIO0 is not used
// in src (as we are not using RF95) as SX1262 does not have it per SX1262 datasheet, so no need to define
// FIXME: confirm that the linked lines below are actually only called when using the SX126x or SX128x and no other modules
// then use SX126X_DIO1 and SX128X_DIO1 respectively for that purpose, removing the need for RF95-style LORA_* definitions when
// the RF95 isn't used
#define LORA_DIO1 \
SX126X_DIO1 // The old name is used in
// https://github.com/meshtastic/firmware/blob/7eff5e7bcb2084499b723c5e3846c15ee089e36d/src/sleep.cpp#L298, so
// must also define the old name
// LORA_DIO2 value is never used in src (as we are not using RF95), so no need to define, and if DIO2_AS_RF_SWITCH is set then it
// cannot serve any extra function even if requested to LORA_DIO3 value is never used in src (as we are not using RF95), so no
// need to define, and DIO3_AS_TCXO_AT_1V8 is set so it cannot serve any extra function even if requested to (from 13.3.2.1
// DioxMask in SX1262 datasheet: Note that if DIO2 or DIO3 are used to control the RF Switch or the TCXO, the IRQ will not be
// generated even if it is mapped to the pins.)

View File

@@ -80,6 +80,7 @@ static const uint8_t A5 = PIN_A5;
// Other pins
#define PIN_AREF PIN_A5
#define PIN_VBAT PIN_A4
#define BATTERY_PIN PIN_VBAT
#define PIN_NFC1 (33)
#define PIN_NFC2 (2)
#define PIN_PIEZO (37)

View File

@@ -100,6 +100,7 @@ static const uint8_t A5 = PIN_A5;
// Other pins
#define PIN_AREF PIN_A5
#define PIN_VBAT PIN_A4
#define BATTERY_PIN PIN_VBAT
#define PIN_NFC1 (33)
#define PIN_NFC2 (2)
#define PIN_PIEZO (37)

View File

@@ -170,7 +170,7 @@ External serial flash W25Q16JV_IQ
// Voltage divider value => 100K + 100K voltage divider on VBAT = (100K / (100K + 100K))
#define VBAT_DIVIDER (0.5F)
// Compensation factor for the VBAT divider
#define VBAT_DIVIDER_COMP (2.0)
#define VBAT_DIVIDER_COMP (2.0F)
// Fixed calculation of milliVolt from compensation value
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
#undef AREF_VOLTAGE

View File

@@ -1,3 +1,2 @@
#define HAS_WIRE 1
#define HAS_SCREEN 1
#define CANNED_MESSAGE_MODULE_ENABLE 1

View File

@@ -56,6 +56,8 @@ static const uint8_t SCK = 33;
#define LED_PIN LED_BLUE
#define PIN_VBAT WB_A0
#define BATTERY_PIN PIN_VBAT
#define ADC_CHANNEL ADC1_GPIO36_CHANNEL
// https://docs.rakwireless.com/Product-Categories/WisBlock/RAK13300/

View File

@@ -10,4 +10,6 @@ build_flags = ${rp2040_base.build_flags}
-DDEBUG_RP2040_PORT=Serial
-L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus"
lib_deps =
${rp2040_base.lib_deps}
${rp2040_base.lib_deps}
debug_build_flags = ${rp2040_base.build_flags}
debug_tool = cmsis-dap ; for e.g. Picotool

View File

@@ -12,6 +12,7 @@
// #define EXT_NOTIFY_OUT 4
#define BATTERY_PIN 26
#define BATTERY_SENSE_RESOLUTION_BITS ADC_RESOLUTION
// ratio of voltage divider = 3.0 (R17=200k, R18=100k)
#define ADC_MULTIPLIER 3.1 // 3.0 + a bit for being optimistic

View File

@@ -254,7 +254,7 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG
// Voltage divider value => 1.5M + 1M voltage divider on VBAT = (1.5M / (1M + 1.5M))
#define VBAT_DIVIDER (0.4F)
// Compensation factor for the VBAT divider
#define VBAT_DIVIDER_COMP (1.73)
#define VBAT_DIVIDER_COMP (1.73F)
// Fixed calculation of milliVolt from compensation value
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
#undef AREF_VOLTAGE

View File

@@ -223,7 +223,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
// Voltage divider value => 1.5M + 1M voltage divider on VBAT = (1.5M / (1M + 1.5M))
#define VBAT_DIVIDER (0.4F)
// Compensation factor for the VBAT divider
#define VBAT_DIVIDER_COMP (1.73)
#define VBAT_DIVIDER_COMP (1.73F)
// Fixed calculation of milliVolt from compensation value
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
#undef AREF_VOLTAGE

View File

@@ -11,4 +11,6 @@ build_flags = ${rp2040_base.build_flags}
-DHW_SPI1_DEVICE
-L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m0plus"
lib_deps =
${rp2040_base.lib_deps}
${rp2040_base.lib_deps}
debug_build_flags = ${rp2040_base.build_flags}
debug_tool = cmsis-dap ; for e.g. Picotool

View File

@@ -22,6 +22,7 @@
#define BATTERY_PIN 26
// ratio of voltage divider = 3.0 (R17=200k, R18=100k)
#define ADC_MULTIPLIER 3.1 // 3.0 + a bit for being optimistic
#define BATTERY_SENSE_RESOLUTION_BITS ADC_RESOLUTION
#define USE_SX1262

View File

@@ -14,4 +14,6 @@ build_flags = ${rp2040_base.build_flags}
build_src_filter = ${rp2040_base.build_src_filter} +<mesh/wifi/>
lib_deps =
${rp2040_base.lib_deps}
${networking_base.lib_deps}
${networking_base.lib_deps}
debug_build_flags = ${rp2040_base.build_flags}
debug_tool = cmsis-dap ; for e.g. Picotool

View File

@@ -24,6 +24,7 @@
#define BATTERY_PIN 26
// ratio of voltage divider = 3.0 (R17=200k, R18=100k)
#define ADC_MULTIPLIER 3.1 // 3.0 + a bit for being optimistic
#define BATTERY_SENSE_RESOLUTION_BITS ADC_RESOLUTION
#define USE_SX1262

View File

@@ -8,6 +8,7 @@
#define LED_PIN PIN_LED
#undef BATTERY_PIN
#define BATTERY_SENSE_RESOLUTION_BITS ADC_RESOLUTION
#undef LORA_SCK
#undef LORA_MISO

View File

@@ -213,7 +213,7 @@ External serial flash WP25R1635FZUIL0
// Voltage divider value => 100K + 100K voltage divider on VBAT = (100K / (100K + 100K))
#define VBAT_DIVIDER (0.5F)
// Compensation factor for the VBAT divider
#define VBAT_DIVIDER_COMP (2.0)
#define VBAT_DIVIDER_COMP (2.0F)
// Fixed calculation of milliVolt from compensation value
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
#undef AREF_VOLTAGE

View File

@@ -16,5 +16,13 @@
#define USE_RF95
#define LORA_DIO0 26 // a No connect on the SX1262 module
#define LORA_RESET 23
// In the T3 V1.6.1 TXCO version, GPIO 33 is connected to Radios
// internal temperature-compensated crystal oscillator enable
#ifdef LORA_TCXO_GPIO
#define LORA_DIO1 RADIOLIB_NC // no-connect on sx127x module
#else
#define LORA_DIO1 33 // https://www.thethingsnetwork.org/forum/t/big-esp32-sx127x-topic-part-3/18436
#endif
#define LORA_DIO2 32 // Not really used

View File

@@ -0,0 +1,9 @@
[env:tlora-v2-1-1_6-tcxo]
extends = esp32_base
board = ttgo-lora32-v21
build_flags =
${esp32_base.build_flags}
-D TLORA_V2_1_16
-I variants/tlora_v2_1_16
-D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
-D LORA_TCXO_GPIO=33

View File

@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 2
build = 19
build = 21