diff --git a/src/airtime.cpp b/src/airtime.cpp index 66f4a0a57..8d1800d52 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -5,10 +5,6 @@ AirTime *airTime; -// A reminder that there are 3600 seconds in an hour so I don't have -// to keep googling it. -// This can be changed to a smaller number to speed up testing. -// uint32_t secondsPerPeriod = 3600; uint32_t lastMillis = 0; uint32_t secSinceBoot = 0; @@ -17,25 +13,23 @@ uint32_t secSinceBoot = 0; // Don't read out of this directly. Use the helper functions. struct airtimeStruct { - uint16_t periodTX[periodsToLog]; // AirTime transmitted - uint16_t periodRX[periodsToLog]; // AirTime received and repeated (Only valid mesh packets) - uint16_t periodRX_ALL[periodsToLog]; // AirTime received regardless of valid mesh packet. Could include noise. + uint32_t periodTX[periodsToLog]; // AirTime transmitted + uint32_t periodRX[periodsToLog]; // AirTime received and repeated (Only valid mesh packets) + uint32_t periodRX_ALL[periodsToLog]; // AirTime received regardless of valid mesh packet. Could include noise. uint8_t lastPeriodIndex; } airtimes; void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms) { - // DEBUG_MSG("Packet - logAirtime()\n"); - if (reportType == TX_LOG) { - DEBUG_MSG("AirTime - Packet transmitted : %us %ums\n", (uint32_t)round((float)airtime_ms / (float)1000), airtime_ms); - airtimes.periodTX[0] = airtimes.periodTX[0] + round(airtime_ms / 1000); + DEBUG_MSG("AirTime - Packet transmitted : %ums\n", airtime_ms); + airtimes.periodTX[0] = airtimes.periodTX[0] + airtime_ms; } else if (reportType == RX_LOG) { - DEBUG_MSG("AirTime - Packet received : %us %ums\n", (uint32_t)round((float)airtime_ms / (float)1000), airtime_ms); - airtimes.periodRX[0] = airtimes.periodRX[0] + round(airtime_ms / 1000); + DEBUG_MSG("AirTime - Packet received : %ums\n", airtime_ms); + airtimes.periodRX[0] = airtimes.periodRX[0] + airtime_ms; } else if (reportType == RX_ALL_LOG) { - DEBUG_MSG("AirTime - Packet received (noise?) : %us %ums\n", (uint32_t)round((float)airtime_ms / (float)1000), airtime_ms); - airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + round(airtime_ms / 1000); + DEBUG_MSG("AirTime - Packet received (noise?) : %ums\n", airtime_ms); + airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + airtime_ms; } else { DEBUG_MSG("AirTime - Unknown report time. This should never happen!!\n"); } @@ -65,7 +59,7 @@ void airtimeRotatePeriod() } } -uint16_t *airtimeReport(reportTypes reportType) +uint32_t *airtimeReport(reportTypes reportType) { if (reportType == TX_LOG) { diff --git a/src/airtime.h b/src/airtime.h index 439670010..d78db86a4 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -34,7 +34,7 @@ uint8_t getPeriodsToLog(); uint32_t getSecondsSinceBoot(); -uint16_t *airtimeReport(reportTypes reportType); +uint32_t *airtimeReport(reportTypes reportType); uint32_t getSecondsPerPeriod(); diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 7a43c45ff..eee8280c5 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -1,6 +1,7 @@ #include "plugins/NodeInfoPlugin.h" #include "plugins/PositionPlugin.h" #include "plugins/ReplyPlugin.h" +#include "plugins/SerialPlugin.h" #include "plugins/RemoteHardwarePlugin.h" #include "plugins/TextMessagePlugin.h" @@ -17,4 +18,5 @@ void setupPlugins() { new RemoteHardwarePlugin(); new ReplyPlugin(); + new SerialPlugin(); // Maintained by MC Hamster (Jm Casler) jm@casler.org } \ No newline at end of file diff --git a/src/plugins/SerialPlugin.cpp b/src/plugins/SerialPlugin.cpp new file mode 100644 index 000000000..cc355c066 --- /dev/null +++ b/src/plugins/SerialPlugin.cpp @@ -0,0 +1,161 @@ +#include "SerialPlugin.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include + +#include + +/* + SerialPlugin + An overly simplistic interface to send messages over the mesh network by sending strings + over a serial port. + + Originally designed for lora32 v1.0 + Manufacture Info: http://www.lilygo.cn/prod_view.aspx?TypeId=50003&Id=1133&FId=t3:50003:3 + Pin Mapping: http://ae01.alicdn.com/kf/HTB1fLBcxkSWBuNjSszdq6zeSpXaJ.jpg + + This will probably and most likely work on other esp32 devices, given possible change the RX/TX + selection. + + Need help with this plugin? Post your question on the Meshtastic Discourse: + https://meshtastic.discourse.group + + Basic Usage: + + 1) Enable the plugin by setting SERIALPLUGIN_ENABLED to 1. + 2) Set the pins (RXD2 / TXD2) for your preferred RX and TX GPIO pins. + 3) Set SERIALPLUGIN_TIMEOUT to the amount of time to wait before we consider + your packet as "done". + 4) (Optional) In SerialPlugin.h set the port to PortNum_TEXT_MESSAGE_APP if you want to + send messages to/from the general text message channel. + 5) Connect to your device over the serial interface at 38400 8N1. + 6) Send a packet up to 240 bytes in length. This will get relayed over the mesh network. + 7) (Optional) Set SERIALPLUGIN_ECHO to 1 and any message you send out will be echoed back + to your device. + + TODO (in this order): + * Once protobufs regenerated with the new port, update SerialPlugin.h + * Ensure this works on a tbeam + * Define a verbose RX mode to report on mesh and packet infomration. + - This won't happen any time soon. + + KNOWN PROBLEMS + * Until the plugin is initilized by the startup sequence, the TX pin is in a floating + state. Device connected to that pin may see this as "noise". + + +*/ + +#define RXD2 16 +#define TXD2 17 +#define SERIALPLUGIN_RX_BUFFER 128 +#define SERIALPLUGIN_STRING_MAX Constants_DATA_PAYLOAD_LEN +#define SERIALPLUGIN_TIMEOUT 250 +#define SERIALPLUGIN_BAUD 38400 +#define SERIALPLUGIN_ENABLED 1 +#define SERIALPLUGIN_ECHO 0 +#define SERIALPLUGIN_ACK 0 + +SerialPlugin *serialPlugin; +SerialPluginRadio *serialPluginRadio; + +SerialPlugin::SerialPlugin() : concurrency::OSThread("SerialPlugin") {} + +char serialStringChar[Constants_DATA_PAYLOAD_LEN]; + +int32_t SerialPlugin::runOnce() +{ + +#if SERIALPLUGIN_ENABLED == 1 + + if (firstTime) { + + // Interface with the serial peripheral from in here. + DEBUG_MSG("Initilizing serial peripheral interface\n"); + + Serial2.begin(SERIALPLUGIN_BAUD, SERIAL_8N1, RXD2, TXD2); + Serial2.setTimeout(SERIALPLUGIN_TIMEOUT); // Number of MS to wait to set the timeout for the string. + Serial2.setRxBufferSize(SERIALPLUGIN_RX_BUFFER); + + serialPluginRadio = new SerialPluginRadio(); + + firstTime = 0; + + } else { + String serialString; + + while (Serial2.available()) { + serialString = Serial2.readString(); + serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN); + + serialPluginRadio->sendPayload(); + + DEBUG_MSG("Received: %s\n", serialStringChar); + } + } + + return (10); +#else + DEBUG_MSG("Serial Plugin Disabled\n"); + + return (INT32_MAX); +#endif +} + +MeshPacket *SerialPluginRadio::allocReply() +{ + + auto reply = allocDataPacket(); // Allocate a packet for sending + + return reply; +} + +void SerialPluginRadio::sendPayload(NodeNum dest, bool wantReplies) +{ + MeshPacket *p = allocReply(); + p->to = dest; + p->decoded.want_response = wantReplies; + + p->want_ack = SERIALPLUGIN_ACK; + + p->decoded.data.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply + memcpy(p->decoded.data.payload.bytes, serialStringChar, p->decoded.data.payload.size); + + service.sendToMesh(p); +} + +bool SerialPluginRadio::handleReceived(const MeshPacket &mp) +{ + auto &p = mp.decoded.data; + // DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n", nodeDB.getNodeNum(), + // mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes); + + if (mp.from == nodeDB.getNodeNum()) { + + /* + * If SERIALPLUGIN_ECHO is true, then echo the packets that are sent out back to the TX + * of the serial interface. + */ + if (SERIALPLUGIN_ECHO) { + + // For some reason, we get the packet back twice when we send out of the radio. + // TODO: need to find out why. + if (lastRxID != mp.id) { + lastRxID = mp.id; + // DEBUG_MSG("* * Message came this device\n"); + // Serial2.println("* * Message came this device"); + Serial2.printf("%s", p.payload.bytes); + } + } + + } else { + // DEBUG_MSG("* * Message came from the mesh\n"); + // Serial2.println("* * Message came from the mesh"); + Serial2.printf("%s", p.payload.bytes); + } + + return true; // Let others look at this message also if they want +} diff --git a/src/plugins/SerialPlugin.h b/src/plugins/SerialPlugin.h new file mode 100644 index 000000000..c6d79f3eb --- /dev/null +++ b/src/plugins/SerialPlugin.h @@ -0,0 +1,54 @@ +#pragma once + +#include "SinglePortPlugin.h" +#include "concurrency/OSThread.h" +#include "configuration.h" +#include +#include + +class SerialPlugin : private concurrency::OSThread +{ + bool firstTime = 1; + + public: + SerialPlugin(); + + protected: + virtual int32_t runOnce(); +}; + +extern SerialPlugin *serialPlugin; + +/* + * Radio interface for SerialPlugin + * + */ +class SerialPluginRadio : public SinglePortPlugin +{ + uint32_t lastRxID; + + public: + /* + TODO: Switch this to PortNum_SERIAL_APP once the change is able to be merged back here + from the main code. + */ + + SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_TEXT_MESSAGE_APP) {} + // SerialPluginRadio() : SinglePortPlugin("SerialPluginRadio", PortNum_SERIAL_APP) {} + + /** + * Send our payload into the mesh + */ + void sendPayload(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false); + + protected: + virtual MeshPacket *allocReply(); + + /** Called to handle a particular incoming message + + @return true if you've guaranteed you've handled this message and no other handlers should be considered for it + */ + virtual bool handleReceived(const MeshPacket &mp); +}; + +extern SerialPluginRadio *serialPluginRadio; \ No newline at end of file