mirror of
https://github.com/meshtastic/firmware.git
synced 2025-09-05 19:19:18 +00:00
Compare commits
4 Commits
b9dd902ee2
...
8cd2a2ae27
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8cd2a2ae27 | ||
![]() |
c5fad6cca1 | ||
![]() |
b8d7222423 | ||
![]() |
5b52fd06b8 |
@ -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";
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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?)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
312
src/modules/SerialPacketModule.cpp
Normal file
312
src/modules/SerialPacketModule.cpp
Normal 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
|
69
src/modules/SerialPacketModule.h
Normal file
69
src/modules/SerialPacketModule.h
Normal 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
|
@ -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
|
||||
|
@ -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_
|
||||
|
Loading…
Reference in New Issue
Block a user