mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-23 09:06:02 +00:00
Release Develop to Master
This commit is contained in:
parent
d0243d2cd0
commit
14be4ee9f0
47
boards/tlora-t3s3-v1.json
Normal file
47
boards/tlora-t3s3-v1.json
Normal file
@ -0,0 +1,47 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"ldscript": "esp32s3_out.ld"
|
||||
},
|
||||
"core": "esp32",
|
||||
"extra_flags": [
|
||||
"-DLILYGO_T3S3_V1",
|
||||
"-DARDUINO_USB_CDC_ON_BOOT=1",
|
||||
"-DARDUINO_USB_MODE=0",
|
||||
"-DARDUINO_RUNNING_CORE=1",
|
||||
"-DARDUINO_EVENT_RUNNING_CORE=1"
|
||||
],
|
||||
"f_cpu": "240000000L",
|
||||
"f_flash": "80000000L",
|
||||
"flash_mode": "dio",
|
||||
"hwids": [
|
||||
[
|
||||
"0X303A",
|
||||
"0x1001"
|
||||
]
|
||||
],
|
||||
"mcu": "esp32s3",
|
||||
"variant": "tlora-t3s3-v1"
|
||||
},
|
||||
"connectivity": [
|
||||
"wifi"
|
||||
],
|
||||
"debug": {
|
||||
"openocd_target": "esp32s3.cfg"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino",
|
||||
"espidf"
|
||||
],
|
||||
"name": "LilyGo TLora-T3S3-V1",
|
||||
"upload": {
|
||||
"flash_size": "4MB",
|
||||
"maximum_ram_size": 327680,
|
||||
"maximum_size": 4194304,
|
||||
"wait_for_upload_port": true,
|
||||
"require_upload_port": true,
|
||||
"speed": 921600
|
||||
},
|
||||
"url": "http://www.lilygo.cn/",
|
||||
"vendor": "LilyGo"
|
||||
}
|
@ -65,7 +65,8 @@ lib_deps =
|
||||
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
|
||||
nanopb/Nanopb@^0.4.6
|
||||
erriez/ErriezCRC32@^1.0.1
|
||||
jgromes/RadioLib@^5.5.0
|
||||
; jgromes/RadioLib@^5.5.1
|
||||
https://github.com/jgromes/RadioLib.git#395844922c5d88d5db0481a9c91479931172428d
|
||||
|
||||
; Used for the code analysis in PIO Home / Inspect
|
||||
check_tool = cppcheck
|
||||
@ -81,6 +82,7 @@ framework = arduino
|
||||
lib_deps =
|
||||
${env.lib_deps}
|
||||
mprograms/QMC5883LCompass@^1.1.1
|
||||
end2endzone/NonBlockingRTTTL@^1.3.0
|
||||
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#52b5282639d08a8cbd4b748363089eed6102dc76
|
||||
|
||||
build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0
|
||||
|
@ -327,9 +327,7 @@ void PowerFSM_setup()
|
||||
powerFSM.add_timed_transition(&stateON, &stateDARK, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout");
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
|
||||
State *lowPowerState = &stateLS;
|
||||
|
||||
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
|
||||
|
||||
// See: https://github.com/meshtastic/firmware/issues/1071
|
||||
|
@ -25,7 +25,7 @@ void consolePrintf(const char *format, ...)
|
||||
#endif
|
||||
}
|
||||
|
||||
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
||||
SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), concurrency::OSThread("SerialConsole")
|
||||
{
|
||||
assert(!console);
|
||||
console = this;
|
||||
@ -46,6 +46,10 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
|
||||
emitRebooted();
|
||||
}
|
||||
|
||||
int32_t SerialConsole::runOnce()
|
||||
{
|
||||
return runOncePart();
|
||||
}
|
||||
|
||||
// For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages
|
||||
bool SerialConsole::checkIsConnected()
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs
|
||||
* (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs).
|
||||
*/
|
||||
class SerialConsole : public StreamAPI, public RedirectablePrint
|
||||
class SerialConsole : public StreamAPI, public RedirectablePrint, private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
SerialConsole();
|
||||
@ -24,6 +24,8 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
|
||||
return RedirectablePrint::write(c);
|
||||
}
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
protected:
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
|
@ -35,7 +35,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "mesh/Channels.h"
|
||||
#include "mesh/generated/deviceonly.pb.h"
|
||||
#include "modules/TextMessageModule.h"
|
||||
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
#include "utils.h"
|
||||
@ -1071,7 +1071,13 @@ int32_t Screen::runOnce()
|
||||
handleSetOn(false);
|
||||
break;
|
||||
case Cmd::ON_PRESS:
|
||||
handleOnPress();
|
||||
// If a nag notification is running, stop it
|
||||
if (externalNotificationModule->nagCycleCutoff != UINT32_MAX) {
|
||||
externalNotificationModule->stopNow();
|
||||
} else {
|
||||
// Don't advance the screen if we just wanted to switch off the nag notification
|
||||
handleOnPress();
|
||||
}
|
||||
break;
|
||||
case Cmd::START_BLUETOOTH_PIN_SCREEN:
|
||||
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
|
||||
@ -1400,7 +1406,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
||||
display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
|
||||
// Draw our hardware ID to assist with bluetooth pairing. Either prefix with Info or S&F Logo
|
||||
if (moduleConfig.store_forward.enabled) {
|
||||
#if 0
|
||||
#ifdef ARCH_ESP32
|
||||
if (millis() - storeForwardModule->lastHeartbeat > (storeForwardModule->heartbeatInterval * 1200)) { //no heartbeat, overlap a bit
|
||||
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
|
||||
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgQuestionL1);
|
||||
|
12
src/main.cpp
12
src/main.cpp
@ -242,7 +242,6 @@ void setup()
|
||||
digitalWrite(PIN_3V3_EN, 1);
|
||||
#endif
|
||||
|
||||
|
||||
// Currently only the tbeam has a PMU
|
||||
// PMU initialization needs to be placed before scanI2Cdevice
|
||||
power = new Power();
|
||||
@ -462,17 +461,6 @@ if((config.lora.region == Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLo
|
||||
}
|
||||
}
|
||||
|
||||
if((config.lora.region != Config_LoRaConfig_RegionCode_LORA_24) && (rIf->wideLora())){
|
||||
DEBUG_MSG("Warning: Radio chip only supports 2.4GHz LoRa. Adjusting Region.\n");
|
||||
config.lora.region = Config_LoRaConfig_RegionCode_LORA_24;
|
||||
nodeDB.saveToDisk(SEGMENT_CONFIG);
|
||||
if(!rIf->reconfigure()) {
|
||||
DEBUG_MSG("Reconfigure failed, rebooting\n");
|
||||
screen->startRebootScreen();
|
||||
rebootAtMsec = millis() + 5000;
|
||||
}
|
||||
}
|
||||
|
||||
#if HAS_WIFI || HAS_ETHERNET
|
||||
mqttInit();
|
||||
#endif
|
||||
|
@ -17,7 +17,7 @@ ErrorCode FloodingRouter::send(MeshPacket *p)
|
||||
return Router::send(p);
|
||||
}
|
||||
|
||||
bool FloodingRouter::shouldFilterReceived(MeshPacket *p)
|
||||
bool FloodingRouter::shouldFilterReceived(const MeshPacket *p)
|
||||
{
|
||||
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
|
||||
printPacket("Ignoring incoming msg, because we've already seen it", p);
|
||||
@ -34,7 +34,8 @@ void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
|
||||
// do not flood direct message that is ACKed
|
||||
DEBUG_MSG("Receiving an ACK 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
|
||||
} else if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) {
|
||||
}
|
||||
if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) {
|
||||
if (p->id != 0) {
|
||||
if (config.device.role != Config_DeviceConfig_Role_CLIENT_MUTE) {
|
||||
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
|
||||
|
@ -51,7 +51,7 @@ class FloodingRouter : public Router, protected PacketHistory
|
||||
* Called immedately on receiption, before any further processing.
|
||||
* @return true to abandon the packet
|
||||
*/
|
||||
virtual bool shouldFilterReceived(MeshPacket *p) override;
|
||||
virtual bool shouldFilterReceived(const MeshPacket *p) override;
|
||||
|
||||
/**
|
||||
* Look for broadcasts we need to rebroadcast
|
||||
|
@ -44,11 +44,11 @@ MeshPacket *MeshModule::allocAckNak(Routing_Error err, NodeNum to, PacketId idFr
|
||||
// auto p = allocDataProtobuf(c);
|
||||
MeshPacket *p = router->allocForSending();
|
||||
p->decoded.portnum = PortNum_ROUTING_APP;
|
||||
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), Routing_fields, &c);
|
||||
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &Routing_msg, &c);
|
||||
|
||||
p->priority = MeshPacket_Priority_ACK;
|
||||
|
||||
p->hop_limit = 0; // Assume just immediate neighbors for now
|
||||
p->hop_limit = config.lora.hop_limit; // Flood ACK back to original sender
|
||||
p->to = to;
|
||||
p->decoded.request_id = idFrom;
|
||||
p->channel = chIndex;
|
||||
|
@ -401,7 +401,7 @@ bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_
|
||||
void NodeDB::loadFromDisk()
|
||||
{
|
||||
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
|
||||
if (!loadProto(prefFileName, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate)) {
|
||||
if (!loadProto(prefFileName, DeviceState_size, sizeof(DeviceState), &DeviceState_msg, &devicestate)) {
|
||||
installDefaultDeviceState(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (devicestate.version < DEVICESTATE_MIN_VER) {
|
||||
@ -412,7 +412,7 @@ void NodeDB::loadFromDisk()
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadProto(configFileName, LocalConfig_size, sizeof(LocalConfig), LocalConfig_fields, &config)) {
|
||||
if (!loadProto(configFileName, LocalConfig_size, sizeof(LocalConfig), &LocalConfig_msg, &config)) {
|
||||
installDefaultConfig(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (config.version < DEVICESTATE_MIN_VER) {
|
||||
@ -423,7 +423,7 @@ void NodeDB::loadFromDisk()
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadProto(moduleConfigFileName, LocalModuleConfig_size, sizeof(LocalModuleConfig), LocalModuleConfig_fields, &moduleConfig)) {
|
||||
if (!loadProto(moduleConfigFileName, LocalModuleConfig_size, sizeof(LocalModuleConfig), &LocalModuleConfig_msg, &moduleConfig)) {
|
||||
installDefaultModuleConfig(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (moduleConfig.version < DEVICESTATE_MIN_VER) {
|
||||
@ -434,7 +434,7 @@ void NodeDB::loadFromDisk()
|
||||
}
|
||||
}
|
||||
|
||||
if (!loadProto(channelFileName, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile)) {
|
||||
if (!loadProto(channelFileName, ChannelFile_size, sizeof(ChannelFile), &ChannelFile_msg, &channelFile)) {
|
||||
installDefaultChannels(); // Our in RAM copy might now be corrupt
|
||||
} else {
|
||||
if (channelFile.version < DEVICESTATE_MIN_VER) {
|
||||
@ -445,12 +445,12 @@ void NodeDB::loadFromDisk()
|
||||
}
|
||||
}
|
||||
|
||||
if (loadProto(oemConfigFile, OEMStore_size, sizeof(OEMStore), OEMStore_fields, &oemStore))
|
||||
if (loadProto(oemConfigFile, OEMStore_size, sizeof(OEMStore), &OEMStore_msg, &oemStore))
|
||||
DEBUG_MSG("Loaded OEMStore\n");
|
||||
}
|
||||
|
||||
/** Save a protobuf from a file, return true for success */
|
||||
bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, const void *dest_struct)
|
||||
bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct)
|
||||
{
|
||||
bool okay = false;
|
||||
#ifdef FSCom
|
||||
@ -498,7 +498,7 @@ void NodeDB::saveChannelsToDisk()
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(channelFileName, ChannelFile_size, sizeof(channelFile), ChannelFile_fields, &channelFile);
|
||||
saveProto(channelFileName, ChannelFile_size, &ChannelFile_msg, &channelFile);
|
||||
}
|
||||
}
|
||||
|
||||
@ -508,7 +508,7 @@ void NodeDB::saveDeviceStateToDisk()
|
||||
#ifdef FSCom
|
||||
FSCom.mkdir("/prefs");
|
||||
#endif
|
||||
saveProto(prefFileName, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate);
|
||||
saveProto(prefFileName, DeviceState_size, &DeviceState_msg, &devicestate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,7 +530,7 @@ void NodeDB::saveToDisk(int saveWhat)
|
||||
config.has_power = true;
|
||||
config.has_network = true;
|
||||
config.has_bluetooth = true;
|
||||
saveProto(configFileName, LocalConfig_size, sizeof(config), LocalConfig_fields, &config);
|
||||
saveProto(configFileName, LocalConfig_size, &LocalConfig_msg, &config);
|
||||
}
|
||||
|
||||
if (saveWhat & SEGMENT_MODULECONFIG) {
|
||||
@ -541,7 +541,7 @@ void NodeDB::saveToDisk(int saveWhat)
|
||||
moduleConfig.has_serial = true;
|
||||
moduleConfig.has_store_forward = true;
|
||||
moduleConfig.has_telemetry = true;
|
||||
saveProto(moduleConfigFileName, LocalModuleConfig_size, sizeof(moduleConfig), LocalModuleConfig_fields, &moduleConfig);
|
||||
saveProto(moduleConfigFileName, LocalModuleConfig_size, &LocalModuleConfig_msg, &moduleConfig);
|
||||
}
|
||||
|
||||
if (saveWhat & SEGMENT_CHANNELS) {
|
||||
|
@ -77,7 +77,7 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
|
||||
// return (lastContactMsec != 0) &&
|
||||
|
||||
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
|
||||
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
|
||||
if (pb_decode_from_bytes(buf, bufLength, &ToRadio_msg, &toRadioScratch)) {
|
||||
switch (toRadioScratch.which_payload_variant) {
|
||||
case ToRadio_packet_tag:
|
||||
return handleToRadioPacket(toRadioScratch.packet);
|
||||
@ -291,7 +291,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
||||
// Do we have a message from the mesh?
|
||||
if (fromRadioScratch.which_payload_variant != 0) {
|
||||
// Encapsulate as a FromRadio packet
|
||||
size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch);
|
||||
size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, &FromRadio_msg, &fromRadioScratch);
|
||||
|
||||
DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes);
|
||||
return numbytes;
|
||||
|
@ -175,7 +175,7 @@ uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
|
||||
{
|
||||
assert(slotTimeMsec); // Better be non zero
|
||||
static uint8_t bytes[MAX_RHPACKETLEN];
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &Data_msg, &p->decoded);
|
||||
uint32_t packetAirtime = getPacketTime(numbytes + sizeof(PacketHeader));
|
||||
// Make sure enough time has elapsed for this packet to be sent and an ACK is received.
|
||||
// DEBUG_MSG("Waiting for flooding message with airtime %d and slotTime is %d\n", packetAirtime, slotTimeMsec);
|
||||
|
@ -66,10 +66,5 @@ class RadioLibRF95: public SX1278 {
|
||||
// since default current limit for SX126x/127x in updated RadioLib is 60mA
|
||||
// use the previous value
|
||||
float currentLimit = 100;
|
||||
|
||||
#ifndef RADIOLIB_GODMODE
|
||||
private:
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
@ -27,7 +27,7 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
|
||||
return FloodingRouter::send(p);
|
||||
}
|
||||
|
||||
bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
|
||||
bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
|
||||
{
|
||||
// Note: do not use getFrom() here, because we want to ignore messages sent from phone
|
||||
if (p->from == getNodeNum()) {
|
||||
@ -37,9 +37,8 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
|
||||
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for
|
||||
// the original sending process.
|
||||
|
||||
// FIXME - we might want to turn off this "optimization", it does save lots of airtime but it assumes that once we've
|
||||
// heard one one adjacent node hear our packet that a) probably other adjacent nodes heard it and b) we can trust those
|
||||
// nodes to reach our destination. Both of which might be incorrect.
|
||||
// This "optimization", does save lots of airtime. For DMs, you also get a real ACK back
|
||||
// from the intended recipient.
|
||||
auto key = GlobalPacketId(getFrom(p), p->id);
|
||||
auto old = findPendingPacket(key);
|
||||
if (old) {
|
||||
@ -54,16 +53,11 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
|
||||
}
|
||||
}
|
||||
|
||||
/* send acks for repeated packets that want acks and are destined for us
|
||||
* this way if an ACK is dropped and a packet is resent we'll ACK the resent packet
|
||||
* make sure wasSeenRecently _doesn't_ update
|
||||
* finding the channel requires decoding the packet. */
|
||||
if (p->want_ack && (p->to == getNodeNum()) && wasSeenRecently(p, false) && !MeshModule::currentReply) {
|
||||
if (perhapsDecode(p)) {
|
||||
sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
|
||||
DEBUG_MSG("acking a repeated want_ack packet\n");
|
||||
}
|
||||
} else if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
|
||||
/* Resend implicit ACKs for repeated packets (assuming the original packet was sent with HOP_RELIABLE)
|
||||
* this way if an implicit ACK is dropped and a packet is resent we'll rebroadcast again.
|
||||
* Resending real ACKs is omitted, as you might receive a packet multiple times due to flooding and
|
||||
* flooding this ACK back to the original sender already adds redundancy. */
|
||||
if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
|
||||
// retransmission on broadcast has hop_limit still equal to HOP_RELIABLE
|
||||
DEBUG_MSG("Resending implicit ack for a repeated floodmsg\n");
|
||||
MeshPacket *tosend = packetPool.allocCopy(*p);
|
||||
|
@ -96,7 +96,7 @@ class ReliableRouter : public FloodingRouter
|
||||
/**
|
||||
* We hook this method so we can see packets before FloodingRouter says they should be discarded
|
||||
*/
|
||||
virtual bool shouldFilterReceived(MeshPacket *p) override;
|
||||
virtual bool shouldFilterReceived(const MeshPacket *p) override;
|
||||
|
||||
/**
|
||||
* Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting.
|
||||
|
@ -306,7 +306,7 @@ bool perhapsDecode(MeshPacket *p)
|
||||
|
||||
// Take those raw bytes and convert them back into a well structured protobuf we can understand
|
||||
memset(&p->decoded, 0, sizeof(p->decoded));
|
||||
if (!pb_decode_from_bytes(bytes, rawSize, Data_fields, &p->decoded)) {
|
||||
if (!pb_decode_from_bytes(bytes, rawSize, &Data_msg, &p->decoded)) {
|
||||
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?)!\n");
|
||||
} else if (p->decoded.portnum == PortNum_UNKNOWN_APP) {
|
||||
DEBUG_MSG("Invalid portnum (bad psk?)!\n");
|
||||
@ -360,7 +360,7 @@ Routing_Error perhapsEncode(MeshPacket *p)
|
||||
if (p->which_payload_variant == MeshPacket_decoded_tag) {
|
||||
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
|
||||
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
|
||||
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &Data_msg, &p->decoded);
|
||||
|
||||
// Only allow encryption on the text message app.
|
||||
// TODO: Allow modules to opt into compression.
|
||||
|
@ -90,7 +90,7 @@ class Router : protected concurrency::OSThread
|
||||
* Called immedately on receiption, before any further processing.
|
||||
* @return true to abandon the packet
|
||||
*/
|
||||
virtual bool shouldFilterReceived(MeshPacket *p) { return false; }
|
||||
virtual bool shouldFilterReceived(const MeshPacket *p) { return false; }
|
||||
|
||||
/**
|
||||
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "configuration.h"
|
||||
#include "SX128xInterface.h"
|
||||
#include "mesh/NodeDB.h"
|
||||
#include "error.h"
|
||||
|
||||
// Particular boards might define a different max power based on what their hardware can do
|
||||
@ -50,6 +51,20 @@ bool SX128xInterface<T>::init()
|
||||
// \todo Display actual typename of the adapter, not just `SX128x`
|
||||
DEBUG_MSG("SX128x init result %d\n", res);
|
||||
|
||||
if((config.lora.region != Config_LoRaConfig_RegionCode_LORA_24) && (res == RADIOLIB_ERR_INVALID_FREQUENCY)) {
|
||||
DEBUG_MSG("Warning: Radio chip only supports 2.4GHz LoRa. Adjusting Region and rebooting.\n");
|
||||
config.lora.region = Config_LoRaConfig_RegionCode_LORA_24;
|
||||
nodeDB.saveToDisk(SEGMENT_CONFIG);
|
||||
delay(2000);
|
||||
#if defined(ARCH_ESP32)
|
||||
ESP.restart();
|
||||
#elif defined(ARCH_NRF52)
|
||||
NVIC_SystemReset();
|
||||
#else
|
||||
DEBUG_MSG("FIXME implement reboot for this platform. Skipping for now.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
DEBUG_MSG("Frequency set to %f\n", getFreq());
|
||||
DEBUG_MSG("Bandwidth set to %f\n", bw);
|
||||
DEBUG_MSG("Power output set to %d\n", power);
|
||||
@ -223,13 +238,9 @@ bool SX128xInterface<T>::isChannelActive()
|
||||
template<typename T>
|
||||
bool SX128xInterface<T>::isActivelyReceiving()
|
||||
{
|
||||
#ifdef RADIOLIB_GODMODE
|
||||
uint16_t irq = lora.getIrqStatus();
|
||||
bool hasPreamble = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID);
|
||||
return hasPreamble;
|
||||
#else
|
||||
return isChannelActive();
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -27,9 +27,7 @@ class SX128xInterface : public RadioLibInterface
|
||||
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
|
||||
virtual bool sleep() override;
|
||||
|
||||
#ifdef RADIOLIB_GODMODE
|
||||
bool isIRQPending() override { return lora.getIrqStatus() != 0; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#define START2 0xc3
|
||||
#define HEADER_LEN 4
|
||||
|
||||
int32_t StreamAPI::runOnce()
|
||||
int32_t StreamAPI::runOncePart()
|
||||
{
|
||||
auto result = readStream();
|
||||
writeStream();
|
||||
@ -115,7 +115,7 @@ void StreamAPI::emitRebooted()
|
||||
fromRadioScratch.rebooted = true;
|
||||
|
||||
// DEBUG_MSG("Emitting reboot packet for serial shell\n");
|
||||
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
|
||||
emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, &FromRadio_msg, &fromRadioScratch));
|
||||
}
|
||||
|
||||
/// Hookable to find out when connection changes
|
||||
|
@ -28,7 +28,7 @@ valid utf8 encoding. This makes it a bit easier to start a device outputting reg
|
||||
after it has received a valid packet from the PC, turn off unencoded debug printing and switch to this packet encoding.
|
||||
|
||||
*/
|
||||
class StreamAPI : public PhoneAPI, protected concurrency::OSThread
|
||||
class StreamAPI : public PhoneAPI
|
||||
{
|
||||
/**
|
||||
* The stream we read/write from
|
||||
@ -42,13 +42,13 @@ class StreamAPI : public PhoneAPI, protected concurrency::OSThread
|
||||
uint32_t lastRxMsec = 0;
|
||||
|
||||
public:
|
||||
StreamAPI(Stream *_stream) : concurrency::OSThread("StreamAPI"), stream(_stream) {}
|
||||
StreamAPI(Stream *_stream) : stream(_stream) {}
|
||||
|
||||
/**
|
||||
* Currently we require frequent invocation from loop() to check for arrived serial packets and to send new packets to the
|
||||
* phone.
|
||||
*/
|
||||
virtual int32_t runOnce() override;
|
||||
virtual int32_t runOncePart();
|
||||
|
||||
private:
|
||||
/**
|
||||
|
@ -14,7 +14,7 @@ void initApiServer(int port)
|
||||
}
|
||||
}
|
||||
|
||||
ethServerAPI::ethServerAPI(EthernetClient &_client) : StreamAPI(&client), client(_client)
|
||||
ethServerAPI::ethServerAPI(EthernetClient &_client) : StreamAPI(&client), concurrency::OSThread("ethServerAPI"), client(_client)
|
||||
{
|
||||
DEBUG_MSG("Incoming ethernet connection\n");
|
||||
}
|
||||
@ -42,7 +42,7 @@ bool ethServerAPI::checkIsConnected()
|
||||
int32_t ethServerAPI::runOnce()
|
||||
{
|
||||
if (client.connected()) {
|
||||
return StreamAPI::runOnce();
|
||||
return StreamAPI::runOncePart();
|
||||
} else {
|
||||
DEBUG_MSG("Client dropped connection, suspending API service\n");
|
||||
enabled = false; // we no longer need to run
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs
|
||||
* (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs).
|
||||
*/
|
||||
class ethServerAPI : public StreamAPI
|
||||
class ethServerAPI : public StreamAPI, private concurrency::OSThread
|
||||
{
|
||||
private:
|
||||
EthernetClient client;
|
||||
|
@ -54,6 +54,8 @@ typedef enum _HardwareModel {
|
||||
HardwareModel_NANO_G1 = 14,
|
||||
/* TODO: REPLACE */
|
||||
HardwareModel_TLORA_V2_1_1P8 = 15,
|
||||
/* TODO: REPLACE */
|
||||
HardwareModel_TLORA_T3_S3 = 16,
|
||||
/* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */
|
||||
HardwareModel_STATION_G1 = 25,
|
||||
/* Less common/prototype boards listed here (needs one more byte over the air) */
|
||||
|
@ -10,8 +10,8 @@
|
||||
#endif
|
||||
|
||||
/* Enum definitions */
|
||||
/* 1 - 99 = From Router
|
||||
101 - 199 = From Client */
|
||||
/* 001 - 063 = From Router
|
||||
064 - 127 = From Client */
|
||||
typedef enum _StoreAndForward_RequestResponse {
|
||||
/* Unset/unused */
|
||||
StoreAndForward_RequestResponse_UNSET = 0,
|
||||
@ -28,17 +28,19 @@ typedef enum _StoreAndForward_RequestResponse {
|
||||
StoreAndForward_RequestResponse_ROUTER_BUSY = 5,
|
||||
/* Router is responding to a request for history. */
|
||||
StoreAndForward_RequestResponse_ROUTER_HISTORY = 6,
|
||||
/* Router is responding to a request for stats. */
|
||||
StoreAndForward_RequestResponse_ROUTER_STATS = 7,
|
||||
/* Client is an in error state. */
|
||||
StoreAndForward_RequestResponse_CLIENT_ERROR = 101,
|
||||
StoreAndForward_RequestResponse_CLIENT_ERROR = 64,
|
||||
/* Client has requested a replay from the router. */
|
||||
StoreAndForward_RequestResponse_CLIENT_HISTORY = 102,
|
||||
StoreAndForward_RequestResponse_CLIENT_HISTORY = 65,
|
||||
/* Client has requested stats from the router. */
|
||||
StoreAndForward_RequestResponse_CLIENT_STATS = 103,
|
||||
StoreAndForward_RequestResponse_CLIENT_STATS = 66,
|
||||
/* Client has requested the router respond. This can work as a
|
||||
"are you there" message. */
|
||||
StoreAndForward_RequestResponse_CLIENT_PING = 104,
|
||||
StoreAndForward_RequestResponse_CLIENT_PING = 67,
|
||||
/* The response to a "Ping" */
|
||||
StoreAndForward_RequestResponse_CLIENT_PONG = 105,
|
||||
StoreAndForward_RequestResponse_CLIENT_PONG = 68,
|
||||
/* Client has requested that the router abort processing the client's request */
|
||||
StoreAndForward_RequestResponse_CLIENT_ABORT = 106
|
||||
} StoreAndForward_RequestResponse;
|
||||
@ -88,15 +90,17 @@ typedef struct _StoreAndForward_Heartbeat {
|
||||
typedef struct _StoreAndForward {
|
||||
/* TODO: REPLACE */
|
||||
StoreAndForward_RequestResponse rr;
|
||||
/* TODO: REPLACE */
|
||||
bool has_stats;
|
||||
StoreAndForward_Statistics stats;
|
||||
/* TODO: REPLACE */
|
||||
bool has_history;
|
||||
StoreAndForward_History history;
|
||||
/* TODO: REPLACE */
|
||||
bool has_heartbeat;
|
||||
StoreAndForward_Heartbeat heartbeat;
|
||||
pb_size_t which_variant;
|
||||
union {
|
||||
/* TODO: REPLACE */
|
||||
StoreAndForward_Statistics stats;
|
||||
/* TODO: REPLACE */
|
||||
StoreAndForward_History history;
|
||||
/* TODO: REPLACE */
|
||||
StoreAndForward_Heartbeat heartbeat;
|
||||
/* Empty Payload */
|
||||
bool empty;
|
||||
} variant;
|
||||
} StoreAndForward;
|
||||
|
||||
|
||||
@ -116,11 +120,11 @@ extern "C" {
|
||||
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define StoreAndForward_init_default {_StoreAndForward_RequestResponse_MIN, false, StoreAndForward_Statistics_init_default, false, StoreAndForward_History_init_default, false, StoreAndForward_Heartbeat_init_default}
|
||||
#define StoreAndForward_init_default {_StoreAndForward_RequestResponse_MIN, 0, {StoreAndForward_Statistics_init_default}}
|
||||
#define StoreAndForward_Statistics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define StoreAndForward_History_init_default {0, 0, 0}
|
||||
#define StoreAndForward_Heartbeat_init_default {0, 0}
|
||||
#define StoreAndForward_init_zero {_StoreAndForward_RequestResponse_MIN, false, StoreAndForward_Statistics_init_zero, false, StoreAndForward_History_init_zero, false, StoreAndForward_Heartbeat_init_zero}
|
||||
#define StoreAndForward_init_zero {_StoreAndForward_RequestResponse_MIN, 0, {StoreAndForward_Statistics_init_zero}}
|
||||
#define StoreAndForward_Statistics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define StoreAndForward_History_init_zero {0, 0, 0}
|
||||
#define StoreAndForward_Heartbeat_init_zero {0, 0}
|
||||
@ -144,18 +148,20 @@ extern "C" {
|
||||
#define StoreAndForward_stats_tag 2
|
||||
#define StoreAndForward_history_tag 3
|
||||
#define StoreAndForward_heartbeat_tag 4
|
||||
#define StoreAndForward_empty_tag 5
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define StoreAndForward_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, rr, 1) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, stats, 2) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, history, 3) \
|
||||
X(a, STATIC, OPTIONAL, MESSAGE, heartbeat, 4)
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,stats,variant.stats), 2) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,history,variant.history), 3) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (variant,heartbeat,variant.heartbeat), 4) \
|
||||
X(a, STATIC, ONEOF, BOOL, (variant,empty,variant.empty), 5)
|
||||
#define StoreAndForward_CALLBACK NULL
|
||||
#define StoreAndForward_DEFAULT NULL
|
||||
#define StoreAndForward_stats_MSGTYPE StoreAndForward_Statistics
|
||||
#define StoreAndForward_history_MSGTYPE StoreAndForward_History
|
||||
#define StoreAndForward_heartbeat_MSGTYPE StoreAndForward_Heartbeat
|
||||
#define StoreAndForward_variant_stats_MSGTYPE StoreAndForward_Statistics
|
||||
#define StoreAndForward_variant_history_MSGTYPE StoreAndForward_History
|
||||
#define StoreAndForward_variant_heartbeat_MSGTYPE StoreAndForward_Heartbeat
|
||||
|
||||
#define StoreAndForward_Statistics_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, messages_total, 1) \
|
||||
@ -198,7 +204,7 @@ extern const pb_msgdesc_t StoreAndForward_Heartbeat_msg;
|
||||
#define StoreAndForward_Heartbeat_size 12
|
||||
#define StoreAndForward_History_size 18
|
||||
#define StoreAndForward_Statistics_size 50
|
||||
#define StoreAndForward_size 88
|
||||
#define StoreAndForward_size 54
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
@ -14,7 +14,7 @@ void initApiServer(int port)
|
||||
}
|
||||
}
|
||||
|
||||
WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), client(_client)
|
||||
WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), concurrency::OSThread("WiFiServerAPI"), client(_client)
|
||||
{
|
||||
DEBUG_MSG("Incoming wifi connection\n");
|
||||
}
|
||||
@ -42,7 +42,7 @@ bool WiFiServerAPI::checkIsConnected()
|
||||
int32_t WiFiServerAPI::runOnce()
|
||||
{
|
||||
if (client.connected()) {
|
||||
return StreamAPI::runOnce();
|
||||
return StreamAPI::runOncePart();
|
||||
} else {
|
||||
DEBUG_MSG("Client dropped connection, suspending API service\n");
|
||||
enabled = false; // we no longer need to run
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs
|
||||
* (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs).
|
||||
*/
|
||||
class WiFiServerAPI : public StreamAPI
|
||||
class WiFiServerAPI : public StreamAPI, private concurrency::OSThread
|
||||
{
|
||||
private:
|
||||
WiFiClient client;
|
||||
|
@ -515,7 +515,7 @@ void AdminModule::saveChanges(int saveWhat, bool shouldReboot)
|
||||
}
|
||||
}
|
||||
|
||||
AdminModule::AdminModule() : ProtobufModule("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
|
||||
AdminModule::AdminModule() : ProtobufModule("Admin", PortNum_ADMIN_APP, &AdminMessage_msg)
|
||||
{
|
||||
// restrict to the admin channel for rx
|
||||
boundChannel = Channels::adminChannel;
|
||||
|
@ -45,8 +45,7 @@ CannedMessageModule *cannedMessageModule;
|
||||
|
||||
// TODO: move it into NodeDB.h!
|
||||
extern bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct);
|
||||
extern bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields,
|
||||
const void *dest_struct);
|
||||
extern bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct);
|
||||
|
||||
CannedMessageModule::CannedMessageModule()
|
||||
: SinglePortModule("canned", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("CannedMessageModule")
|
||||
@ -480,7 +479,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
|
||||
void CannedMessageModule::loadProtoForModule()
|
||||
{
|
||||
if (!loadProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, sizeof(cannedMessagesConfigFile),
|
||||
CannedMessageModuleConfig_fields, &cannedMessageModuleConfig)) {
|
||||
&CannedMessageModuleConfig_msg, &cannedMessageModuleConfig)) {
|
||||
installDefaultCannedMessageModuleConfig();
|
||||
}
|
||||
}
|
||||
@ -499,8 +498,8 @@ bool CannedMessageModule::saveProtoForModule()
|
||||
FS.mkdir("/prefs");
|
||||
#endif
|
||||
|
||||
okay &= saveProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, sizeof(cannedMessageModuleConfig),
|
||||
CannedMessageModuleConfig_fields, &cannedMessageModuleConfig);
|
||||
okay &= saveProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size,
|
||||
&CannedMessageModuleConfig_msg, &cannedMessageModuleConfig);
|
||||
|
||||
return okay;
|
||||
}
|
||||
|
@ -11,41 +11,9 @@
|
||||
#define PIN_BUZZER false
|
||||
#endif
|
||||
|
||||
//#include <assert.h>
|
||||
|
||||
/*
|
||||
|
||||
Documentation:
|
||||
https://github.com/meshtastic/firmware/blob/master/docs/software/modules/ExternalNotificationModule.md
|
||||
|
||||
This module supports:
|
||||
https://github.com/meshtastic/firmware/issues/654
|
||||
|
||||
|
||||
Quick reference:
|
||||
|
||||
moduleConfig.external_notification.enabled
|
||||
0 = Disabled (Default)
|
||||
1 = Enabled
|
||||
|
||||
moduleConfig.external_notification.active
|
||||
0 = Active Low (Default)
|
||||
1 = Active High
|
||||
|
||||
moduleConfig.external_notification.alert_message
|
||||
0 = Disabled (Default)
|
||||
1 = Alert when a text message comes
|
||||
|
||||
moduleConfig.external_notification.alert_bell
|
||||
0 = Disabled (Default)
|
||||
1 = Alert when the bell character is received
|
||||
|
||||
moduleConfig.external_notification.output
|
||||
GPIO of the output. (Default = 13)
|
||||
|
||||
moduleConfig.external_notification.output_ms
|
||||
Amount of time in ms for the alert. Default is 1000.
|
||||
|
||||
https://meshtastic.org/docs/settings/moduleconfig/external-notification
|
||||
*/
|
||||
|
||||
// Default configurations
|
||||
@ -58,59 +26,113 @@
|
||||
|
||||
#define ASCII_BELL 0x07
|
||||
|
||||
bool externalCurrentState = 0;
|
||||
uint32_t externalTurnedOn = 0;
|
||||
ExternalNotificationModule *externalNotificationModule;
|
||||
|
||||
bool externalCurrentState[3] = {};
|
||||
|
||||
uint32_t externalTurnedOn[3] = {};
|
||||
|
||||
int32_t ExternalNotificationModule::runOnce()
|
||||
{
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the module
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
// moduleConfig.external_notification.enabled = 1;
|
||||
// moduleConfig.external_notification.alert_message = 1;
|
||||
|
||||
// moduleConfig.external_notification.active = 1;
|
||||
// moduleConfig.external_notification.alert_bell = 1;
|
||||
// moduleConfig.external_notification.output_ms = 1000;
|
||||
// moduleConfig.external_notification.output = 13;
|
||||
|
||||
if (externalCurrentState && !moduleConfig.external_notification.use_pwm) {
|
||||
if (!moduleConfig.external_notification.enabled) {
|
||||
return INT32_MAX; // we don't need this thread here...
|
||||
} else {
|
||||
if ((nagCycleCutoff < millis()) && !rtttl::isPlaying()) {
|
||||
nagCycleCutoff = UINT32_MAX;
|
||||
DEBUG_MSG("Turning off external notification: ");
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (getExternal(i)) {
|
||||
setExternalOff(i);
|
||||
externalTurnedOn[i] = 0;
|
||||
DEBUG_MSG("%d ", i);
|
||||
}
|
||||
}
|
||||
DEBUG_MSG("\n");
|
||||
return INT32_MAX; // save cycles till we're needed again
|
||||
}
|
||||
|
||||
// If the output is turned on, turn it back off after the given period of time.
|
||||
if (externalTurnedOn + (moduleConfig.external_notification.output_ms
|
||||
if (nagCycleCutoff != UINT32_MAX) {
|
||||
if (externalTurnedOn[0] + (moduleConfig.external_notification.output_ms
|
||||
? moduleConfig.external_notification.output_ms
|
||||
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
|
||||
millis()) {
|
||||
DEBUG_MSG("Turning off external notification\n");
|
||||
setExternalOff();
|
||||
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) {
|
||||
getExternal(0) ? setExternalOff(0) : setExternalOn(0);
|
||||
}
|
||||
if (externalTurnedOn[1] + (moduleConfig.external_notification.output_ms
|
||||
? moduleConfig.external_notification.output_ms
|
||||
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) {
|
||||
getExternal(1) ? setExternalOff(1) : setExternalOn(1);
|
||||
}
|
||||
if (externalTurnedOn[2] + (moduleConfig.external_notification.output_ms
|
||||
? moduleConfig.external_notification.output_ms
|
||||
: EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) {
|
||||
getExternal(2) ? setExternalOff(2) : setExternalOn(2);
|
||||
}
|
||||
}
|
||||
|
||||
// now let the PWM buzzer play
|
||||
if (moduleConfig.external_notification.use_pwm) {
|
||||
if (rtttl::isPlaying()) {
|
||||
rtttl::play();
|
||||
} else if (nagCycleCutoff >= millis()) {
|
||||
// start the song again if we have time left
|
||||
rtttl::begin(config.device.buzzer_gpio, pwmRingtone);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (moduleConfig.external_notification.use_pwm)
|
||||
return INT32_MAX; // we don't need this thread here...
|
||||
else
|
||||
return 25;
|
||||
}
|
||||
}
|
||||
|
||||
void ExternalNotificationModule::setExternalOn()
|
||||
void ExternalNotificationModule::setExternalOn(uint8_t index)
|
||||
{
|
||||
externalCurrentState = 1;
|
||||
externalTurnedOn = millis();
|
||||
externalCurrentState[index] = 1;
|
||||
externalTurnedOn[index] = millis();
|
||||
|
||||
digitalWrite(output,
|
||||
(moduleConfig.external_notification.active ? true : false));
|
||||
switch(index) {
|
||||
case 1:
|
||||
if(moduleConfig.external_notification.output_vibra)
|
||||
digitalWrite(moduleConfig.external_notification.output_vibra, true);
|
||||
break;
|
||||
case 2:
|
||||
if(moduleConfig.external_notification.output_buzzer)
|
||||
digitalWrite(moduleConfig.external_notification.output_buzzer, true);
|
||||
break;
|
||||
default:
|
||||
digitalWrite(output, (moduleConfig.external_notification.active ? true : false));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ExternalNotificationModule::setExternalOff()
|
||||
void ExternalNotificationModule::setExternalOff(uint8_t index)
|
||||
{
|
||||
externalCurrentState = 0;
|
||||
externalCurrentState[index] = 0;
|
||||
externalTurnedOn[index] = millis();
|
||||
|
||||
digitalWrite(output,
|
||||
(moduleConfig.external_notification.active ? false : true));
|
||||
switch(index) {
|
||||
case 1:
|
||||
if(moduleConfig.external_notification.output_vibra)
|
||||
digitalWrite(moduleConfig.external_notification.output_vibra, false);
|
||||
break;
|
||||
case 2:
|
||||
if(moduleConfig.external_notification.output_buzzer)
|
||||
digitalWrite(moduleConfig.external_notification.output_buzzer, false);
|
||||
break;
|
||||
default:
|
||||
digitalWrite(output, (moduleConfig.external_notification.active ? false : true));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// --------
|
||||
bool ExternalNotificationModule::getExternal(uint8_t index)
|
||||
{
|
||||
return externalCurrentState[index];
|
||||
}
|
||||
|
||||
void ExternalNotificationModule::stopNow() {
|
||||
rtttl::stop();
|
||||
nagCycleCutoff = 1; // small value
|
||||
setIntervalFromNow(0);
|
||||
}
|
||||
|
||||
ExternalNotificationModule::ExternalNotificationModule()
|
||||
: SinglePortModule("ExternalNotificationModule", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread(
|
||||
@ -121,13 +143,18 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
*/
|
||||
|
||||
// moduleConfig.external_notification.enabled = 1;
|
||||
// moduleConfig.external_notification.alert_message = 1;
|
||||
// moduleConfig.external_notification.enabled = true;
|
||||
// moduleConfig.external_notification.alert_message = true;
|
||||
// moduleConfig.external_notification.alert_message_buzzer = true;
|
||||
// moduleConfig.external_notification.alert_message_vibra = true;
|
||||
|
||||
// moduleConfig.external_notification.active = 1;
|
||||
// moduleConfig.external_notification.active = true;
|
||||
// moduleConfig.external_notification.alert_bell = 1;
|
||||
// moduleConfig.external_notification.output_ms = 1000;
|
||||
// moduleConfig.external_notification.output = 13;
|
||||
// moduleConfig.external_notification.output = 4; // RAK4631 IO4
|
||||
// moduleConfig.external_notification.output_buzzer = 10; // RAK4631 IO6
|
||||
// moduleConfig.external_notification.output_vibra = 28; // RAK4631 IO7
|
||||
// moduleConfig.external_notification.nag_timeout = 300;
|
||||
|
||||
if (moduleConfig.external_notification.enabled) {
|
||||
|
||||
@ -137,19 +164,30 @@ ExternalNotificationModule::ExternalNotificationModule()
|
||||
? moduleConfig.external_notification.output
|
||||
: EXT_NOTIFICATION_MODULE_OUTPUT;
|
||||
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
// Set the direction of a pin
|
||||
DEBUG_MSG("Using Pin %i in digital mode\n", output);
|
||||
pinMode(output, OUTPUT);
|
||||
// Turn off the pin
|
||||
setExternalOff();
|
||||
} else {
|
||||
config.device.buzzer_gpio = config.device.buzzer_gpio
|
||||
? config.device.buzzer_gpio
|
||||
: PIN_BUZZER;
|
||||
|
||||
// in PWM Mode we force the buzzer pin if it is set
|
||||
DEBUG_MSG("Using Pin %i in PWM mode\n", config.device.buzzer_gpio);
|
||||
// Set the direction of a pin
|
||||
DEBUG_MSG("Using Pin %i in digital mode\n", output);
|
||||
pinMode(output, OUTPUT);
|
||||
setExternalOff(0);
|
||||
externalTurnedOn[0] = 0;
|
||||
if(moduleConfig.external_notification.output_vibra) {
|
||||
DEBUG_MSG("Using Pin %i for vibra motor\n", moduleConfig.external_notification.output_vibra);
|
||||
pinMode(moduleConfig.external_notification.output_vibra, OUTPUT);
|
||||
setExternalOff(1);
|
||||
externalTurnedOn[1] = 0;
|
||||
}
|
||||
if(moduleConfig.external_notification.output_buzzer) {
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
DEBUG_MSG("Using Pin %i for buzzer\n", moduleConfig.external_notification.output_buzzer);
|
||||
pinMode(moduleConfig.external_notification.output_buzzer, OUTPUT);
|
||||
setExternalOff(2);
|
||||
externalTurnedOn[2] = 0;
|
||||
} else {
|
||||
config.device.buzzer_gpio = config.device.buzzer_gpio
|
||||
? config.device.buzzer_gpio
|
||||
: PIN_BUZZER;
|
||||
// in PWM Mode we force the buzzer pin if it is set
|
||||
DEBUG_MSG("Using Pin %i in PWM mode\n", config.device.buzzer_gpio);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG("External Notification Module Disabled\n");
|
||||
@ -163,30 +201,91 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
|
||||
|
||||
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
||||
|
||||
// TODO: This may be a problem if messages are sent in unicide, but I'm not sure if it will.
|
||||
// Need to know if and how this could be a problem.
|
||||
// Check if the message contains a bell character. Don't do this loop for every pin, just once.
|
||||
auto &p = mp.decoded;
|
||||
bool containsBell = false;
|
||||
for (int i = 0; i < p.payload.size; i++) {
|
||||
if (p.payload.bytes[i] == ASCII_BELL) {
|
||||
containsBell = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.alert_bell) {
|
||||
auto &p = mp.decoded;
|
||||
DEBUG_MSG("externalNotificationModule - Notification Bell\n");
|
||||
for (int i = 0; i < p.payload.size; i++) {
|
||||
if (p.payload.bytes[i] == ASCII_BELL) {
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn();
|
||||
} else {
|
||||
playBeep();
|
||||
}
|
||||
if (containsBell) {
|
||||
DEBUG_MSG("externalNotificationModule - Notification Bell\n");
|
||||
setExternalOn(0);
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
} else {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.alert_bell_vibra) {
|
||||
if (containsBell) {
|
||||
DEBUG_MSG("externalNotificationModule - Notification Bell (Vibra)\n");
|
||||
setExternalOn(1);
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
} else {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.alert_bell_buzzer) {
|
||||
if (containsBell) {
|
||||
DEBUG_MSG("externalNotificationModule - Notification Bell (Buzzer)\n");
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn(2);
|
||||
} else {
|
||||
rtttl::begin(config.device.buzzer_gpio, pwmRingtone);
|
||||
}
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
} else {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.alert_message) {
|
||||
DEBUG_MSG("externalNotificationModule - Notification Module\n");
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn();
|
||||
setExternalOn(0);
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
} else {
|
||||
playBeep();
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||
}
|
||||
}
|
||||
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
if (moduleConfig.external_notification.alert_message_vibra) {
|
||||
DEBUG_MSG("externalNotificationModule - Notification Module (Vibra)\n");
|
||||
setExternalOn(1);
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
} else {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||
}
|
||||
}
|
||||
|
||||
if (moduleConfig.external_notification.alert_message_buzzer) {
|
||||
DEBUG_MSG("externalNotificationModule - Notification Module (Buzzer)\n");
|
||||
if (!moduleConfig.external_notification.use_pwm) {
|
||||
setExternalOn(2);
|
||||
} else {
|
||||
rtttl::begin(config.device.buzzer_gpio, pwmRingtone);
|
||||
}
|
||||
if (moduleConfig.external_notification.nag_timeout) {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
|
||||
} else {
|
||||
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
setIntervalFromNow(0); // run once so we know if we should do something
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "SinglePortModule.h"
|
||||
#include "concurrency/OSThread.h"
|
||||
#include "configuration.h"
|
||||
#include <NonBlockingRtttl.h>
|
||||
#include <Arduino.h>
|
||||
#include <functional>
|
||||
|
||||
@ -17,18 +18,23 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
|
||||
public:
|
||||
ExternalNotificationModule();
|
||||
|
||||
void setExternalOn();
|
||||
void setExternalOff();
|
||||
void getExternal();
|
||||
uint32_t nagCycleCutoff = UINT32_MAX;
|
||||
|
||||
void setExternalOn(uint8_t index = 0);
|
||||
void setExternalOff(uint8_t index = 0);
|
||||
bool getExternal(uint8_t index = 0);
|
||||
|
||||
void stopNow();
|
||||
|
||||
char pwmRingtone[Constants_DATA_PAYLOAD_LEN] = "a:d=8,o=5,b=125:4d#6,a#,2d#6,16p,g#,4a#,4d#.,p,16g,16a#,d#6,a#,f6,2d#6,16p,c#.6,16c6,16a#,g#.,2a#";
|
||||
|
||||
protected:
|
||||
// virtual MeshPacket *allocReply();
|
||||
|
||||
/** Called to handle a particular incoming message
|
||||
|
||||
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
|
||||
*/
|
||||
virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
|
||||
|
||||
virtual int32_t runOnce() override;
|
||||
};
|
||||
|
||||
extern ExternalNotificationModule *externalNotificationModule;
|
||||
|
@ -24,7 +24,7 @@
|
||||
#endif
|
||||
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#if !defined(TTGO_T_ECHO)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
#include "modules/SerialModule.h"
|
||||
#endif
|
||||
#endif
|
||||
@ -63,13 +63,13 @@ void setupModules()
|
||||
new DeviceTelemetryModule();
|
||||
new EnvironmentTelemetryModule();
|
||||
#endif
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO)
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
new SerialModule();
|
||||
#endif
|
||||
#ifdef ARCH_ESP32
|
||||
// Only run on an esp32 based device.
|
||||
audioModule = new AudioModule();
|
||||
new ExternalNotificationModule();
|
||||
externalNotificationModule = new ExternalNotificationModule();
|
||||
|
||||
storeForwardModule = new StoreForwardModule();
|
||||
|
||||
|
@ -51,7 +51,7 @@ MeshPacket *NodeInfoModule::allocReply()
|
||||
}
|
||||
|
||||
NodeInfoModule::NodeInfoModule()
|
||||
: ProtobufModule("nodeinfo", PortNum_NODEINFO_APP, User_fields), concurrency::OSThread("NodeInfoModule")
|
||||
: ProtobufModule("nodeinfo", PortNum_NODEINFO_APP, &User_msg), concurrency::OSThread("NodeInfoModule")
|
||||
{
|
||||
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
|
||||
setIntervalFromNow(30 * 1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup)
|
||||
|
@ -10,7 +10,7 @@
|
||||
PositionModule *positionModule;
|
||||
|
||||
PositionModule::PositionModule()
|
||||
: ProtobufModule("position", PortNum_POSITION_APP, Position_fields), concurrency::OSThread("PositionModule")
|
||||
: ProtobufModule("position", PortNum_POSITION_APP, &Position_msg), concurrency::OSThread("PositionModule")
|
||||
{
|
||||
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
|
||||
setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
|
||||
|
@ -47,7 +47,7 @@ static uint64_t digitalReads(uint64_t mask)
|
||||
}
|
||||
|
||||
RemoteHardwareModule::RemoteHardwareModule()
|
||||
: ProtobufModule("remotehardware", PortNum_REMOTE_HARDWARE_APP, HardwareMessage_fields), concurrency::OSThread(
|
||||
: ProtobufModule("remotehardware", PortNum_REMOTE_HARDWARE_APP, &HardwareMessage_msg), concurrency::OSThread(
|
||||
"remotehardware")
|
||||
{
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ void RoutingModule::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, C
|
||||
router->sendLocal(p); // we sometimes send directly to the local node
|
||||
}
|
||||
|
||||
RoutingModule::RoutingModule() : ProtobufModule("routing", PortNum_ROUTING_APP, Routing_fields)
|
||||
RoutingModule::RoutingModule() : ProtobufModule("routing", PortNum_ROUTING_APP, &Routing_msg)
|
||||
{
|
||||
isPromiscuous = true;
|
||||
encryptedOk = true;
|
||||
|
@ -46,6 +46,8 @@
|
||||
|
||||
*/
|
||||
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
|
||||
#define RXD2 16
|
||||
#define TXD2 17
|
||||
#define RX_BUFFER 128
|
||||
@ -53,13 +55,15 @@
|
||||
#define BAUD 38400
|
||||
#define ACK 1
|
||||
|
||||
// API: Defaulting to the formerly removed phone_timeout_secs value of 15 minutes
|
||||
#define SERIAL_CONNECTION_TIMEOUT (15 * 60) * 1000UL
|
||||
|
||||
SerialModule *serialModule;
|
||||
SerialModuleRadio *serialModuleRadio;
|
||||
|
||||
SerialModule::SerialModule() : concurrency::OSThread("SerialModule") {}
|
||||
SerialModule::SerialModule() : StreamAPI(&Serial2), concurrency::OSThread("SerialModule") {}
|
||||
|
||||
char serialBytes[Constants_DATA_PAYLOAD_LEN];
|
||||
size_t serialPayloadSize;
|
||||
char serialStringChar[Constants_DATA_PAYLOAD_LEN];
|
||||
|
||||
SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
|
||||
{
|
||||
@ -80,9 +84,15 @@ SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
|
||||
}
|
||||
}
|
||||
|
||||
// For the serial2 port we can't really detect if any client is on the other side, so instead just look for recent messages
|
||||
bool SerialModule::checkIsConnected()
|
||||
{
|
||||
uint32_t now = millis();
|
||||
return (now - lastContactMsec) < SERIAL_CONNECTION_TIMEOUT;
|
||||
}
|
||||
|
||||
int32_t SerialModule::runOnce()
|
||||
{
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
/*
|
||||
Uncomment the preferences below if you want to use the module
|
||||
without having to configure it from the PythonAPI or WebUI.
|
||||
@ -178,19 +188,32 @@ int32_t SerialModule::runOnce()
|
||||
|
||||
firstTime = 0;
|
||||
|
||||
// in API mode send rebooted sequence
|
||||
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
|
||||
emitRebooted();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// in NMEA mode send out GGA every 2 seconds, Don't read from Port
|
||||
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {
|
||||
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
|
||||
return runOncePart();
|
||||
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {
|
||||
// in NMEA mode send out GGA every 2 seconds, Don't read from Port
|
||||
if (millis() - lastNmeaTime > 2000) {
|
||||
lastNmeaTime = millis();
|
||||
printGGA(outbuf, nodeDB.getNode(myNodeInfo.my_node_num)->position);
|
||||
Serial2.printf("%s", outbuf);
|
||||
}
|
||||
} else {
|
||||
String serialString;
|
||||
|
||||
while (Serial2.available()) {
|
||||
serialPayloadSize = Serial2.readBytes(serialBytes, Constants_DATA_PAYLOAD_LEN);
|
||||
serialString = Serial2.readString();
|
||||
serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN);
|
||||
|
||||
serialModuleRadio->sendPayload();
|
||||
|
||||
DEBUG_MSG("Received: %s\n", serialStringChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -201,9 +224,6 @@ int32_t SerialModule::runOnce()
|
||||
|
||||
return INT32_MAX;
|
||||
}
|
||||
#else
|
||||
return INT32_MAX;
|
||||
#endif
|
||||
}
|
||||
|
||||
MeshPacket *SerialModuleRadio::allocReply()
|
||||
@ -215,26 +235,25 @@ MeshPacket *SerialModuleRadio::allocReply()
|
||||
|
||||
void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
||||
{
|
||||
Channel *ch = (boundChannel != NULL) ? &channels.getByName(boundChannel) : NULL;
|
||||
MeshPacket *p = allocReply();
|
||||
p->to = dest;
|
||||
if (ch != NULL) {
|
||||
p->channel = ch->index;
|
||||
}
|
||||
p->decoded.want_response = wantReplies;
|
||||
|
||||
p->want_ack = ACK;
|
||||
|
||||
p->decoded.payload.size = serialPayloadSize; // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, serialBytes, p->decoded.payload.size);
|
||||
p->decoded.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, serialStringChar, p->decoded.payload.size);
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
|
||||
{
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
if (moduleConfig.serial.enabled) {
|
||||
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
|
||||
// in API mode we don't care about stuff from radio.
|
||||
return ProcessMessage::CONTINUE;
|
||||
}
|
||||
|
||||
auto &p = mp.decoded;
|
||||
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
|
||||
@ -262,22 +281,20 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
|
||||
|
||||
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_DEFAULT ||
|
||||
moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) {
|
||||
Serial2.write(p.payload.bytes, p.payload.size);
|
||||
Serial2.printf("%s", p.payload.bytes);
|
||||
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG) {
|
||||
NodeInfo *node = nodeDB.getNode(getFrom(&mp));
|
||||
String sender = (node && node->has_user) ? node->user.short_name : "???";
|
||||
Serial2.println();
|
||||
Serial2.printf("%s: %s", sender, p.payload.bytes);
|
||||
Serial2.println();
|
||||
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
|
||||
// TODO this needs to be implemented
|
||||
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {
|
||||
// Decode the Payload some more
|
||||
Position scratch;
|
||||
Position *decoded = NULL;
|
||||
if (mp.which_payload_variant == MeshPacket_decoded_tag && mp.decoded.portnum == ourPortNum) {
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, Position_fields, &scratch)) {
|
||||
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &Position_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
}
|
||||
// send position packet as WPL to the serial port
|
||||
@ -290,8 +307,6 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
|
||||
} else {
|
||||
DEBUG_MSG("Serial Module Disabled\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
||||
}
|
||||
#endif
|
||||
|
@ -8,7 +8,9 @@
|
||||
#include "Router.h"
|
||||
#include <functional>
|
||||
|
||||
class SerialModule : private concurrency::OSThread
|
||||
#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
|
||||
class SerialModule : public StreamAPI, private concurrency::OSThread
|
||||
{
|
||||
bool firstTime = 1;
|
||||
unsigned long lastNmeaTime = millis();
|
||||
@ -19,6 +21,9 @@ class SerialModule : private concurrency::OSThread
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
/// Check the current underlying physical link to see if the client is currently connected
|
||||
virtual bool checkIsConnected() override;
|
||||
};
|
||||
|
||||
extern SerialModule *serialModule;
|
||||
@ -65,3 +70,5 @@ class SerialModuleRadio : public MeshModule
|
||||
};
|
||||
|
||||
extern SerialModuleRadio *serialModuleRadio;
|
||||
|
||||
#endif
|
||||
|
@ -159,7 +159,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
|
||||
const char *lastSender = getSenderShortName(*lastMeasurementPacket);
|
||||
|
||||
auto &p = lastMeasurementPacket->decoded;
|
||||
if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, Telemetry_fields, &lastMeasurement)) {
|
||||
if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, &Telemetry_msg, &lastMeasurement)) {
|
||||
display->setFont(FONT_SMALL);
|
||||
display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error");
|
||||
DEBUG_MSG("Unable to decode last packet");
|
||||
|
@ -24,14 +24,14 @@ void TraceRouteModule::updateRoute(MeshPacket* p)
|
||||
RouteDiscovery scratch;
|
||||
RouteDiscovery *updated = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
pb_decode_from_bytes(incoming.payload.bytes, incoming.payload.size, RouteDiscovery_fields, &scratch);
|
||||
pb_decode_from_bytes(incoming.payload.bytes, incoming.payload.size, &RouteDiscovery_msg, &scratch);
|
||||
updated = &scratch;
|
||||
|
||||
appendMyID(updated);
|
||||
printRoute(updated, p->from, NODENUM_BROADCAST);
|
||||
|
||||
// Set updated route to the payload of the to be flooded packet
|
||||
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), RouteDiscovery_fields, updated);
|
||||
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &RouteDiscovery_msg, updated);
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ MeshPacket* TraceRouteModule::allocReply()
|
||||
RouteDiscovery scratch;
|
||||
RouteDiscovery *updated = NULL;
|
||||
memset(&scratch, 0, sizeof(scratch));
|
||||
pb_decode_from_bytes(p.payload.bytes, p.payload.size, RouteDiscovery_fields, &scratch);
|
||||
pb_decode_from_bytes(p.payload.bytes, p.payload.size, &RouteDiscovery_msg, &scratch);
|
||||
updated = &scratch;
|
||||
|
||||
printRoute(updated, req.from, req.to);
|
||||
@ -81,6 +81,6 @@ MeshPacket* TraceRouteModule::allocReply()
|
||||
}
|
||||
|
||||
|
||||
TraceRouteModule::TraceRouteModule() : ProtobufModule("traceroute", PortNum_TRACEROUTE_APP, RouteDiscovery_fields) {
|
||||
TraceRouteModule::TraceRouteModule() : ProtobufModule("traceroute", PortNum_TRACEROUTE_APP, &RouteDiscovery_msg) {
|
||||
ourPortNum = PortNum_TRACEROUTE_APP;
|
||||
}
|
||||
|
@ -22,41 +22,32 @@ int32_t StoreForwardModule::runOnce()
|
||||
if (this->busy) {
|
||||
// Only send packets if the channel is less than 25% utilized.
|
||||
if (airTime->channelUtilizationPercent() < polite_channel_util_percent) {
|
||||
|
||||
// DEBUG_MSG("--- --- --- In busy loop 1 %d\n", this->packetHistoryTXQueue_index);
|
||||
storeForwardModule->sendPayload(this->busyTo, this->packetHistoryTXQueue_index);
|
||||
|
||||
if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) {
|
||||
strcpy(this->routerMessage, "** S&F - Done");
|
||||
storeForwardModule->sendMessage(this->busyTo, this->routerMessage);
|
||||
|
||||
// DEBUG_MSG("--- --- --- In busy loop - Done \n");
|
||||
// Tell the client we're done sending
|
||||
StoreAndForward sf = StoreAndForward_init_zero;
|
||||
sf.rr = StoreAndForward_RequestResponse_ROUTER_PING;
|
||||
storeForwardModule->sendMessage(this->busyTo, sf);
|
||||
DEBUG_MSG("*** S&F - Done. (ROUTER_PING)\n");
|
||||
this->packetHistoryTXQueue_index = 0;
|
||||
this->busy = false;
|
||||
} else {
|
||||
this->packetHistoryTXQueue_index++;
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Channel utilization is too high. Retrying later.\n");
|
||||
DEBUG_MSG("*** Channel utilization is too high. Retrying later.\n");
|
||||
}
|
||||
DEBUG_MSG("SF bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
|
||||
DEBUG_MSG("*** SF bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
|
||||
|
||||
} else if (millis() - lastHeartbeat > 300000) {
|
||||
} else if ((millis() - lastHeartbeat > (heartbeatInterval * 1000)) && (airTime->channelUtilizationPercent() < polite_channel_util_percent)) {
|
||||
lastHeartbeat = millis();
|
||||
DEBUG_MSG("Sending heartbeat\n");
|
||||
|
||||
StoreAndForward sf;
|
||||
DEBUG_MSG("*** Sending heartbeat\n");
|
||||
StoreAndForward sf = StoreAndForward_init_zero;
|
||||
sf.rr = StoreAndForward_RequestResponse_ROUTER_HEARTBEAT;
|
||||
sf.has_heartbeat = true;
|
||||
sf.heartbeat.period = 300;
|
||||
sf.heartbeat.secondary = 0; // TODO we always have one primary router for now
|
||||
|
||||
MeshPacket *p = allocDataProtobuf(sf);
|
||||
p->to = NODENUM_BROADCAST;
|
||||
p->decoded.want_response = false;
|
||||
p->priority = MeshPacket_Priority_MIN;
|
||||
service.sendToMesh(p);
|
||||
sf.which_variant = StoreAndForward_heartbeat_tag;
|
||||
sf.variant.heartbeat.period = 300;
|
||||
sf.variant.heartbeat.secondary = 0; // TODO we always have one primary router for now
|
||||
storeForwardModule->sendMessage(NODENUM_BROADCAST, sf);
|
||||
}
|
||||
return (this->packetTimeMax);
|
||||
}
|
||||
@ -74,7 +65,7 @@ void StoreForwardModule::populatePSRAM()
|
||||
https://learn.upesy.com/en/programmation/psram.html#psram-tab
|
||||
*/
|
||||
|
||||
DEBUG_MSG("Before PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(), ESP.getPsramSize());
|
||||
DEBUG_MSG("*** Before PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(), ESP.getPsramSize());
|
||||
|
||||
this->packetHistoryTXQueue =
|
||||
static_cast<PacketHistoryStruct *>(ps_calloc(this->historyReturnMax, sizeof(PacketHistoryStruct)));
|
||||
@ -83,46 +74,36 @@ void StoreForwardModule::populatePSRAM()
|
||||
Note: This needs to be done after every thing that would use PSRAM
|
||||
*/
|
||||
uint32_t numberOfPackets = (this->records ? this->records : (((ESP.getFreePsram() / 3) * 2) / sizeof(PacketHistoryStruct)));
|
||||
this->records = numberOfPackets;
|
||||
|
||||
this->packetHistory = static_cast<PacketHistoryStruct *>(ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct)));
|
||||
|
||||
DEBUG_MSG("After PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(), ESP.getPsramSize());
|
||||
DEBUG_MSG("numberOfPackets for packetHistory - %u\n", numberOfPackets);
|
||||
DEBUG_MSG("*** After PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(), ESP.getPsramSize());
|
||||
DEBUG_MSG("*** numberOfPackets for packetHistory - %u\n", numberOfPackets);
|
||||
}
|
||||
|
||||
void StoreForwardModule::historyReport()
|
||||
{
|
||||
DEBUG_MSG("Message history contains %u records\n", this->packetHistoryCurrent);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void StoreForwardModule::historySend(uint32_t msAgo, uint32_t to)
|
||||
{
|
||||
|
||||
// uint32_t packetsSent = 0;
|
||||
|
||||
uint32_t queueSize = storeForwardModule->historyQueueCreate(msAgo, to);
|
||||
|
||||
if (queueSize) {
|
||||
snprintf(this->routerMessage, 80, "** S&F - Sending %u message(s)", queueSize);
|
||||
storeForwardModule->sendMessage(to, this->routerMessage);
|
||||
|
||||
DEBUG_MSG ("*** S&F - Sending %u message(s)\n", queueSize);
|
||||
this->busy = true; // runOnce() will pickup the next steps once busy = true.
|
||||
this->busyTo = to;
|
||||
|
||||
} else {
|
||||
strcpy(this->routerMessage, "** S&F - No history to send");
|
||||
storeForwardModule->sendMessage(to, this->routerMessage);
|
||||
DEBUG_MSG ("*** S&F - No history to send\n");
|
||||
}
|
||||
StoreAndForward sf = StoreAndForward_init_zero;
|
||||
sf.rr = StoreAndForward_RequestResponse_ROUTER_HISTORY;
|
||||
sf.which_variant = StoreAndForward_history_tag;
|
||||
sf.variant.history.history_messages = queueSize;
|
||||
sf.variant.history.window = msAgo;
|
||||
storeForwardModule->sendMessage(to, sf);
|
||||
}
|
||||
|
||||
uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
|
||||
{
|
||||
|
||||
// uint32_t packetHistoryTXQueueIndex = 0;
|
||||
|
||||
this->packetHistoryTXQueue_size = 0;
|
||||
|
||||
for (int i = 0; i < this->packetHistoryCurrent; i++) {
|
||||
@ -133,7 +114,7 @@ uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
|
||||
DEBUG_MSG("SF historyQueueCreate - math %d\n", (millis() - msAgo));
|
||||
*/
|
||||
if (this->packetHistory[i].time && (this->packetHistory[i].time < (millis() - msAgo))) {
|
||||
DEBUG_MSG("SF historyQueueCreate - Time matches - ok\n");
|
||||
DEBUG_MSG("*** SF historyQueueCreate - Time matches - ok\n");
|
||||
/*
|
||||
Copy the messages that were received by the router in the last msAgo
|
||||
to the packetHistoryTXQueue structure.
|
||||
@ -144,7 +125,6 @@ uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
|
||||
if ((this->packetHistory[i].to & NODENUM_BROADCAST) == NODENUM_BROADCAST ||
|
||||
((this->packetHistory[i].to & NODENUM_BROADCAST) == to)) {
|
||||
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].time = this->packetHistory[i].time;
|
||||
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].time = this->packetHistory[i].time;
|
||||
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].to = this->packetHistory[i].to;
|
||||
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].from = this->packetHistory[i].from;
|
||||
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].channel = this->packetHistory[i].channel;
|
||||
@ -153,9 +133,8 @@ uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
|
||||
Constants_DATA_PAYLOAD_LEN);
|
||||
this->packetHistoryTXQueue_size++;
|
||||
|
||||
DEBUG_MSG("PacketHistoryStruct time=%d\n", this->packetHistory[i].time);
|
||||
DEBUG_MSG("PacketHistoryStruct msg=%.*s\n", this->packetHistory[i].payload);
|
||||
// DEBUG_MSG("PacketHistoryStruct msg=%.*s\n", this->packetHistoryTXQueue[packetHistoryTXQueueIndex].payload);
|
||||
DEBUG_MSG("*** PacketHistoryStruct time=%d\n", this->packetHistory[i].time);
|
||||
DEBUG_MSG("*** PacketHistoryStruct msg=%s\n", this->packetHistory[i].payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -174,6 +153,7 @@ void StoreForwardModule::historyAdd(const MeshPacket &mp)
|
||||
memcpy(this->packetHistory[this->packetHistoryCurrent].payload, p.payload.bytes, Constants_DATA_PAYLOAD_LEN);
|
||||
|
||||
this->packetHistoryCurrent++;
|
||||
this->packetHistoryMax++;
|
||||
}
|
||||
|
||||
MeshPacket *StoreForwardModule::allocReply()
|
||||
@ -184,7 +164,7 @@ MeshPacket *StoreForwardModule::allocReply()
|
||||
|
||||
void StoreForwardModule::sendPayload(NodeNum dest, uint32_t packetHistory_index)
|
||||
{
|
||||
DEBUG_MSG("Sending S&F Payload\n");
|
||||
DEBUG_MSG("*** Sending S&F Payload\n");
|
||||
MeshPacket *p = allocReply();
|
||||
|
||||
p->to = dest;
|
||||
@ -203,12 +183,14 @@ void StoreForwardModule::sendPayload(NodeNum dest, uint32_t packetHistory_index)
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
void StoreForwardModule::sendMessage(NodeNum dest, char *str)
|
||||
void StoreForwardModule::sendMessage(NodeNum dest, StoreAndForward &payload)
|
||||
{
|
||||
MeshPacket *p = allocReply();
|
||||
MeshPacket *p = allocDataProtobuf(payload);
|
||||
|
||||
p->to = dest;
|
||||
|
||||
p->priority = MeshPacket_Priority_MIN;
|
||||
|
||||
// FIXME - Determine if the delayed packet is broadcast or delayed. For now, assume
|
||||
// everything is broadcast.
|
||||
p->delayed = MeshPacket_Delayed_DELAYED_BROADCAST;
|
||||
@ -216,13 +198,37 @@ void StoreForwardModule::sendMessage(NodeNum dest, char *str)
|
||||
// Let's assume that if the router received the S&F request that the client is in range.
|
||||
// TODO: Make this configurable.
|
||||
p->want_ack = false;
|
||||
|
||||
p->decoded.payload.size = strlen(str); // You must specify how many bytes are in the reply
|
||||
memcpy(p->decoded.payload.bytes, str, strlen(str));
|
||||
p->decoded.want_response = false;
|
||||
|
||||
service.sendToMesh(p);
|
||||
}
|
||||
|
||||
// HardwareMessage_init_default
|
||||
void StoreForwardModule::sendMessage(NodeNum dest, StoreAndForward_RequestResponse rr)
|
||||
{
|
||||
// Craft an empty response, save some bytes in flash
|
||||
StoreAndForward sf = StoreAndForward_init_zero;
|
||||
sf.rr = rr;
|
||||
storeForwardModule->sendMessage(dest, sf);
|
||||
}
|
||||
|
||||
void StoreForwardModule::statsSend(uint32_t to)
|
||||
{
|
||||
StoreAndForward sf = StoreAndForward_init_zero;
|
||||
|
||||
sf.rr = StoreAndForward_RequestResponse_ROUTER_STATS;
|
||||
sf.which_variant = StoreAndForward_stats_tag;
|
||||
sf.variant.stats.messages_total = this->packetHistoryMax;
|
||||
sf.variant.stats.messages_saved = this->packetHistoryCurrent;
|
||||
sf.variant.stats.messages_max = this->records;
|
||||
sf.variant.stats.up_time = millis() / 1000;
|
||||
sf.variant.stats.requests = this->requests;
|
||||
sf.variant.stats.requests_history = this->requests_history;
|
||||
sf.variant.stats.heartbeat = this->heartbeat;
|
||||
sf.variant.stats.return_max = this->historyReturnMax;
|
||||
sf.variant.stats.return_window = this->historyReturnWindow;
|
||||
|
||||
DEBUG_MSG("*** Sending S&F Stats\n");
|
||||
storeForwardModule->sendMessage(to, sf);
|
||||
}
|
||||
|
||||
ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
|
||||
@ -230,46 +236,28 @@ ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
|
||||
#ifdef ARCH_ESP32
|
||||
if (moduleConfig.store_forward.enabled) {
|
||||
|
||||
DEBUG_MSG("--- S&F Received something\n");
|
||||
|
||||
// The router node should not be sending messages as a client. Unless he is a ROUTER_CLIENT
|
||||
if ((getFrom(&mp) != nodeDB.getNodeNum()) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
|
||||
|
||||
if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
|
||||
DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n");
|
||||
|
||||
auto &p = mp.decoded;
|
||||
|
||||
if ((p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 0x00)) {
|
||||
DEBUG_MSG("--- --- --- Request to send\n");
|
||||
|
||||
// Send the last 60 minutes of messages.
|
||||
if (this->busy) {
|
||||
strcpy(this->routerMessage, "** S&F - Busy. Try again shortly.");
|
||||
storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage);
|
||||
} else {
|
||||
storeForwardModule->historySend(1000 * 60, getFrom(&mp));
|
||||
}
|
||||
|
||||
} else if ((p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 'm') &&
|
||||
(p.payload.bytes[3] == 0x00)) {
|
||||
strlcpy(this->routerMessage,
|
||||
"01234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"01234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
"01234567890123456789012345678901234567890123456789012345678901234567890123456",
|
||||
sizeof(this->routerMessage));
|
||||
storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage);
|
||||
|
||||
} else {
|
||||
storeForwardModule->historyAdd(mp);
|
||||
}
|
||||
storeForwardModule->historyAdd(mp);
|
||||
DEBUG_MSG("*** S&F stored. Message history contains %u records now.\n", this->packetHistoryCurrent);
|
||||
|
||||
} else if (mp.decoded.portnum == PortNum_STORE_FORWARD_APP) {
|
||||
DEBUG_MSG("Packet came from an PortNum_STORE_FORWARD_APP port %u\n", mp.decoded.portnum);
|
||||
|
||||
} else {
|
||||
DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.portnum);
|
||||
}
|
||||
auto &p = mp.decoded;
|
||||
StoreAndForward scratch;
|
||||
StoreAndForward *decoded = NULL;
|
||||
if (mp.which_payload_variant == MeshPacket_decoded_tag) {
|
||||
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &StoreAndForward_msg, &scratch)) {
|
||||
decoded = &scratch;
|
||||
} else {
|
||||
DEBUG_MSG("Error decoding protobuf module!\n");
|
||||
// if we can't decode it, nobody can process it!
|
||||
return ProcessMessage::STOP;
|
||||
}
|
||||
return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE;
|
||||
}
|
||||
} // all others are irrelevant
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,95 +273,127 @@ bool StoreForwardModule::handleReceivedProtobuf(const MeshPacket &mp, StoreAndFo
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mp.decoded.portnum != PortNum_STORE_FORWARD_APP) {
|
||||
DEBUG_MSG("Packet came from port %u\n", mp.decoded.portnum);
|
||||
return false;
|
||||
} else {
|
||||
DEBUG_MSG("Packet came from PortNum_STORE_FORWARD_APP port %u\n", mp.decoded.portnum);
|
||||
|
||||
requests++;
|
||||
|
||||
switch (p->rr) {
|
||||
case StoreAndForward_RequestResponse_CLIENT_ERROR:
|
||||
case StoreAndForward_RequestResponse_CLIENT_ABORT:
|
||||
if(is_server) {
|
||||
// Do nothing
|
||||
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_ERROR\n");
|
||||
// stop sending stuff, the client wants to abort or has another error
|
||||
if ((this->busy) && (this->busyTo == getFrom(&mp))) {
|
||||
DEBUG_MSG("*** Client in ERROR or ABORT requested\n");
|
||||
this->packetHistoryTXQueue_index = 0;
|
||||
this->busy = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_CLIENT_HISTORY:
|
||||
if(is_server) {
|
||||
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_HISTORY\n");
|
||||
requests_history++;
|
||||
DEBUG_MSG("*** Client Request to send HISTORY\n");
|
||||
// Send the last 60 minutes of messages.
|
||||
if (this->busy) {
|
||||
strcpy(this->routerMessage, "** S&F - Busy. Try again shortly.");
|
||||
storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage);
|
||||
storeForwardModule->sendMessage(getFrom(&mp), StoreAndForward_RequestResponse_ROUTER_BUSY);
|
||||
DEBUG_MSG("*** S&F - Busy. Try again shortly.\n");
|
||||
} else {
|
||||
storeForwardModule->historySend(1000 * 60, getFrom(&mp));
|
||||
if ((p->which_variant == StoreAndForward_history_tag) && (p->variant.history.window > 0)){
|
||||
storeForwardModule->historySend(p->variant.history.window * 60000, getFrom(&mp)); // window is in minutes
|
||||
} else {
|
||||
storeForwardModule->historySend(historyReturnWindow * 60000, getFrom(&mp)); // defaults to 4 hours
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_CLIENT_PING:
|
||||
if(is_server) {
|
||||
// Do nothing
|
||||
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_PING\n");
|
||||
DEBUG_MSG("*** StoreAndForward_RequestResponse_CLIENT_PING\n");
|
||||
// respond with a ROUTER PONG
|
||||
storeForwardModule->sendMessage(getFrom(&mp), StoreAndForward_RequestResponse_ROUTER_PONG);
|
||||
}
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_CLIENT_PONG:
|
||||
if(is_server) {
|
||||
// Do nothing
|
||||
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_PONG\n");
|
||||
DEBUG_MSG("*** StoreAndForward_RequestResponse_CLIENT_PONG\n");
|
||||
// The Client is alive, update NodeDB
|
||||
nodeDB.updateFrom(mp);
|
||||
}
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_CLIENT_STATS:
|
||||
if(is_server) {
|
||||
// Do nothing
|
||||
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_STATS\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_ROUTER_BUSY:
|
||||
if(is_client) {
|
||||
// Do nothing
|
||||
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_BUSY\n");
|
||||
DEBUG_MSG("*** Client Request to send STATS\n");
|
||||
if (this->busy) {
|
||||
storeForwardModule->sendMessage(getFrom(&mp), StoreAndForward_RequestResponse_ROUTER_BUSY);
|
||||
DEBUG_MSG("*** S&F - Busy. Try again shortly.\n");
|
||||
} else {
|
||||
storeForwardModule->statsSend(getFrom(&mp));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_ROUTER_ERROR:
|
||||
case StoreAndForward_RequestResponse_ROUTER_BUSY:
|
||||
if(is_client) {
|
||||
// Do nothing
|
||||
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_ERROR\n");
|
||||
DEBUG_MSG("*** StoreAndForward_RequestResponse_ROUTER_BUSY\n");
|
||||
// retry in messages_saved * packetTimeMax ms
|
||||
retry_delay = millis() + packetHistoryCurrent * packetTimeMax * (StoreAndForward_RequestResponse_ROUTER_ERROR ? 2 : 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_ROUTER_PONG:
|
||||
// A router responded, this is equal to receiving a heartbeat
|
||||
case StoreAndForward_RequestResponse_ROUTER_HEARTBEAT:
|
||||
if(is_client) {
|
||||
// Do nothing
|
||||
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_HEARTBEAT\n");
|
||||
// register heartbeat and interval
|
||||
if (p->which_variant == StoreAndForward_heartbeat_tag) {
|
||||
heartbeatInterval = p->variant.heartbeat.period;
|
||||
}
|
||||
lastHeartbeat = millis();
|
||||
DEBUG_MSG("*** StoreAndForward Heartbeat received\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_ROUTER_PING:
|
||||
if(is_client) {
|
||||
// Do nothing
|
||||
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_PING\n");
|
||||
DEBUG_MSG("*** StoreAndForward_RequestResponse_ROUTER_PING\n");
|
||||
// respond with a CLIENT PONG
|
||||
storeForwardModule->sendMessage(getFrom(&mp), StoreAndForward_RequestResponse_CLIENT_PONG);
|
||||
}
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_ROUTER_PONG:
|
||||
case StoreAndForward_RequestResponse_ROUTER_STATS:
|
||||
if(is_client) {
|
||||
// Do nothing
|
||||
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_PONG\n");
|
||||
DEBUG_MSG("*** Router Response STATS\n");
|
||||
// These fields only have informational purpose on a client. Fill them to consume later.
|
||||
if (p->which_variant == StoreAndForward_stats_tag) {
|
||||
this->packetHistoryMax = p->variant.stats.messages_total;
|
||||
this->packetHistoryCurrent = p->variant.stats.messages_saved;
|
||||
this->records = p->variant.stats.messages_max;
|
||||
this->requests = p->variant.stats.requests;
|
||||
this->requests_history = p->variant.stats.requests_history;
|
||||
this->heartbeat = p->variant.stats.heartbeat;
|
||||
this->historyReturnMax = p->variant.stats.return_max;
|
||||
this->historyReturnWindow = p->variant.stats.return_window;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case StoreAndForward_RequestResponse_ROUTER_HISTORY:
|
||||
if(is_client) {
|
||||
// These fields only have informational purpose on a client. Fill them to consume later.
|
||||
if (p->which_variant == StoreAndForward_history_tag) {
|
||||
this->historyReturnWindow = p->variant.history.window / 60000;
|
||||
DEBUG_MSG("*** Router Response HISTORY - Sending %d messages from last %d minutes\n", p->variant.history.history_messages, this->historyReturnWindow);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0); // unexpected state - FIXME, make an error code and reboot
|
||||
}
|
||||
}
|
||||
|
||||
return true; // There's no need for others to look at this message.
|
||||
}
|
||||
|
||||
@ -398,7 +418,7 @@ StoreForwardModule::StoreForwardModule()
|
||||
|
||||
// Router
|
||||
if ((config.device.role == Config_DeviceConfig_Role_ROUTER) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
|
||||
DEBUG_MSG("Initializing Store & Forward Module in Router mode\n");
|
||||
DEBUG_MSG("*** Initializing Store & Forward Module in Router mode\n");
|
||||
if (ESP.getPsramSize() > 0) {
|
||||
if (ESP.getFreePsram() >= 1024 * 1024) {
|
||||
|
||||
@ -424,19 +444,19 @@ StoreForwardModule::StoreForwardModule()
|
||||
this->populatePSRAM();
|
||||
is_server = true;
|
||||
} else {
|
||||
DEBUG_MSG("Device has less than 1M of PSRAM free.\n");
|
||||
DEBUG_MSG("Store & Forward Module - disabling server.\n");
|
||||
DEBUG_MSG("*** Device has less than 1M of PSRAM free.\n");
|
||||
DEBUG_MSG("*** Store & Forward Module - disabling server.\n");
|
||||
}
|
||||
} else {
|
||||
DEBUG_MSG("Device doesn't have PSRAM.\n");
|
||||
DEBUG_MSG("Store & Forward Module - disabling server.\n");
|
||||
DEBUG_MSG("*** Device doesn't have PSRAM.\n");
|
||||
DEBUG_MSG("*** Store & Forward Module - disabling server.\n");
|
||||
}
|
||||
|
||||
// Client
|
||||
}
|
||||
if ((config.device.role == Config_DeviceConfig_Role_CLIENT) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
|
||||
is_client = true;
|
||||
DEBUG_MSG("Initializing Store & Forward Module in Client mode\n");
|
||||
DEBUG_MSG("*** Initializing Store & Forward Module in Client mode\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -24,10 +24,9 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
|
||||
uint32_t busyTo = 0;
|
||||
char routerMessage[Constants_DATA_PAYLOAD_LEN] = {0};
|
||||
|
||||
uint32_t receivedRecord[50][2] = {{0}};
|
||||
|
||||
PacketHistoryStruct *packetHistory = 0;
|
||||
uint32_t packetHistoryCurrent = 0;
|
||||
uint32_t packetHistoryMax = 0;
|
||||
|
||||
PacketHistoryStruct *packetHistoryTXQueue = 0;
|
||||
uint32_t packetHistoryTXQueue_size = 0;
|
||||
@ -35,20 +34,21 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
|
||||
|
||||
uint32_t packetTimeMax = 5000;
|
||||
|
||||
unsigned long lastHeartbeat = 0;
|
||||
|
||||
bool is_client = false;
|
||||
bool is_server = false;
|
||||
|
||||
public:
|
||||
StoreForwardModule();
|
||||
|
||||
unsigned long lastHeartbeat = 0;
|
||||
uint32_t heartbeatInterval = 300;
|
||||
|
||||
/**
|
||||
Update our local reference of when we last saw that node.
|
||||
@return 0 if we have never seen that node before otherwise return the last time we saw the node.
|
||||
*/
|
||||
void historyAdd(const MeshPacket &mp);
|
||||
void historyReport();
|
||||
void statsSend(uint32_t to);
|
||||
void historySend(uint32_t msAgo, uint32_t to);
|
||||
|
||||
uint32_t historyQueueCreate(uint32_t msAgo, uint32_t to);
|
||||
@ -57,12 +57,23 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
|
||||
* Send our payload into the mesh
|
||||
*/
|
||||
void sendPayload(NodeNum dest = NODENUM_BROADCAST, uint32_t packetHistory_index = 0);
|
||||
void sendMessage(NodeNum dest, char *str);
|
||||
void sendMessage(NodeNum dest, StoreAndForward &payload);
|
||||
void sendMessage(NodeNum dest, StoreAndForward_RequestResponse rr);
|
||||
|
||||
virtual MeshPacket *allocReply() override;
|
||||
/*
|
||||
Override the wantPortnum method.
|
||||
*/
|
||||
virtual bool wantPortnum(PortNum p) { return true; };
|
||||
-Override the wantPacket method.
|
||||
*/
|
||||
virtual bool wantPacket(const MeshPacket *p) override
|
||||
{
|
||||
switch(p->decoded.portnum) {
|
||||
case PortNum_TEXT_MESSAGE_APP:
|
||||
case PortNum_STORE_FORWARD_APP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void populatePSRAM();
|
||||
@ -73,6 +84,12 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
|
||||
uint32_t records = 0; // Calculated
|
||||
bool heartbeat = false; // No heartbeat.
|
||||
|
||||
// stats
|
||||
uint32_t requests = 0;
|
||||
uint32_t requests_history = 0;
|
||||
|
||||
uint32_t retry_delay = 0;
|
||||
|
||||
protected:
|
||||
virtual int32_t runOnce() override;
|
||||
|
||||
|
@ -88,6 +88,8 @@
|
||||
#define HW_VENDOR HardwareModel_HELTEC_V3
|
||||
#elif defined(HELTEC_WSL_V3)
|
||||
#define HW_VENDOR HardwareModel_HELTEC_WSL_V3
|
||||
#elif defined(TLORA_T3S3_V1)
|
||||
#define HW_VENDOR HardwareModel_TLORA_T3_S3
|
||||
#endif
|
||||
|
||||
//
|
||||
|
@ -201,7 +201,7 @@ void SimRadio::startSend(MeshPacket * txp)
|
||||
} else {
|
||||
DEBUG_MSG("Payload size is larger than compressed message allows! Sending empty payload.\n");
|
||||
}
|
||||
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), Compressed_fields, &c);
|
||||
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &Compressed_msg, &c);
|
||||
p->decoded.portnum = PortNum_SIMULATOR_APP;
|
||||
service.sendToPhone(p); // Sending back to simulator
|
||||
}
|
||||
|
34
variants/tlora_t3s3_v1/pins_arduino.h
Normal file
34
variants/tlora_t3s3_v1/pins_arduino.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define USB_VID 0x303a
|
||||
#define USB_PID 0x1001
|
||||
|
||||
#define EXTERNAL_NUM_INTERRUPTS 46
|
||||
#define NUM_DIGITAL_PINS 48
|
||||
#define NUM_ANALOG_INPUTS 20
|
||||
|
||||
#define analogInputToDigitalPin(p) (((p)<20)?(analogChannelToDigitalPin(p)):-1)
|
||||
#define digitalPinToInterrupt(p) (((p)<48)?(p):-1)
|
||||
#define digitalPinHasPWM(p) (p < 46)
|
||||
|
||||
// The default Wire will be mapped to PMU and RTC
|
||||
static const uint8_t SDA = 18;
|
||||
static const uint8_t SCL = 17;
|
||||
|
||||
// Default SPI will be mapped to Radio
|
||||
static const uint8_t SS = 7;
|
||||
static const uint8_t MOSI = 6;
|
||||
static const uint8_t MISO = 3;
|
||||
static const uint8_t SCK = 5;
|
||||
|
||||
#define SPI_MOSI (11)
|
||||
#define SPI_SCK (14)
|
||||
#define SPI_MISO (2)
|
||||
#define SPI_CS (13)
|
||||
|
||||
#define SDCARD_CS SPI_CS
|
||||
|
||||
#endif /* Pins_Arduino_h */
|
9
variants/tlora_t3s3_v1/platformio.ini
Normal file
9
variants/tlora_t3s3_v1/platformio.ini
Normal file
@ -0,0 +1,9 @@
|
||||
[env:tlora-t3s3-v1]
|
||||
extends = esp32s3_base
|
||||
board = tlora-t3s3-v1
|
||||
lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
caveman99/ESP32 Codec2@^1.0.1
|
||||
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_T3S3_V1 -I variants/tlora_t3s3_v1
|
54
variants/tlora_t3s3_v1/variant.h
Normal file
54
variants/tlora_t3s3_v1/variant.h
Normal file
@ -0,0 +1,54 @@
|
||||
#undef GPS_RX_PIN
|
||||
#undef GPS_TX_PIN
|
||||
|
||||
#define HAS_SDCARD
|
||||
#define SDCARD_USE_SPI1
|
||||
|
||||
#define USE_SSD1306
|
||||
|
||||
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
|
||||
// ratio of voltage divider = 2.0 (R42=100k, R43=100k)
|
||||
#define ADC_MULTIPLIER 2.11 // 2.0 + 10% for correction of display undervoltage.
|
||||
|
||||
#define I2C_SDA 18 // I2C pins for this board
|
||||
#define I2C_SCL 17
|
||||
|
||||
#define LED_PIN 37 // If defined we will blink this LED
|
||||
#define BUTTON_PIN 0 // If defined, this will be used for user button presses,
|
||||
|
||||
#define BUTTON_NEED_PULLUP
|
||||
|
||||
// TTGO uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
|
||||
// not found then probe for SX1262
|
||||
#define USE_RF95 // RFM95/SX127x
|
||||
#define USE_SX1262
|
||||
#define USE_SX1280
|
||||
|
||||
#define RF95_SCK 5
|
||||
#define RF95_MISO 3
|
||||
#define RF95_MOSI 6
|
||||
#define RF95_NSS 7
|
||||
|
||||
#define LORA_RESET 8
|
||||
#define LORA_DIO0 9
|
||||
#define LORA_DIO1 9
|
||||
#define LORA_DIO2 33 // SX1262 BUSY
|
||||
#define LORA_DIO3 34 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
|
||||
|
||||
#ifdef USE_SX1262
|
||||
#define SX126X_CS RF95_NSS // FIXME - we really should define LORA_CS instead
|
||||
#define SX126X_DIO1 LORA_DIO1
|
||||
#define SX126X_BUSY 36
|
||||
#define SX126X_RESET LORA_RESET
|
||||
#define SX126X_RXEN 21
|
||||
#define SX126X_TXEN 10
|
||||
#endif
|
||||
|
||||
#ifdef USE_SX1280
|
||||
#define SX128X_CS RF95_NSS
|
||||
#define SX128X_DIO1 LORA_DIO1
|
||||
#define SX128X_BUSY 36
|
||||
#define SX128X_RESET LORA_RESET
|
||||
#define SX128X_RXEN 21
|
||||
#define SX128X_TXEN 10
|
||||
#endif
|
@ -5,7 +5,5 @@ lib_deps =
|
||||
${esp32_base.lib_deps}
|
||||
caveman99/ESP32 Codec2@^1.0.1
|
||||
|
||||
; the RADIOLIB_GODMODE flag can be removed once the next version of RadioLib is released. (>5.5.0)
|
||||
|
||||
build_flags =
|
||||
${esp32_base.build_flags} -D TLORA_V2_1_18 -I variants/tlora_v2_1_18 -D RADIOLIB_GODMODE
|
||||
${esp32_base.build_flags} -D TLORA_V2_1_18 -I variants/tlora_v2_1_18
|
Loading…
Reference in New Issue
Block a user