Compare commits

...

4 Commits

Author SHA1 Message Date
Bob Reese
8cd2a2ae27
Merge 5b52fd06b8 into c5fad6cca1 2025-09-02 06:39:43 -05:00
Tom Fifield
c5fad6cca1
Hold for 20s after GPS lock (#7801)
* Hold for >20s after GPS lock

GPS chips are designed to stay locked for a while to download some data and save it.
This data is important for speeding up future locks, and making them higher quality.
Our present configuration could make every lock perform similar to first lock.

This patch sets a hold of between 20s and 10% of the lock search time after lock
is acquired. This should allow the GPS to finish its work before we turn it off.

Fixes https://github.com/meshtastic/firmware/issues/7466

* Remove T1000E-specific GPS holds

The new code does the same thing, for all devices.

* Fix publishing settings

* Cleanups, removing unused variables.

* ifdef log line with GPS_DEBUG

* fixQual is not a bool.
2025-09-02 06:05:14 -05:00
Jason P
b8d7222423
If usePreset is False, show value as Custom (#7812) 2025-09-02 05:55:57 -05:00
Bob Reese
5b52fd06b8 Changes for serialpacket module 2025-09-01 09:16:36 -05:00
15 changed files with 440 additions and 68 deletions

View File

@ -1,7 +1,14 @@
#include "DisplayFormatters.h"
const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName)
const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName,
bool usePreset)
{
// If use_preset is false, always return "Custom"
if (!usePreset) {
return "Custom";
}
switch (preset) {
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO:
return useShortName ? "ShortT" : "ShortTurbo";

View File

@ -4,5 +4,6 @@
class DisplayFormatters
{
public:
static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName);
static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName,
bool usePreset);
};

View File

@ -429,6 +429,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MESHTASTIC_EXCLUDE_WAYPOINT 1
#define MESHTASTIC_EXCLUDE_INPUTBROKER 1
#define MESHTASTIC_EXCLUDE_SERIAL 1
#define MESHTASTIC_EXCLUDE_SERIALPACKET 1
#define MESHTASTIC_EXCLUDE_POWERSTRESS 1
#define MESHTASTIC_EXCLUDE_ADMIN 1
#endif

View File

@ -843,9 +843,6 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
setPowerPMU(true); // Power (PMU): on
writePinStandby(false); // Standby (pin): awake (not standby)
setPowerUBLOX(true); // Standby (UBLOX): awake
#ifdef GNSS_AIROHA
lastFixStartMsec = 0;
#endif
break;
case GPS_SOFTSLEEP:
@ -863,9 +860,7 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
writePinStandby(true); // Standby (pin): asleep (not awake)
setPowerUBLOX(false, sleepTime); // Standby (UBLOX): asleep, timed
#ifdef GNSS_AIROHA
if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) {
digitalWrite(PIN_GPS_EN, LOW);
}
digitalWrite(PIN_GPS_EN, LOW);
#endif
break;
@ -877,9 +872,7 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime)
writePinStandby(true); // Standby (pin): asleep
setPowerUBLOX(false, 0); // Standby (UBLOX): asleep, indefinitely
#ifdef GNSS_AIROHA
if (config.position.gps_update_interval * 1000 >= GPS_FIX_HOLD_TIME * 2) {
digitalWrite(PIN_GPS_EN, LOW);
}
digitalWrite(PIN_GPS_EN, LOW);
#endif
break;
}
@ -1062,6 +1055,8 @@ void GPS::down()
}
// If update interval long enough (or softsleep unsupported): hardsleep instead
setPowerState(GPS_HARDSLEEP, sleepTime);
// Reset the fix quality to 0, since we're off.
fixQual = 0;
}
}
@ -1121,11 +1116,19 @@ int32_t GPS::runOnce()
shouldPublish = true;
}
uint8_t prev_fixQual = fixQual;
bool gotLoc = lookForLocation();
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
LOG_DEBUG("hasValidLocation RISING EDGE");
hasValidLocation = true;
shouldPublish = true;
// Hold for 20secs after getting a lock to download ephemeris etc
fixHoldEnds = millis() + 20000;
}
if (gotLoc && prev_fixQual == 0) { // just got a lock after turning back on.
fixHoldEnds = millis() + 20000;
shouldPublish = true; // Publish immediately, since next publish is at end of hold
}
bool tooLong = scheduling.searchedTooLong();
@ -1134,8 +1137,7 @@ int32_t GPS::runOnce()
// Once we get a location we no longer desperately want an update
if ((gotLoc && gotTime) || tooLong) {
if (tooLong) {
if (tooLong && !gotLoc) {
// we didn't get a location during this ack window, therefore declare loss of lock
if (hasValidLocation) {
LOG_DEBUG("hasValidLocation FALLING EDGE");
@ -1143,9 +1145,15 @@ int32_t GPS::runOnce()
p = meshtastic_Position_init_default;
hasValidLocation = false;
}
down();
shouldPublish = true; // publish our update for this just finished acquisition window
if (millis() > fixHoldEnds) {
shouldPublish = true; // publish our update at the end of the lock hold
publishUpdate();
down();
#ifdef GPS_DEBUG
} else {
LOG_DEBUG("Holding for GPS data download: %d ms (numSats=%d)", fixHoldEnds - millis(), p.sats_in_view);
#endif
}
}
// If state has changed do a publish
@ -1508,24 +1516,6 @@ static int32_t toDegInt(RawDegrees d)
*/
bool GPS::lookForTime()
{
#ifdef GNSS_AIROHA
uint8_t fix = reader.fixQuality();
if (fix >= 1 && fix <= 5) {
if (lastFixStartMsec > 0) {
if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
return false;
} else {
clearBuffer();
}
} else {
lastFixStartMsec = millis();
return false;
}
} else {
return false;
}
#endif
auto ti = reader.time;
auto d = reader.date;
if (ti.isValid() && d.isValid()) { // Note: we don't check for updated, because we'll only be called if needed
@ -1564,25 +1554,6 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
*/
bool GPS::lookForLocation()
{
#ifdef GNSS_AIROHA
if ((config.position.gps_update_interval * 1000) >= (GPS_FIX_HOLD_TIME * 2)) {
uint8_t fix = reader.fixQuality();
if (fix >= 1 && fix <= 5) {
if (lastFixStartMsec > 0) {
if (Throttle::isWithinTimespanMs(lastFixStartMsec, GPS_FIX_HOLD_TIME)) {
return false;
} else {
clearBuffer();
}
} else {
lastFixStartMsec = millis();
return false;
}
} else {
return false;
}
}
#endif
// By default, TinyGPS++ does not parse GPGSA lines, which give us
// the 2D/3D fixType (see NMEAGPS.h)
// At a minimum, use the fixQuality indicator in GPGGA (FIXME?)

View File

@ -159,7 +159,7 @@ class GPS : private concurrency::OSThread
uint8_t fixType = 0; // fix type from GPGSA
#endif
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0;
uint32_t fixHoldEnds = 0;
uint32_t rx_gpio = 0;
uint32_t tx_gpio = 0;

View File

@ -263,12 +263,6 @@ void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t
display->drawString(x + 1, y, "USB");
}
// auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, true);
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
// if (config.display.heading_bold)
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode) - 1, y, mode);
uint32_t currentMillis = millis();
uint32_t seconds = currentMillis / 1000;
uint32_t minutes = seconds / 60;
@ -398,7 +392,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
display->drawString(nameX, getTextPositions(display)[line++], shortnameble);
// === Second Row: Radio Preset ===
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
char regionradiopreset[25];
const char *region = myRegion ? myRegion->name : NULL;
if (region != nullptr) {

View File

@ -368,7 +368,7 @@ const char *Channels::getName(size_t chIndex)
// Per mesh.proto spec, if bandwidth is specified we must ignore modemPreset enum, we assume that in that case
// the app effed up and forgot to set channelSettings.name
if (config.lora.use_preset) {
channelName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
channelName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
} else {
channelName = "Custom";
}
@ -382,7 +382,8 @@ bool Channels::isDefaultChannel(ChannelIndex chIndex)
const auto &ch = getByIndex(chIndex);
if (ch.settings.psk.size == 1 && ch.settings.psk.bytes[0] == 1) {
const char *name = getName(chIndex);
const char *presetName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
const char *presetName =
DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
// Check if the name is the default derived from the modem preset
if (strcmp(name, presetName) == 0)
return true;

View File

@ -589,7 +589,8 @@ void RadioInterface::applyModemConfig()
// Check if we use the default frequency slot
RadioInterface::uses_default_frequency_slot =
channel_num == hash(DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false)) % numChannels;
channel_num ==
hash(DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset)) % numChannels;
// Old frequency selection formula
// float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num);

View File

@ -14,6 +14,9 @@
#if !MESHTASTIC_EXCLUDE_MQTT
#include "mqtt/MQTT.h"
#endif
#if !MESHTASTIC_EXCLUDE_SERIALPACKET
#include "modules/SerialPacketModule.h"
#endif
#include "Default.h"
#if ARCH_PORTDUINO
#include "platform/portduino/PortduinoGlue.h"
@ -292,6 +295,11 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
#endif
packetPool.release(p_decoded);
}
#if !MESHTASTIC_EXCLUDE_SERIALPACKET
if (serialPacketEnabled){
serialPacketModule->onSend(*p);
}
#endif
#if HAS_UDP_MULTICAST
if (udpHandler && config.network.enabled_protocols & meshtastic_Config_NetworkConfig_ProtocolFlags_UDP_BROADCAST) {

View File

@ -868,6 +868,8 @@ typedef struct _meshtastic_MeshPacket {
meshtastic_MeshPacket_Delayed delayed;
/* Describes whether this packet passed via MQTT somewhere along the path it currently took. */
bool via_mqtt;
/* Describes whether this packet entered the radio via the serial packet link. Not sent over links */
bool via_slink;
/* Hop limit with which the original packet started. Sent via LoRa using three bits in the unencrypted header.
When receiving a packet, the difference between hop_start and hop_limit gives how many hops it traveled. */
uint8_t hop_start;

View File

@ -98,6 +98,10 @@
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !MESHTASTIC_EXCLUDE_SERIAL
#include "modules/SerialModule.h"
#endif
#endif
#if defined(ARCH_NRF52) && !MESHTASTIC_EXCLUDE_SERIALPACKET
#include "modules/SerialPacketModule.h"
#endif
#if !MESHTASTIC_EXCLUDE_DROPZONE
@ -254,6 +258,9 @@ void setupModules()
}
#endif
#endif
#if defined(ARCH_NRF52) && !MESHTASTIC_EXCLUDE_SERIALPACKET
new SerialPacketModule();
#endif
#ifdef ARCH_ESP32
// Only run on an esp32 based device.
#if defined(USE_SX1280) && !MESHTASTIC_EXCLUDE_AUDIO

View File

@ -0,0 +1,312 @@
#include "SerialPacketModule.h"
#include "GeoCoord.h"
#include "MeshService.h"
#include "NMEAWPL.h"
#include "NodeDB.h"
#include "RTC.h"
#include "Router.h"
#include "configuration.h"
#include <Arduino.h>
#include <Throttle.h>
/*
This module implements a serial link for Meshtastic packets.
This has been tested with the WisMesh starter kit (19007 board+ RAK4630) + RS485 (RAK5802), CPU is the NRF52840
This combination uses UART2_RX(P0.15)/UART2_TX(P0.16) on the RAK4630.
Arduino Serial1 is used in this module for the StreamAPI serial driver
The RS485 serial link is used as an alternative path for packets (similar to mqtt)
1. Any packet that comes in via wireless is sent out via RS485 (if the packet is rebroadcast)
2. Any packet that comes in via RS485 serial link is sent out wireless
3. Any packet that came in via RS485 serial link is never rebroadcast back to the serial link
A Meshtastic packet sent over the serial link is wrapped in a header with magic numbers and a CRC.
Incoming packets that fail magic number match or CRC check are discarded.
This has been tested with RS485 links in excess of 1 km @4800 baud.
Complete testing results is at: https://github.com/rbreesems/flamingo
This module does NOT have any module config data yet, so the serialPacketEnabled byte
below is used for enable/disable, this module is DISABLED by default.
Also, the module currently uses the Baud rate setting from the serial module.
You need to be careful of conflicts between this module and the GPS, Serial modules.
The GPS module for the NRF52840 by default uses Serial1. So, if there is a GPS module, but
it does not use the serial uart pins required by this RS485 interface, you could change this code
to use Serial2.
However, the Serial module uses the Serial2 StreamAPI serial driver, so, if you change this code to use Serial2, you
would need to disable the serial module (or change the serial module to use Serial1).
If you use this module and the Serial module, be careful that the Serial module UART pin configuration does
not clash with the pin configuration assumed in this module.
Assuming that you have two setups of (19007 board+ 4630) + RS485 (RAK5802) connected together
(RS485 A wire to A wire, B wire to B wire), the easiest way to test is by doing the following:
a. Have both Radios configured with Lora Transmit enabled on both.
b. Connect your phone to Radio1 , verify that a DM to Radio2 is received/acked.
c. Disable Lora transmit on Radio1.
d. Send a DM to Radio2 - this should be received/acked and as the packet will go via the RS485 link. If this fails, then
something is wrong with your serial link -either a wire connection, or a failure in the RS485 module(s)
e. Assuming success from step (d), disconnect one of the wires
f. Send a DM to Radio2 - this should time out with max transmissions reached as there is no transmit path for the packet.
g. Reconnect the wire, and verify that sending another DM to Radio2 works.
*/
#if defined(ARCH_NRF52)
#define TIMEOUT 250
#define BAUD 19200
// defined as UART2 TX/RX on 4630
// This is what is connected on WisMesh starter kit (19007 board+ 4630) + RS485 (RAK5802)
#define RS485_TXPIN 16
#define RS485_RXPIN 15
#define PACKET_FLAGS_ENCRYPTED_MASK 0x20
SerialPacketModule *serialPacketModule;
meshtastic_serialPacket outPacket;
meshtastic_serialPacket inPacket;
#ifdef SLINK_DEBUG
char tmpbuf[250]; // for debug only
#endif
// since we do not have module config data for this yet, need to put enable byte here
// DISABLED BY DEFAULT
#define SERIAL_PACKET_ENABLED 0
bool serialPacketEnabled = SERIAL_PACKET_ENABLED;
SerialPacketModule::SerialPacketModule() : StreamAPI(&Serial1), concurrency::OSThread("SerialPacket") {}
#define headerByte1 0xaa
#define headerByte2 0x55
size_t serialPacketPayloadSize;
uint32_t computeCrc32(const uint8_t* buf, uint16_t len) {
uint32_t crc = 0xFFFFFFFF; // Initial value
const uint32_t poly = 0xEDB88320; // CRC-32 polynomial
for (uint16_t i = 0; i < len; i++) {
crc ^= (uint8_t)buf[i]; // XOR with the current byte
for (int j = 7; j >= 0; j--) { // Perform 8 bitwise operations
if (crc & 0x80000000) { // Check if the MSB is set
crc = (crc << 1) ^ poly; // Shift and XOR with polynomial
} else {
crc <<= 1; // Shift if MSB is not set
}
}
}
return ~crc; // Return the final CRC value
}
void meshPacketToSerialPacket (const meshtastic_MeshPacket &mp, meshtastic_serialPacket *sp) {
sp->header.hbyte1 = headerByte1;
sp->header.hbyte2 = headerByte2;
sp->header.crc = 0;
if (mp.which_payload_variant == meshtastic_MeshPacket_encrypted_tag ){
sp->header.size = sizeof(SerialPacketHeader) + mp.encrypted.size;
memcpy(sp->payload, mp.encrypted.bytes, mp.encrypted.size);
} else {
sp->header.size = sizeof(SerialPacketHeader) + mp.decoded.payload.size;
memcpy(sp->payload, mp.decoded.payload.bytes, mp.decoded.payload.size);
}
sp->header.from = mp.from;
sp->header.to = mp.to;
sp->header.id = mp.id;
sp->header.channel = mp.channel;
sp->header.hop_limit = mp.hop_limit & PACKET_FLAGS_HOP_LIMIT_MASK;
sp->header.hop_start = mp.hop_start & PACKET_FLAGS_HOP_START_MASK;
sp->header.flags =
0x00 |
(mp.want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0) |
(mp.via_mqtt ? PACKET_FLAGS_VIA_MQTT_MASK : 0) |
((mp.which_payload_variant == meshtastic_MeshPacket_encrypted_tag) ? PACKET_FLAGS_ENCRYPTED_MASK : 0);
sp->header.crc = computeCrc32((const uint8_t *)sp, sp->header.size);
}
void insertSerialPacketToMesh(meshtastic_serialPacket *sp) {
UniquePacketPoolPacket p = packetPool.allocUniqueZeroed();
p->from = sp->header.from;
p->to = sp->header.to;
p->id = sp->header.id;
p->channel = sp->header.channel;
p->hop_limit = sp->header.hop_limit;
p->hop_start = sp->header.hop_start;
p->want_ack = !!(sp->header.flags & PACKET_FLAGS_WANT_ACK_MASK);
p->via_slink = true;
p->via_mqtt = !!(sp->header.flags & PACKET_FLAGS_VIA_MQTT_MASK);
uint16_t payloadLen = sp->header.size - sizeof(SerialPacketHeader);
if (!!(sp->header.flags & PACKET_FLAGS_ENCRYPTED_MASK)) {
p->which_payload_variant = meshtastic_MeshPacket_encrypted_tag;
memcpy(p->encrypted.bytes, sp->payload, payloadLen);
p->encrypted.size = payloadLen;
} else {
p->which_payload_variant = meshtastic_MeshPacket_decoded_tag;
memcpy(p->decoded.payload.bytes, sp->payload, payloadLen);
p->decoded.payload.size = payloadLen;
}
LOG_DEBUG ("SerialPacketModule:: RX from=0x%0x, to=0x%0x, packet_id=0x%0x",
p->from, p->to, p->id);
#ifdef SLINK_DEBUG
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
memcpy(tmpbuf, p->decoded.payload.bytes, p->decoded.payload.size);
tmpbuf[p->decoded.payload.size+1]=0;
LOG_DEBUG("SerialPacketModule:: RX packet of %d bytes, msg: %s", sp->header.size, tmpbuf);
}
#endif
router->enqueueReceivedMessage(p.release());
}
// check if this recieved serial packet is valid
bool checkIfValidSerialPacket(meshtastic_serialPacket *sp) {
if (sp->header.hbyte1 != headerByte1 || sp->header.hbyte2 != headerByte2 ) {
LOG_DEBUG("SerialPacketModule:: valid packet check fail, header bytes");
return false;
}
if (sp->header.size == 0 || sp->header.size > sizeof(meshtastic_serialPacket)) {
LOG_DEBUG("SerialPacketModule:: valid packet check fail, invalid size");
return false;
}
uint32_t received_crc = sp->header.crc;
sp->header.crc = 0; // need to set to zero for computing CRC
if (computeCrc32((const uint8_t *)sp, sp->header.size) != received_crc) {
LOG_DEBUG("SerialPacketModule:: valid packet check fail, invalid crc");
sp->header.crc = received_crc; // restore
return false;
}
sp->header.crc = received_crc; // restore
return true;
}
int32_t SerialPacketModule::runOnce()
{
if (!serialPacketEnabled)
return disable();
if (firstTime) {
// Interface with the serial peripheral from in here.
LOG_INFO("SerialPacketModule:: Init serial interface");
uint32_t baud = getBaudRate();
Serial1.setPins(RS485_RXPIN, RS485_TXPIN);
Serial1.begin(baud, SERIAL_8N1);
Serial1.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
firstTime = 0;
} else {
//stream.cpp/readBytes arduinofruit library
while (Serial1.available()) {
serialPacketPayloadSize = Serial1.readBytes((uint8_t *) &inPacket, sizeof(meshtastic_serialPacket));
if (!checkIfValidSerialPacket(&inPacket)) {
LOG_DEBUG("SerialPacketModule:: failed CRC on RX");
} else {
// checks passed, pass this packet on
LOG_DEBUG("SerialPacketModule:: RX Insert packet to mesh");
insertSerialPacketToMesh(&inPacket);
}
}
}
return (50);
}
/**
* @brief Checks if the serial connection is established.
*
* @return true if the serial connection is established, false otherwise.
*
*/
bool SerialPacketModule::checkIsConnected()
{
// we are not going to be able to determine if connected to another radio or not
// at the end of the serial, just always return true
return true;
}
/*
Called from Router.cpp/Router::send
Send this over the serial link
*/
void SerialPacketModule::onSend(const meshtastic_MeshPacket &mp) {
if (mp.via_slink) {
LOG_DEBUG("SerialPacketModule:: Onsend TX - ignoring packet that came from slink");
}
LOG_DEBUG("SerialPacketModule:: Onsend TX from=0x%0x, to=0x%0x, packet_id=0x%0x",
mp.from, mp.to, mp.id);
meshPacketToSerialPacket(mp, &outPacket);
// debug check
if (!checkIfValidSerialPacket(&outPacket)) {
LOG_DEBUG("SerialPacketModule:: failed CRC on TX");
} else {
if (Serial1.availableForWrite()) {
LOG_DEBUG("SerialPacketModule:: onSend TX packet of %d bytes", outPacket.header.size);
Serial1.write((uint8_t *) &outPacket, outPacket.header.size);
}
}
}
/**
* @brief Returns the baud rate of the serial module from the module configuration.
*
* @return uint32_t The baud rate of the serial module.
*/
uint32_t SerialPacketModule::getBaudRate()
{
if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_110) {
return 110;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_300) {
return 300;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_600) {
return 600;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_1200) {
return 1200;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_2400) {
return 2400;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_4800) {
return 4800;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_9600) {
return 9600;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_19200) {
return 19200;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_38400) {
return 38400;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_57600) {
return 57600;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_115200) {
return 115200;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_230400) {
return 230400;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_460800) {
return 460800;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_576000) {
return 576000;
} else if (moduleConfig.serial.baud == meshtastic_ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600) {
return 921600;
}
return BAUD;
}
#endif

View File

@ -0,0 +1,69 @@
#pragma once
#include "MeshModule.h"
#include "Router.h"
#include "SinglePortModule.h"
#include "concurrency/OSThread.h"
#include "configuration.h"
#include <Arduino.h>
#include <functional>
#if defined(ARCH_NRF52)
extern bool serialPacketEnabled;
/**
* Header for wrapper around Meshtastic packet data sent over the serial link
**/
typedef struct _SerialPacketHeader{
uint8_t hbyte1; //magic number for early rejection
uint8_t hbyte2; //magic number for early rejection
uint16_t size; //this is size of header + payload length
uint32_t crc;
NodeNum to, from; // can be 1 byte or four bytes
PacketId id; // can be 1 byte or 4 bytes
/**
* This flag bytes holds 3 flags from original Meshtastic flags - want_ack, via_mqtt, is_encrypted
**/
uint8_t flags;
/** The channel hash - used as a hint for the decoder to limit which channels we consider */
uint8_t channel;
uint8_t hop_limit;
uint8_t hop_start;
} SerialPacketHeader;
typedef struct _meshtastic_serialPacket{
SerialPacketHeader header;
uint8_t payload[256]; // 256 is max payload size
} meshtastic_serialPacket;
class SerialPacketModule : public StreamAPI, private concurrency::OSThread
{
bool firstTime = 1;
public:
SerialPacketModule();
void onSend(const meshtastic_MeshPacket &mp);
protected:
virtual int32_t runOnce() override;
/// Check the current underlying physical link to see if the client is currently connected
virtual bool checkIsConnected() override;
private:
uint32_t getBaudRate();
};
extern SerialPacketModule *serialPacketModule;
#endif

View File

@ -124,8 +124,7 @@ extern "C" {
#define GPS_RTC_INT (0 + 15) // P0.15, normal is LOW, wake by HIGH
#define GPS_RESETB_OUT (32 + 14) // P1.14, always input pull_up
#define GPS_FIX_HOLD_TIME 15000 // ms
#define BATTERY_PIN 2 // P0.02/AIN0, BAT_ADC
#define BATTERY_PIN 2 // P0.02/AIN0, BAT_ADC
#define BATTERY_IMMUTABLE
#define ADC_MULTIPLIER (2.0F)
// P0.04/AIN2 is VCC_ADC, P0.05/AIN3 is CHARGER_DET, P1.03 is CHARGE_STA, P1.04 is CHARGE_DONE

View File

@ -123,7 +123,6 @@ extern "C" {
#define GPS_RESETB_OUT (32 + 14) // P1.14, awlays input pull_up
// #define GPS_THREAD_INTERVAL 50
#define GPS_FIX_HOLD_TIME 15000 // ms
#define BATTERY_PIN 2
// #define ADC_CHANNEL ADC1_GPIO2_CHANNEL
@ -157,4 +156,4 @@ extern "C" {
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
#endif // _VARIANT_WIO_SDK_WM1110_
#endif // _VARIANT_WIO_SDK_WM1110_