Compare commits

..

31 Commits

Author SHA1 Message Date
Ben Meadors
d490a332a7 Update version.properties 2024-05-02 19:11:35 -05:00
todd-herbert
5dfa4b837f Ensure LED is off when disabling heartbeat (#3772) 2024-05-02 19:11:13 -05:00
github-actions[bot]
9501f3bda9 [create-pull-request] automated change (#3771)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-05-02 16:17:41 -05:00
Jonathan Bennett
b69a1cada9 Portduino bump to pick up minor fix (#3770) 2024-05-02 13:54:50 -05:00
Jonathan Bennett
06e7d2b845 Track actual GPIO values, not just the enum values (#3768)
* Track actual GPIO values, not just the enum values

* trunk
2024-05-02 13:39:28 -05:00
Oliver Seiler
71400103b3 set USB_CDC_ON_BOOT, udate arduinoespressif32 to 2.0.15 (#3764) 2024-05-02 13:39:18 -05:00
Thomas Göttgens
40e361e6d0 Merge pull request #3763 from lewisxhe/master
Fix t-echo gps failure
2024-05-02 15:13:43 +02:00
lewisxhe
d1b6f11429 Fix t-echo gps failure 2024-05-02 14:39:58 +02:00
todd-herbert
0527fb10ce Init. battery voltage from ADC reading, instead of fixed value (#3761) 2024-05-02 07:14:44 -05:00
Andrew Yong
5f929a8024 Publish fixed position updates and consider changes in only altitude as an updated point (#3758)
* AdminModule: Publish fixed position updates

Enabled GPS thread when fixed position is updated, to let the GPS thread run once and publish the new fixed position.

Signed-off-by: Andrew Yong <me@ndoo.sg>

* GPS: Consider changes in only altitude as an updated point

Signed-off-by: Andrew Yong <me@ndoo.sg>

---------

Signed-off-by: Andrew Yong <me@ndoo.sg>
2024-05-02 07:13:36 -05:00
Thomas Göttgens
4f54862d63 Merge pull request #3765 from meshtastic/twc-mesh-buildfix
fix building new TWC_mesh_v4 board
2024-05-02 13:30:49 +02:00
Thomas Göttgens
0f4ac94559 fix building new TWC_mesh_v4 board 2024-05-02 12:48:50 +02:00
Jonathan Bennett
45c1b46bd0 Move native to spi_host to indicate spidev for LovyanGFX 2024-05-01 13:21:23 -05:00
Jonathan Bennett
5095efc55f Pick up support for more than 64 GPIO lines under Portduino 2024-05-01 13:21:23 -05:00
Ben Meadors
ec92f7a5a3 Remove phone nodenum warning and empty else clause (#3756) 2024-05-01 08:27:43 -05:00
Ben Meadors
57da37cfbc Position module should enforce precision for phone originated position packets (#3752) 2024-05-01 08:05:26 -05:00
github-actions[bot]
3619ac87b8 [create-pull-request] automated change (#3754)
Co-authored-by: thebentern <thebentern@users.noreply.github.com>
2024-04-30 20:14:38 -05:00
GUVWAF
e51ee91c39 Optimization: stop relaying when reply is received (#3753) 2024-04-30 20:07:15 -05:00
todd-herbert
21311bbeda T-Echo touch button no longer requires "wake on tap or motion" (#3745) 2024-04-29 08:54:57 -05:00
Andrew Yong
18e69a0906 Update Heltec HT-C62 variant based on HT-DEV-ESP board (#3731)
* I2C is not defined in the reference schematic nor HT-DEV-ESP board, remove definition accordingly
* There is no screen in the the reference schematic nor HT-DEV-ESP board, change definition accordingly
* BUTTON_PIN has a 10 kOhm pullup resistor on HT-DEV-ESP, turning off redundant internal pullup should save some power
* LED is connected to GPIO2 on HT-DEV-ESP and is not inverted, update definition accordingly
* Remove redundant undef lines for LoRa pins

Above changes were built and flashed to my [HT-DEV-ESP_V2 board purchased from Heltec's Taobao store](https://item.taobao.com/item.htm?id=521590063077).

Signed-off-by: Andrew Yong <me@ndoo.sg>
2024-04-28 06:49:26 -05:00
David Ellefsen
93f77ea7d2 Update TinyGPSPlus version (#3727)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-27 19:50:15 -05:00
Mike
ee4c4ae6c9 Allow setting hopLimit for MQTT json sendtext and sendposition (#3735)
* Fix channel name extraction

* Allow setting hopLimit for mqtt sendtext and sendposition
2024-04-27 18:15:54 -05:00
Ben Meadors
6cc7dee95c Tradunkadunk 2024-04-27 11:12:52 -05:00
HarukiToreda
38c4d35a7b Add Notification on device screen following feature toggle (#3627)
* Update CannedMessageModule.h

* Update CannedMessageModule.cpp

* Update CannedMessageModule.cpp

hopefully this fixes the errors on Trunk

* Update CannedMessageModule.cpp

Changed "Ping Broadcasted" with "Telemetry Update Sent"

* tryfix: disable tempmessage again after 2 seconds

* fix 2s showtime

* Put spelling fix back

* Fix build

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2024-04-27 11:08:25 -05:00
Ben Meadors
e683d8f552 Rebrand "send network ping" to more honest "try send position" with better output (#3737) 2024-04-27 08:55:04 -05:00
jcyrio
e66aec8223 fix typo in comment (#3726) 2024-04-27 08:54:06 -05:00
Oliver Seiler
a06a01d25e fix #if HAS_TELEMETRY when set to 0 (#3733) 2024-04-27 06:35:44 -05:00
Andrew Yong
f8c3f43ea6 Fix xiao_ble variant build error due to undefined BATTERY_SENSE_RESOLUTION_BITS (#3732)
Define BATTERY_SENSE_RESOLUTION_BITS based on [amoroz's snippet on the Meshtastic forum](https://meshtastic.discourse.group/t/new-1w-diy-variant-xiao-nrf52840-ebyte-e22-900m30s/7904/10).

Fixes following build error:

```
src/Power.cpp: In member function 'virtual uint16_t AnalogBatteryLevel::getBattVoltage()':
src/Power.cpp:224:79: error: 'BATTERY_SENSE_RESOLUTION_BITS' was not declared in this scope
             scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
```

Signed-off-by: Andrew Yong <me@ndoo.sg>
2024-04-27 06:17:17 -05:00
todd-herbert
dfcabba0b2 Prevent overflow when calculating timezones (#3730) 2024-04-26 20:43:09 -05:00
Thomas Göttgens
827bacdfc8 Merge pull request #3723 from meshtastic/create-pull-request/patch
Changes by create-pull-request action
2024-04-25 23:46:43 +02:00
thebentern
5806a266d3 [create-pull-request] automated change 2024-04-25 20:19:54 +00:00
31 changed files with 202 additions and 105 deletions

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#659e49346aa33008b150dfb206b1817ddabc7132
platform = https://github.com/meshtastic/platform-native.git#9881bf3721d610cccacf5ae8e3a07839cce75d63
framework = arduino
build_src_filter =
@@ -24,7 +24,7 @@ lib_deps =
${env.lib_deps}
${networking_base.lib_deps}
rweather/Crypto@^0.4.0
https://github.com/lovyan03/LovyanGFX.git#d35e60f269dfecbb18a8cb0fd07d594c2fb7e7a8
https://github.com/lovyan03/LovyanGFX.git#5a39989aa2c9492572255b22f033843ec8900233
build_flags =
${arduino_base.build_flags}
@@ -34,4 +34,4 @@ build_flags =
-DPORTDUINO_LINUX_HARDWARE
-lbluetooth
-lgpiod
-lyaml-cpp
-lyaml-cpp

View File

@@ -7,6 +7,7 @@
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DLILYGO_TBEAM_S3_CORE",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"

View File

@@ -78,7 +78,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#964f75a72cccd6b53cd74e4add1f7a42c6f7344d
https://github.com/meshtastic/TinyGPSPlus.git#71a82db35f3b973440044c476d4bcdc673b104f4
https://github.com/meshtastic/ArduinoThread.git#1ae8778c85d0a2a729f989e0b1e7d7c4dc84eef0
nanopb/Nanopb@^0.4.7
erriez/ErriezCRC32@^1.0.1

View File

@@ -136,9 +136,12 @@ int32_t ButtonThread::runOnce()
case BUTTON_EVENT_DOUBLE_PRESSED: {
LOG_BUTTON("Double press!\n");
service.refreshLocalMeshNode();
service.sendNetworkPing(NODENUM_BROADCAST, true);
auto sentPosition = service.trySendPosition(NODENUM_BROADCAST, true);
if (screen) {
screen->print("Sent ad-hoc ping\n");
if (sentPosition)
screen->print("Sent ad-hoc position\n");
else
screen->print("Sent ad-hoc nodeinfo\n");
screen->forceDisplay(true); // Force a new UI frame, then force an EInk update
}
break;
@@ -193,15 +196,13 @@ int32_t ButtonThread::runOnce()
#ifdef BUTTON_PIN_TOUCH
case BUTTON_EVENT_TOUCH_LONG_PRESSED: {
LOG_BUTTON("Touch press!\n");
if (config.display.wake_on_tap_or_motion) {
if (screen) {
// Wake if asleep
if (powerFSM.getState() == &stateDARK)
powerFSM.trigger(EVENT_PRESS);
if (screen) {
// Wake if asleep
if (powerFSM.getState() == &stateDARK)
powerFSM.trigger(EVENT_PRESS);
// Update display (legacy behaviour)
screen->forceDisplay();
}
// Update display (legacy behaviour)
screen->forceDisplay();
}
break;
}

View File

@@ -184,7 +184,7 @@ class AnalogBatteryLevel : public HasBatteryLevel
virtual uint16_t getBattVoltage() override
{
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU)
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO) && !defined(HAS_PMU)
if (hasINA()) {
LOG_DEBUG("Using INA on I2C addr 0x%x for device battery voltage\n", config.power.device_battery_ina_address);
return getINAVoltage();
@@ -223,7 +223,17 @@ class AnalogBatteryLevel : public HasBatteryLevel
raw = raw / BATTERY_SENSE_SAMPLES;
scaled = operativeAdcMultiplier * ((1000 * AREF_VOLTAGE) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * raw;
#endif
last_read_value += (scaled - last_read_value) * 0.5; // Virtual LPF
if (!initial_read_done) {
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
if (scaled > last_read_value)
last_read_value = scaled;
initial_read_done = true;
} else {
// Already initialized - filter this reading
last_read_value += (scaled - last_read_value) * 0.5; // Virtual LPF
}
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u filtered=%u\n", BATTERY_PIN, raw, (uint32_t)(scaled), (uint32_t)
// (last_read_value));
}
@@ -357,10 +367,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
const float noBatVolt = (OCV[NUM_OCV_POINTS - 1] - 500) * NUM_CELLS;
// Start value from minimum voltage for the filter to not start from 0
// that could trigger some events.
// This value is over-written by the first ADC reading, it the voltage seems reasonable.
bool initial_read_done = false;
float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS);
uint32_t last_read_time_ms = 0;
#if defined(HAS_TELEMETRY) && !defined(ARCH_PORTDUINO)
#if HAS_TELEMETRY && !defined(ARCH_PORTDUINO)
uint16_t getINAVoltage()
{
if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) {

View File

@@ -1467,7 +1467,7 @@ bool GPS::lookForLocation()
#endif // GPS_EXTRAVERBOSE
// Is this a new point or are we re-reading the previous one?
if (!reader.location.isUpdated())
if (!reader.location.isUpdated() && !reader.altitude.isUpdated())
return false;
// check if a complete GPS solution set is available for reading

View File

@@ -223,7 +223,7 @@ int32_t getTZOffset()
now = time(NULL);
gmt = gmtime(&now);
gmt->tm_isdst = -1;
return (int16_t)difftime(now, mktime(gmt));
return (int32_t)difftime(now, mktime(gmt));
}
/**

View File

@@ -356,7 +356,7 @@ class LGFX : public lgfx::LGFX_Device
_panel_instance = new lgfx::Panel_ILI9341;
auto buscfg = _bus_instance.config();
buscfg.spi_mode = 0;
_bus_instance.spi_device(DisplaySPI);
buscfg.spi_host = settingsMap[displayspidev];
buscfg.pin_dc = settingsMap[displayDC]; // Set SPI DC pin number (-1 = disable)
@@ -397,6 +397,8 @@ class LGFX : public lgfx::LGFX_Device
touch_cfg.offset_rotation = 1;
if (settingsMap[touchscreenI2CAddr] != -1) {
touch_cfg.i2c_addr = settingsMap[touchscreenI2CAddr];
} else {
touch_cfg.spi_host = settingsMap[touchscreenspidev];
}
_touch_instance->config(touch_cfg);

View File

@@ -693,6 +693,12 @@ void setup()
// Now that the mesh service is created, create any modules
setupModules();
#ifdef LED_PIN
// Turn LED off after boot, if heartbeat by config
if (config.device.led_heartbeat_disabled)
digitalWrite(LED_PIN, LOW ^ LED_INVERTED);
#endif
// Do this after service.init (because that clears error_code)
#ifdef HAS_PMU
if (!pmu_found)
@@ -729,7 +735,7 @@ void setup()
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(*LoraSPI, spiSettings);
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
rIf = new SX1262Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
@@ -743,7 +749,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(*LoraSPI, spiSettings);
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
rIf = new RF95Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
@@ -758,7 +764,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(*LoraSPI, spiSettings);
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
rIf = new SX1280Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {
@@ -773,7 +779,7 @@ void setup()
} else if (settingsMap[use_sx1268]) {
if (!rIf) {
LOG_DEBUG("Attempting to activate sx1268 radio on SPI port %s\n", settingsStrings[spidev].c_str());
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(*LoraSPI, spiSettings);
LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings);
rIf = new SX1268Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset],
settingsMap[busy]);
if (!rIf->init()) {

View File

@@ -35,11 +35,10 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p)
void FloodingRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtastic_Routing *c)
{
bool isAck =
((c && c->error_reason == meshtastic_Routing_Error_NONE)); // consider only ROUTING_APP message without error as ACK
if (isAck && p->to != getNodeNum()) {
// do not flood direct message that is ACKed
LOG_DEBUG("Receiving an ACK not for me, but don't need to rebroadcast this direct message anymore.\n");
bool isAckorReply = (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) && (p->decoded.request_id != 0);
if (isAckorReply && p->to != getNodeNum() && p->to != NODENUM_BROADCAST) {
// do not flood direct message that is ACKed or replied to
LOG_DEBUG("Receiving an ACK or reply not for me, but don't need to rebroadcast this direct message anymore.\n");
Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM
}
if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) {

View File

@@ -193,10 +193,7 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
}
#endif
if (p.from != 0) { // We don't let phones assign nodenums to their sent messages
LOG_WARN("phone tried to pick a nodenum, we don't allow that.\n");
p.from = 0;
} else {
// p.from = nodeDB->getNodeNum();
}
if (p.id == 0)
@@ -267,7 +264,7 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh
}
}
void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
bool MeshService::trySendPosition(NodeNum dest, bool wantReplies)
{
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum());
@@ -278,6 +275,7 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
if (positionModule) {
LOG_INFO("Sending position ping to 0x%x, wantReplies=%d, channel=%d\n", dest, wantReplies, node->channel);
positionModule->sendOurPosition(dest, wantReplies, node->channel);
return true;
}
} else {
#endif
@@ -286,6 +284,7 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
nodeInfoModule->sendOurNodeInfo(dest, wantReplies, node->channel);
}
}
return false;
}
void MeshService::sendToPhone(meshtastic_MeshPacket *p)

View File

@@ -108,8 +108,9 @@ class MeshService
void reloadOwner(bool shouldSave = true);
/// Called when the user wakes up our GUI, normally sends our latest location to the mesh (if we have it), otherwise at least
/// sends our owner
void sendNetworkPing(NodeNum dest, bool wantReplies = false);
/// sends our nodeinfo
/// returns true if we sent a position
bool trySendPosition(NodeNum dest, bool wantReplies = false);
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb

View File

@@ -352,9 +352,6 @@ void NodeDB::installDefaultModuleConfig()
moduleConfig.external_notification.alert_message = true;
moduleConfig.external_notification.output_ms = 100;
moduleConfig.external_notification.active = true;
#endif
#ifdef TTGO_T_ECHO
config.display.wake_on_tap_or_motion = true; // Enable touch button for screen-on / refresh
#endif
moduleConfig.has_canned_message = true;

View File

@@ -55,7 +55,7 @@ extern const pb_msgdesc_t meshtastic_ChannelSet_msg;
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_APPONLY_PB_H_MAX_SIZE meshtastic_ChannelSet_size
#define meshtastic_ChannelSet_size 658
#define meshtastic_ChannelSet_size 674
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -34,6 +34,9 @@ typedef enum _meshtastic_Channel_Role {
typedef struct _meshtastic_ModuleSettings {
/* Bits of precision for the location sent in position packets. */
uint32_t position_precision;
/* Controls whether or not the phone / clients should mute the current channel
Useful for noisy public channels you don't necessarily want to disable */
bool is_client_muted;
} meshtastic_ModuleSettings;
typedef PB_BYTES_ARRAY_T(32) meshtastic_ChannelSettings_psk_t;
@@ -126,14 +129,15 @@ extern "C" {
/* Initializer values for message structs */
#define meshtastic_ChannelSettings_init_default {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_default}
#define meshtastic_ModuleSettings_init_default {0}
#define meshtastic_ModuleSettings_init_default {0, 0}
#define meshtastic_Channel_init_default {0, false, meshtastic_ChannelSettings_init_default, _meshtastic_Channel_Role_MIN}
#define meshtastic_ChannelSettings_init_zero {0, {0, {0}}, "", 0, 0, 0, false, meshtastic_ModuleSettings_init_zero}
#define meshtastic_ModuleSettings_init_zero {0}
#define meshtastic_ModuleSettings_init_zero {0, 0}
#define meshtastic_Channel_init_zero {0, false, meshtastic_ChannelSettings_init_zero, _meshtastic_Channel_Role_MIN}
/* Field tags (for use in manual encoding/decoding) */
#define meshtastic_ModuleSettings_position_precision_tag 1
#define meshtastic_ModuleSettings_is_client_muted_tag 2
#define meshtastic_ChannelSettings_channel_num_tag 1
#define meshtastic_ChannelSettings_psk_tag 2
#define meshtastic_ChannelSettings_name_tag 3
@@ -159,7 +163,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, module_settings, 7)
#define meshtastic_ChannelSettings_module_settings_MSGTYPE meshtastic_ModuleSettings
#define meshtastic_ModuleSettings_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, position_precision, 1)
X(a, STATIC, SINGULAR, UINT32, position_precision, 1) \
X(a, STATIC, SINGULAR, BOOL, is_client_muted, 2)
#define meshtastic_ModuleSettings_CALLBACK NULL
#define meshtastic_ModuleSettings_DEFAULT NULL
@@ -182,9 +187,9 @@ extern const pb_msgdesc_t meshtastic_Channel_msg;
/* Maximum encoded size of messages (where known) */
#define MESHTASTIC_MESHTASTIC_CHANNEL_PB_H_MAX_SIZE meshtastic_Channel_size
#define meshtastic_ChannelSettings_size 70
#define meshtastic_Channel_size 85
#define meshtastic_ModuleSettings_size 6
#define meshtastic_ChannelSettings_size 72
#define meshtastic_Channel_size 87
#define meshtastic_ModuleSettings_size 8
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -306,7 +306,7 @@ extern const pb_msgdesc_t meshtastic_OEMStore_msg;
/* Maximum encoded size of messages (where known) */
/* meshtastic_DeviceState_size depends on runtime parameters */
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_OEMStore_size
#define meshtastic_ChannelFile_size 702
#define meshtastic_ChannelFile_size 718
#define meshtastic_NodeInfoLite_size 166
#define meshtastic_OEMStore_size 3346
#define meshtastic_PositionLite_size 28

View File

@@ -23,6 +23,10 @@
#include "mqtt/MQTT.h"
#endif
#if !MESHTASTIC_EXCLUDE_GPS
#include "GPS.h"
#endif
AdminModule *adminModule;
bool hasOpenEditTransaction;
@@ -217,6 +221,10 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
nodeDB->setLocalPosition(r->set_fixed_position);
config.position.fixed_position = true;
saveChanges(SEGMENT_DEVICESTATE | SEGMENT_CONFIG, false);
#if !MESHTASTIC_EXCLUDE_GPS
if (gps != nullptr)
gps->enable();
#endif
}
break;
}

View File

@@ -233,14 +233,16 @@ int32_t CannedMessageModule::runOnce()
{
if (((!moduleConfig.canned_message.enabled) && !CANNED_MESSAGE_MODULE_ENABLE) ||
(this->runState == CANNED_MESSAGE_RUN_STATE_DISABLED) || (this->runState == CANNED_MESSAGE_RUN_STATE_INACTIVE)) {
temporaryMessage = "";
return INT32_MAX;
}
// LOG_DEBUG("Check status\n");
UIFrameEvent e = {false, true};
if ((this->runState == CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE) ||
(this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED)) {
// TODO: might have some feedback of sendig state
(this->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) || (this->runState == CANNED_MESSAGE_RUN_STATE_MESSAGE)) {
// TODO: might have some feedback of sending state
this->runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
temporaryMessage = "";
e.frameChanged = true;
this->currentMessageIndex = -1;
this->freetext = ""; // clear freetext
@@ -434,7 +436,7 @@ int32_t CannedMessageModule::runOnce()
}
if (screen)
screen->forceDisplay();
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
showTemporaryMessage("GPS Toggled");
break;
// mute (switch off/toggle) external notifications on fn+m
@@ -442,18 +444,21 @@ int32_t CannedMessageModule::runOnce()
if (moduleConfig.external_notification.enabled == true) {
if (externalNotificationModule->getMute()) {
externalNotificationModule->setMute(false);
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
showTemporaryMessage("Notifications \nEnabled");
} else {
externalNotificationModule->stopNow(); // this will turn off all GPIO and sounds and idle the loop
externalNotificationModule->setMute(true);
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
showTemporaryMessage("Notifications \nDisabled");
}
}
break;
case 0xaf: // fn+space send network ping like double press does
service.refreshLocalMeshNode();
service.sendNetworkPing(NODENUM_BROADCAST, true);
runState = CANNED_MESSAGE_RUN_STATE_INACTIVE;
if (service.trySendPosition(NODENUM_BROADCAST, true)) {
showTemporaryMessage("Position \nUpdate Sent");
} else {
showTemporaryMessage("Node Info \nUpdate Sent");
}
break;
default:
if (this->cursor == this->freetext.length()) {
@@ -542,12 +547,27 @@ int CannedMessageModule::getPrevIndex()
return this->currentMessageIndex - 1;
}
}
void CannedMessageModule::showTemporaryMessage(const String &message)
{
temporaryMessage = message;
UIFrameEvent e = {false, true};
e.frameChanged = true;
notifyObservers(&e);
runState = CANNED_MESSAGE_RUN_STATE_MESSAGE;
// run this loop again in 2 seconds, next iteration will clear the display
setIntervalFromNow(2000);
}
void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
char buffer[50];
if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) {
if (temporaryMessage.length() != 0) {
LOG_DEBUG("Drawing temporary message: %s", temporaryMessage.c_str());
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
display->drawString(display->getWidth() / 2 + x, 0 + y + 12, temporaryMessage);
} else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED) {
display->setTextAlignment(TEXT_ALIGN_CENTER);
display->setFont(FONT_MEDIUM);
String displayString;
@@ -766,4 +786,4 @@ String CannedMessageModule::drawWithCursor(String text, int cursor)
return result;
}
#endif
#endif

View File

@@ -10,6 +10,7 @@ enum cannedMessageModuleRunState {
CANNED_MESSAGE_RUN_STATE_FREETEXT,
CANNED_MESSAGE_RUN_STATE_SENDING_ACTIVE,
CANNED_MESSAGE_RUN_STATE_ACK_NACK_RECEIVED,
CANNED_MESSAGE_RUN_STATE_MESSAGE,
CANNED_MESSAGE_RUN_STATE_ACTION_SELECT,
CANNED_MESSAGE_RUN_STATE_ACTION_UP,
CANNED_MESSAGE_RUN_STATE_ACTION_DOWN,
@@ -51,6 +52,8 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
void handleGetCannedMessageModuleMessages(const meshtastic_MeshPacket &req, meshtastic_AdminMessage *response);
void handleSetCannedMessageModuleMessages(const char *from_msg);
void showTemporaryMessage(const String &message);
String drawWithCursor(String text, int cursor);
/*
@@ -112,7 +115,8 @@ class CannedMessageModule : public SinglePortModule, public Observable<const UIF
char *messages[CANNED_MESSAGE_MODULE_MESSAGE_MAX_COUNT];
int messagesCount = 0;
unsigned long lastTouchMillis = 0;
String temporaryMessage;
};
extern CannedMessageModule *cannedMessageModule;
#endif
#endif

View File

@@ -87,6 +87,23 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
return false; // Let others look at this message also if they want
}
void PositionModule::alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_Position *p)
{
// Phone position packets need to be truncated to the channel precision
if (nodeDB->getNodeNum() == getFrom(&mp) && (precision < 32 && precision > 0)) {
LOG_DEBUG("Truncating phone position to channel precision %i\n", precision);
p->latitude_i = p->latitude_i & (UINT32_MAX << (32 - precision));
p->longitude_i = p->longitude_i & (UINT32_MAX << (32 - precision));
// We want the imprecise position to be the middle of the possible location, not
p->latitude_i += (1 << (31 - precision));
p->longitude_i += (1 << (31 - precision));
mp.decoded.payload.size =
pb_encode_to_bytes(mp.decoded.payload.bytes, sizeof(mp.decoded.payload.bytes), &meshtastic_Position_msg, p);
}
}
void PositionModule::trySetRtc(meshtastic_Position p, bool isLocal)
{
struct timeval tv;

View File

@@ -42,6 +42,8 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
*/
virtual bool handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Position *p) override;
virtual void alterReceivedProtobuf(meshtastic_MeshPacket &mp, meshtastic_Position *p) override;
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
* so that subclasses can (optionally) send a response back to the original sender. */
virtual meshtastic_MeshPacket *allocReply() override;

View File

@@ -54,9 +54,9 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
JSONObject json;
json = json_value->AsObject();
// parse the channel name from the topic string by looking for "json/"
const char *jsonSlash = "json/";
char *ptr = strstr(topic, jsonSlash) + sizeof(jsonSlash) + 1; // set pointer to after "json/"
// parse the channel name from the topic string
// the topic has been checked above for having jsonTopic prefix, so just move past it
char *ptr = topic + jsonTopic.length();
ptr = strtok(ptr, "/") ? strtok(ptr, "/") : ptr; // if another "/" was added, parse string up to that character
meshtastic_Channel sendChannel = channels.getByName(ptr);
// We allow downlink JSON packets only on a channel named "mqtt"
@@ -76,6 +76,8 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
p->channel = json["channel"]->AsNumber();
if (json.find("to") != json.end() && json["to"]->IsNumber())
p->to = json["to"]->AsNumber();
if (json.find("hopLimit") != json.end() && json["hopLimit"]->IsNumber())
p->hop_limit = json["hopLimit"]->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();
@@ -105,6 +107,8 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
p->channel = json["channel"]->AsNumber();
if (json.find("to") != json.end() && json["to"]->IsNumber())
p->to = json["to"]->AsNumber();
if (json.find("hopLimit") != json.end() && json["hopLimit"]->IsNumber())
p->hop_limit = json["hopLimit"]->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
@@ -907,6 +911,7 @@ 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("hopLimit") != json.end() ? json["hopLimit"]->IsNumber() : true) && // hop limit should be a number
(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

View File

@@ -15,8 +15,6 @@
#include <map>
#include <unistd.h>
HardwareSPI *DisplaySPI;
HardwareSPI *LoraSPI;
std::map<configNames, int> settingsMap;
std::map<configNames, std::string> settingsStrings;
char *configPath = nullptr;
@@ -76,7 +74,21 @@ void portduinoCustomInit()
void portduinoSetup()
{
printf("Setting up Meshtastic on Portduino...\n");
gpioInit();
int max_GPIO = 0;
configNames GPIO_lines[] = {cs,
irq,
busy,
reset,
txen,
rxen,
displayDC,
displayCS,
displayBacklight,
displayBacklightPWMChannel,
displayReset,
touchscreenCS,
touchscreenIRQ,
user};
std::string gpioChipName = "gpiochip";
settingsStrings[i2cdev] = "";
@@ -159,6 +171,15 @@ void portduinoSetup()
gpioChipName += std::to_string(settingsMap[gpiochip]);
settingsStrings[spidev] = "/dev/" + yamlConfig["Lora"]["spidev"].as<std::string>("spidev0.0");
if (settingsStrings[spidev].length() == 14) {
int x = settingsStrings[spidev].at(11) - '0';
int y = settingsStrings[spidev].at(13) - '0';
if (x >= 0 && x < 10 && y >= 0 && y < 10) {
settingsMap[spidev] = x + y << 4;
settingsMap[displayspidev] = settingsMap[spidev];
settingsMap[touchscreenspidev] = settingsMap[spidev];
}
}
}
if (yamlConfig["GPIO"]) {
settingsMap[user] = yamlConfig["GPIO"]["User"].as<int>(RADIOLIB_NC);
@@ -208,6 +229,14 @@ void portduinoSetup()
settingsMap[displayBusFrequency] = yamlConfig["Display"]["BusFrequency"].as<int>(40000000);
if (yamlConfig["Display"]["spidev"]) {
settingsStrings[displayspidev] = "/dev/" + yamlConfig["Display"]["spidev"].as<std::string>("spidev0.1");
if (settingsStrings[displayspidev].length() == 14) {
int x = settingsStrings[displayspidev].at(11) - '0';
int y = settingsStrings[displayspidev].at(13) - '0';
if (x >= 0 && x < 10 && y >= 0 && y < 10) {
settingsMap[displayspidev] = x + y << 4;
settingsMap[touchscreenspidev] = settingsMap[displayspidev];
}
}
}
}
settingsMap[touchscreenModule] = no_touchscreen;
@@ -227,6 +256,13 @@ void portduinoSetup()
settingsMap[touchscreenI2CAddr] = yamlConfig["Touchscreen"]["I2CAddr"].as<int>(-1);
if (yamlConfig["Touchscreen"]["spidev"]) {
settingsStrings[touchscreenspidev] = "/dev/" + yamlConfig["Touchscreen"]["spidev"].as<std::string>("");
if (settingsStrings[touchscreenspidev].length() == 14) {
int x = settingsStrings[touchscreenspidev].at(11) - '0';
int y = settingsStrings[touchscreenspidev].at(13) - '0';
if (x >= 0 && x < 10 && y >= 0 && y < 10) {
settingsMap[touchscreenspidev] = x + y << 4;
}
}
}
}
if (yamlConfig["Input"]) {
@@ -245,6 +281,13 @@ void portduinoSetup()
exit(EXIT_FAILURE);
}
for (configNames i : GPIO_lines) {
if (settingsMap[i] > max_GPIO)
max_GPIO = settingsMap[i];
}
gpioInit(max_GPIO + 1); // Done here so we can inform Portduino how many GPIOs we need.
// Need to bind all the configured GPIO pins so they're not simulated
if (settingsMap.count(cs) > 0 && settingsMap[cs] != RADIOLIB_NC) {
if (initGPIOPin(settingsMap[cs], gpioChipName) != ERRNO_OK) {
@@ -298,27 +341,9 @@ void portduinoSetup()
if (settingsMap[touchscreenIRQ] > 0)
initGPIOPin(settingsMap[touchscreenIRQ], gpioChipName);
}
// if we specify a touchscreen dev, that is SPI.
// else if we specify a screen dev, that is SPI
// else if we specify a LoRa dev, that is SPI.
if (settingsStrings[touchscreenspidev] != "") {
SPI.begin(settingsStrings[touchscreenspidev].c_str());
DisplaySPI = new HardwareSPI;
DisplaySPI->begin(settingsStrings[displayspidev].c_str());
LoraSPI = new HardwareSPI;
LoraSPI->begin(settingsStrings[spidev].c_str());
} else if (settingsStrings[displayspidev] != "") {
SPI.begin(settingsStrings[displayspidev].c_str());
DisplaySPI = &SPI;
LoraSPI = new HardwareSPI;
LoraSPI->begin(settingsStrings[spidev].c_str());
} else {
if (settingsStrings[spidev] != "") {
SPI.begin(settingsStrings[spidev].c_str());
LoraSPI = &SPI;
DisplaySPI = &SPI;
}
return;
}

View File

@@ -56,6 +56,4 @@ enum { level_error, level_warn, level_info, level_debug };
extern std::map<configNames, int> settingsMap;
extern std::map<configNames, std::string> settingsStrings;
int initGPIOPin(int pinNum, std::string gpioChipname);
extern HardwareSPI *DisplaySPI;
extern HardwareSPI *LoraSPI;
int initGPIOPin(int pinNum, std::string gpioChipname);

View File

@@ -1,6 +1,6 @@
[env:TWC_mesh_v4]
extends = nrf52840_base
board = TWC_mesh_v4
board = nordic_pca10059
board_level = extra
build_flags = ${nrf52840_base.build_flags} -I variants/TWC_mesh_v4 -D TWC_mesh_v4 -L".pio\libdeps\TWC_mesh_v4\BSEC2 Software Library\src\cortex-m4\fpv4-sp-d16-hard"
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/TWC_mesh_v4>

View File

@@ -1,24 +1,16 @@
#define I2C_SDA 1
#define I2C_SCL 0
#define BUTTON_PIN 9
#define BUTTON_NEED_PULLUP
// LED flashes brighter
// LED pin on HT-DEV-ESP_V2 and HT-DEV-ESP_V3
// https://resource.heltec.cn/download/HT-CT62/HT-CT62_Reference_Design.pdf
#define LED_PIN 18 // LED
#define LED_INVERTED 1
// https://resource.heltec.cn/download/HT-DEV-ESP/HT-DEV-ESP_V3_Sch.pdf
#define LED_PIN 2 // LED
#define LED_INVERTED 0
#define HAS_SCREEN 1
#define HAS_SCREEN 0
#define HAS_GPS 0
#undef GPS_RX_PIN
#undef GPS_TX_PIN
#undef LORA_SCK
#undef LORA_MISO
#undef LORA_MOSI
#undef LORA_CS
#define USE_SX1262
#define LORA_SCK 10
#define LORA_MISO 6

View File

@@ -131,7 +131,7 @@ External serial flash WP25R1635FZUIL0
// Note DIO2 is attached internally to the module to an analog switch for TX/RX switching
#define SX1262_DIO3 \
(0 + 21) // This is used as an *output* from the sx1262 and connected internally to power the tcxo, do not drive from the main
// CPU?
// CPU?
#define SX126X_BUSY (0 + 17)
#define SX126X_RESET (0 + 25)
// Not really an E22 but TTGO seems to be trying to clone that
@@ -177,13 +177,13 @@ External serial flash WP25R1635FZUIL0
#define PIN_GPS_STANDBY (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake
// Seems to be missing on this new board
// #define PIN_GPS_PPS (32 + 4) // Pulse per second input from the GPS
#define PIN_GPS_TX (32 + 9) // This is for bits going TOWARDS the CPU
#define PIN_GPS_RX (32 + 8) // This is for bits going TOWARDS the GPS
#define GPS_TX_PIN (32 + 9) // This is for bits going TOWARDS the CPU
#define GPS_RX_PIN (32 + 8) // This is for bits going TOWARDS the GPS
#define GPS_THREAD_INTERVAL 50
#define PIN_SERIAL1_RX PIN_GPS_TX
#define PIN_SERIAL1_TX PIN_GPS_RX
#define PIN_SERIAL1_RX GPS_TX_PIN
#define PIN_SERIAL1_TX GPS_RX_PIN
// PCF8563 RTC Module
#define PCF8563_RTC 0x51

View File

@@ -3,6 +3,8 @@
extends = esp32s3_base
board = tbeam-s3-core
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.15
lib_deps =
${esp32s3_base.lib_deps}
lewisxhe/PCF8563_Library@1.0.1

View File

@@ -181,6 +181,7 @@ static const uint8_t SCL = PIN_WIRE_SCL;
#define BAT_READ \
14 // P0_14 = 14 Reads battery voltage from divider on signal board. (PIN_VBAT is reading voltage divider on XIAO and is
// program pin 32 / or P0.31)
#define BATTERY_SENSE_RESOLUTION_BITS 10
#define CHARGE_LED 23 // P0_17 = 17 D23 YELLOW CHARGE LED
#define HICHG 22 // P0_13 = 13 D22 Charge-select pin for Lipo for 100 mA instead of default 50mA charge

View File

@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 3
build = 7
build = 8