2022-02-27 09:27:17 +00:00
|
|
|
#include "RangeTestModule.h"
|
2021-01-31 17:12:36 +00:00
|
|
|
#include "MeshService.h"
|
|
|
|
#include "NodeDB.h"
|
2021-02-15 05:34:47 +00:00
|
|
|
#include "PowerFSM.h"
|
2021-01-31 17:12:36 +00:00
|
|
|
#include "RTC.h"
|
|
|
|
#include "Router.h"
|
2022-01-27 06:20:13 +00:00
|
|
|
#include "airtime.h"
|
2021-01-31 17:12:36 +00:00
|
|
|
#include "configuration.h"
|
2021-10-09 17:28:51 +00:00
|
|
|
#include "gps/GeoCoord.h"
|
2021-01-31 17:12:36 +00:00
|
|
|
#include <Arduino.h>
|
2022-02-14 17:45:29 +00:00
|
|
|
#include <FSCommon.h>
|
2021-02-14 21:31:11 +00:00
|
|
|
//#include <assert.h>
|
2021-01-31 17:12:36 +00:00
|
|
|
|
2021-02-08 03:20:29 +00:00
|
|
|
/*
|
2022-11-09 14:12:57 +00:00
|
|
|
As a sender, I can send packets every n seconds. These packets include an incremented PacketID.
|
2022-02-14 17:45:29 +00:00
|
|
|
As a receiver, I can receive packets from multiple senders. These packets can be saved to the Filesystem.
|
2021-02-08 03:20:29 +00:00
|
|
|
*/
|
|
|
|
|
2022-02-27 09:49:24 +00:00
|
|
|
RangeTestModule *rangeTestModule;
|
|
|
|
RangeTestModuleRadio *rangeTestModuleRadio;
|
2021-01-31 17:12:36 +00:00
|
|
|
|
2022-02-27 09:49:24 +00:00
|
|
|
RangeTestModule::RangeTestModule() : concurrency::OSThread("RangeTestModule") {}
|
2021-01-31 17:12:36 +00:00
|
|
|
|
2021-02-14 06:21:01 +00:00
|
|
|
uint32_t packetSequence = 0;
|
2021-02-03 16:10:13 +00:00
|
|
|
|
2021-02-14 06:21:01 +00:00
|
|
|
#define SEC_PER_DAY 86400
|
|
|
|
#define SEC_PER_HOUR 3600
|
|
|
|
#define SEC_PER_MIN 60
|
2021-01-31 17:12:36 +00:00
|
|
|
|
2022-02-27 09:49:24 +00:00
|
|
|
int32_t RangeTestModule::runOnce()
|
2021-01-31 17:12:36 +00:00
|
|
|
{
|
2022-07-31 12:11:47 +00:00
|
|
|
#ifdef ARCH_ESP32
|
2021-01-31 17:12:36 +00:00
|
|
|
|
2021-02-07 07:29:18 +00:00
|
|
|
/*
|
2022-02-27 08:29:05 +00:00
|
|
|
Uncomment the preferences below if you want to use the module
|
2021-02-07 07:29:18 +00:00
|
|
|
without having to configure it from the PythonAPI or WebUI.
|
|
|
|
*/
|
|
|
|
|
2022-11-09 14:12:57 +00:00
|
|
|
// moduleConfig.range_test.enabled = 1;
|
|
|
|
// moduleConfig.range_test.sender = 30;
|
2022-05-22 11:27:56 +00:00
|
|
|
// moduleConfig.range_test.save = 1;
|
2021-02-14 06:21:01 +00:00
|
|
|
|
|
|
|
// Fixed position is useful when testing indoors.
|
2022-11-09 14:12:57 +00:00
|
|
|
// config.position.fixed_position = 1;
|
2021-02-07 07:29:18 +00:00
|
|
|
|
2022-05-22 11:27:56 +00:00
|
|
|
uint32_t senderHeartbeat = moduleConfig.range_test.sender * 1000;
|
2021-02-07 07:29:18 +00:00
|
|
|
|
2022-05-22 11:27:56 +00:00
|
|
|
if (moduleConfig.range_test.enabled) {
|
2021-01-31 17:12:36 +00:00
|
|
|
|
|
|
|
if (firstTime) {
|
2022-02-27 09:49:24 +00:00
|
|
|
rangeTestModuleRadio = new RangeTestModuleRadio();
|
2021-01-31 17:12:36 +00:00
|
|
|
|
|
|
|
firstTime = 0;
|
|
|
|
|
2022-05-22 11:27:56 +00:00
|
|
|
if (moduleConfig.range_test.sender) {
|
2022-02-27 08:52:25 +00:00
|
|
|
DEBUG_MSG("Initializing Range Test Module -- Sender\n");
|
2021-02-15 17:11:28 +00:00
|
|
|
return (5000); // Sending first message 5 seconds after initilization.
|
2021-02-03 16:10:13 +00:00
|
|
|
} else {
|
2022-02-27 08:52:25 +00:00
|
|
|
DEBUG_MSG("Initializing Range Test Module -- Receiver\n");
|
2022-11-09 14:12:57 +00:00
|
|
|
return (INT32_MAX);
|
|
|
|
// This thread does not need to run as a receiver
|
2021-02-03 16:10:13 +00:00
|
|
|
}
|
|
|
|
|
2021-01-31 17:12:36 +00:00
|
|
|
} else {
|
2021-02-01 02:20:08 +00:00
|
|
|
|
2022-05-22 11:27:56 +00:00
|
|
|
if (moduleConfig.range_test.sender) {
|
2021-02-03 16:10:13 +00:00
|
|
|
// If sender
|
2022-02-27 10:21:02 +00:00
|
|
|
DEBUG_MSG("Range Test Module - Sending heartbeat every %d ms\n", (senderHeartbeat));
|
2021-02-07 07:29:18 +00:00
|
|
|
|
|
|
|
DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude());
|
|
|
|
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
|
|
|
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
|
|
|
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
2022-11-09 14:12:57 +00:00
|
|
|
DEBUG_MSG("fixed_position() %d\n", config.position.fixed_position);
|
2021-02-01 02:20:08 +00:00
|
|
|
|
2022-01-27 06:20:13 +00:00
|
|
|
// Only send packets if the channel is less than 25% utilized.
|
|
|
|
if (airTime->channelUtilizationPercent() < 25) {
|
2022-02-27 09:49:24 +00:00
|
|
|
rangeTestModuleRadio->sendPayload();
|
2022-01-27 06:20:13 +00:00
|
|
|
} else {
|
2022-01-27 06:32:33 +00:00
|
|
|
DEBUG_MSG("rangeTest - Channel utilization is >25 percent. Skipping this opportunity to send.\n");
|
2022-01-27 06:20:13 +00:00
|
|
|
}
|
|
|
|
|
2021-02-15 17:11:28 +00:00
|
|
|
return (senderHeartbeat);
|
2021-02-01 02:20:08 +00:00
|
|
|
} else {
|
2022-11-09 14:12:57 +00:00
|
|
|
return (INT32_MAX);
|
|
|
|
// This thread does not need to run as a receiver
|
2021-02-01 02:20:08 +00:00
|
|
|
}
|
2022-11-09 14:12:57 +00:00
|
|
|
|
|
|
|
|
2021-01-31 17:12:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2022-02-27 10:21:02 +00:00
|
|
|
DEBUG_MSG("Range Test Module - Disabled\n");
|
2021-01-31 17:12:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
2022-01-24 19:58:07 +00:00
|
|
|
return (INT32_MAX);
|
2021-01-31 17:12:36 +00:00
|
|
|
}
|
|
|
|
|
2022-02-27 09:49:24 +00:00
|
|
|
MeshPacket *RangeTestModuleRadio::allocReply()
|
2021-01-31 17:12:36 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
auto reply = allocDataPacket(); // Allocate a packet for sending
|
|
|
|
|
|
|
|
return reply;
|
|
|
|
}
|
|
|
|
|
2022-02-27 09:49:24 +00:00
|
|
|
void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
2021-01-31 17:12:36 +00:00
|
|
|
{
|
|
|
|
MeshPacket *p = allocReply();
|
|
|
|
p->to = dest;
|
|
|
|
p->decoded.want_response = wantReplies;
|
|
|
|
|
2021-02-01 02:20:08 +00:00
|
|
|
p->want_ack = true;
|
|
|
|
|
2021-02-03 16:10:13 +00:00
|
|
|
packetSequence++;
|
|
|
|
|
2022-05-25 00:42:46 +00:00
|
|
|
static char heartbeatString[MAX_RHPACKETLEN];
|
2021-03-20 07:38:53 +00:00
|
|
|
snprintf(heartbeatString, sizeof(heartbeatString), "seq %u", packetSequence);
|
2021-02-01 02:20:08 +00:00
|
|
|
|
2021-02-22 02:39:46 +00:00
|
|
|
p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
|
|
|
|
memcpy(p->decoded.payload.bytes, heartbeatString, p->decoded.payload.size);
|
2021-02-01 02:20:08 +00:00
|
|
|
|
2021-01-31 17:12:36 +00:00
|
|
|
service.sendToMesh(p);
|
2021-02-15 05:34:47 +00:00
|
|
|
|
|
|
|
// TODO: Handle this better. We want to keep the phone awake otherwise it stops sending.
|
|
|
|
powerFSM.trigger(EVENT_CONTACT_FROM_PHONE);
|
2021-01-31 17:12:36 +00:00
|
|
|
}
|
|
|
|
|
2022-02-27 09:49:24 +00:00
|
|
|
ProcessMessage RangeTestModuleRadio::handleReceived(const MeshPacket &mp)
|
2021-01-31 17:12:36 +00:00
|
|
|
{
|
2022-07-31 12:11:47 +00:00
|
|
|
#ifdef ARCH_ESP32
|
2021-01-31 17:12:36 +00:00
|
|
|
|
2022-05-22 11:27:56 +00:00
|
|
|
if (moduleConfig.range_test.enabled) {
|
2021-01-31 17:12:36 +00:00
|
|
|
|
2021-12-04 02:59:10 +00:00
|
|
|
/*
|
|
|
|
auto &p = mp.decoded;
|
|
|
|
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);
|
|
|
|
*/
|
2021-01-31 17:12:36 +00:00
|
|
|
|
2021-03-05 02:19:27 +00:00
|
|
|
if (getFrom(&mp) != nodeDB.getNodeNum()) {
|
2021-01-31 17:12:36 +00:00
|
|
|
|
2022-05-22 11:27:56 +00:00
|
|
|
if (moduleConfig.range_test.save) {
|
2021-02-14 06:21:01 +00:00
|
|
|
appendFile(mp);
|
|
|
|
}
|
2021-02-08 03:20:29 +00:00
|
|
|
|
2021-11-27 03:12:00 +00:00
|
|
|
/*
|
2021-12-04 02:59:10 +00:00
|
|
|
NodeInfo *n = nodeDB.getNode(getFrom(&mp));
|
|
|
|
|
2021-02-08 03:20:29 +00:00
|
|
|
DEBUG_MSG("-----------------------------------------\n");
|
2021-02-03 16:10:13 +00:00
|
|
|
DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes);
|
|
|
|
DEBUG_MSG("p.payload.size %d\n", p.payload.size);
|
2021-02-08 03:20:29 +00:00
|
|
|
DEBUG_MSG("---- Received Packet:\n");
|
2021-02-07 17:31:29 +00:00
|
|
|
DEBUG_MSG("mp.from %d\n", mp.from);
|
2021-02-03 16:10:13 +00:00
|
|
|
DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr);
|
|
|
|
DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit);
|
2022-11-25 13:17:24 +00:00
|
|
|
// DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated
|
|
|
|
// DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated
|
2021-02-08 03:20:29 +00:00
|
|
|
DEBUG_MSG("---- Node Information of Received Packet (mp.from):\n");
|
|
|
|
DEBUG_MSG("n->user.long_name %s\n", n->user.long_name);
|
|
|
|
DEBUG_MSG("n->user.short_name %s\n", n->user.short_name);
|
2021-12-04 02:59:10 +00:00
|
|
|
DEBUG_MSG("n->user.macaddr %X\n", n->user.macaddr);
|
2021-02-08 03:20:29 +00:00
|
|
|
DEBUG_MSG("n->has_position %d\n", n->has_position);
|
|
|
|
DEBUG_MSG("n->position.latitude_i %d\n", n->position.latitude_i);
|
|
|
|
DEBUG_MSG("n->position.longitude_i %d\n", n->position.longitude_i);
|
|
|
|
DEBUG_MSG("---- Current device location information:\n");
|
2021-02-03 16:10:13 +00:00
|
|
|
DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude());
|
|
|
|
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
|
|
|
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
|
|
|
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
2021-02-08 03:20:29 +00:00
|
|
|
DEBUG_MSG("-----------------------------------------\n");
|
2021-11-27 03:12:00 +00:00
|
|
|
*/
|
2021-01-31 17:12:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2022-02-27 10:21:02 +00:00
|
|
|
DEBUG_MSG("Range Test Module Disabled\n");
|
2021-01-31 17:12:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2021-09-23 01:42:09 +00:00
|
|
|
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
|
2021-01-31 17:12:36 +00:00
|
|
|
}
|
2021-02-14 06:21:01 +00:00
|
|
|
|
2022-02-27 09:49:24 +00:00
|
|
|
bool RangeTestModuleRadio::appendFile(const MeshPacket &mp)
|
2021-02-14 06:21:01 +00:00
|
|
|
{
|
2021-02-22 02:39:46 +00:00
|
|
|
auto &p = mp.decoded;
|
2021-02-14 06:21:01 +00:00
|
|
|
|
2021-03-05 02:19:27 +00:00
|
|
|
NodeInfo *n = nodeDB.getNode(getFrom(&mp));
|
2021-02-14 06:21:01 +00:00
|
|
|
/*
|
|
|
|
DEBUG_MSG("-----------------------------------------\n");
|
|
|
|
DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes);
|
|
|
|
DEBUG_MSG("p.payload.size %d\n", p.payload.size);
|
|
|
|
DEBUG_MSG("---- Received Packet:\n");
|
|
|
|
DEBUG_MSG("mp.from %d\n", mp.from);
|
|
|
|
DEBUG_MSG("mp.rx_snr %f\n", mp.rx_snr);
|
|
|
|
DEBUG_MSG("mp.hop_limit %d\n", mp.hop_limit);
|
|
|
|
// DEBUG_MSG("mp.decoded.position.latitude_i %d\n", mp.decoded.position.latitude_i); // Depricated
|
|
|
|
// DEBUG_MSG("mp.decoded.position.longitude_i %d\n", mp.decoded.position.longitude_i); // Depricated
|
|
|
|
DEBUG_MSG("---- Node Information of Received Packet (mp.from):\n");
|
|
|
|
DEBUG_MSG("n->user.long_name %s\n", n->user.long_name);
|
|
|
|
DEBUG_MSG("n->user.short_name %s\n", n->user.short_name);
|
|
|
|
DEBUG_MSG("n->user.macaddr %X\n", n->user.macaddr);
|
|
|
|
DEBUG_MSG("n->has_position %d\n", n->has_position);
|
|
|
|
DEBUG_MSG("n->position.latitude_i %d\n", n->position.latitude_i);
|
|
|
|
DEBUG_MSG("n->position.longitude_i %d\n", n->position.longitude_i);
|
|
|
|
DEBUG_MSG("---- Current device location information:\n");
|
|
|
|
DEBUG_MSG("gpsStatus->getLatitude() %d\n", gpsStatus->getLatitude());
|
|
|
|
DEBUG_MSG("gpsStatus->getLongitude() %d\n", gpsStatus->getLongitude());
|
|
|
|
DEBUG_MSG("gpsStatus->getHasLock() %d\n", gpsStatus->getHasLock());
|
|
|
|
DEBUG_MSG("gpsStatus->getDOP() %d\n", gpsStatus->getDOP());
|
|
|
|
DEBUG_MSG("-----------------------------------------\n");
|
|
|
|
*/
|
2022-02-14 17:45:29 +00:00
|
|
|
if (!FSBegin()) {
|
|
|
|
DEBUG_MSG("An Error has occurred while mounting the filesystem\n");
|
2021-02-14 06:21:01 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-02-14 17:45:29 +00:00
|
|
|
if (FSCom.totalBytes() - FSCom.usedBytes() < 51200) {
|
|
|
|
DEBUG_MSG("Filesystem doesn't have enough free space. Aborting write.\n");
|
2021-02-14 06:21:01 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-11-09 14:12:57 +00:00
|
|
|
FSCom.mkdir("/static");
|
|
|
|
|
2021-02-15 00:17:40 +00:00
|
|
|
// If the file doesn't exist, write the header.
|
2022-02-14 17:45:29 +00:00
|
|
|
if (!FSCom.exists("/static/rangetest.csv")) {
|
2021-02-15 00:17:40 +00:00
|
|
|
//--------- Write to file
|
2022-02-14 17:45:29 +00:00
|
|
|
File fileToWrite = FSCom.open("/static/rangetest.csv", FILE_WRITE);
|
2021-02-14 06:21:01 +00:00
|
|
|
|
2021-02-15 00:17:40 +00:00
|
|
|
if (!fileToWrite) {
|
|
|
|
DEBUG_MSG("There was an error opening the file for writing\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2021-02-14 06:21:01 +00:00
|
|
|
|
2021-03-26 02:25:20 +00:00
|
|
|
// Print the CSV header
|
|
|
|
if (fileToWrite.println(
|
2021-12-07 17:14:31 +00:00
|
|
|
"time,from,sender name,sender lat,sender long,rx lat,rx long,rx elevation,rx snr,distance,hop limit,payload")) {
|
2021-02-15 00:17:40 +00:00
|
|
|
DEBUG_MSG("File was written\n");
|
|
|
|
} else {
|
|
|
|
DEBUG_MSG("File write failed\n");
|
|
|
|
}
|
2021-02-14 06:21:01 +00:00
|
|
|
|
2021-02-15 00:17:40 +00:00
|
|
|
fileToWrite.close();
|
|
|
|
}
|
2021-02-14 06:21:01 +00:00
|
|
|
|
2022-02-14 17:45:29 +00:00
|
|
|
//--------- Append content to file
|
|
|
|
File fileToAppend = FSCom.open("/static/rangetest.csv", FILE_APPEND);
|
2021-02-14 06:21:01 +00:00
|
|
|
|
|
|
|
if (!fileToAppend) {
|
|
|
|
DEBUG_MSG("There was an error opening the file for appending\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct timeval tv;
|
|
|
|
if (!gettimeofday(&tv, NULL)) {
|
|
|
|
long hms = tv.tv_sec % SEC_PER_DAY;
|
|
|
|
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
|
|
|
|
|
|
|
// Tear apart hms into h:m:s
|
|
|
|
int hour = hms / SEC_PER_HOUR;
|
|
|
|
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
|
|
|
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
|
|
|
|
|
2021-02-15 00:17:40 +00:00
|
|
|
fileToAppend.printf("%02d:%02d:%02d,", hour, min, sec); // Time
|
2021-02-14 06:21:01 +00:00
|
|
|
} else {
|
2021-02-15 00:17:40 +00:00
|
|
|
fileToAppend.printf("??:??:??,"); // Time
|
2021-02-14 06:21:01 +00:00
|
|
|
}
|
|
|
|
|
2021-03-20 07:38:53 +00:00
|
|
|
fileToAppend.printf("%d,", getFrom(&mp)); // From
|
2021-02-15 00:17:40 +00:00
|
|
|
fileToAppend.printf("%s,", n->user.long_name); // Long Name
|
|
|
|
fileToAppend.printf("%f,", n->position.latitude_i * 1e-7); // Sender Lat
|
|
|
|
fileToAppend.printf("%f,", n->position.longitude_i * 1e-7); // Sender Long
|
|
|
|
fileToAppend.printf("%f,", gpsStatus->getLatitude() * 1e-7); // RX Lat
|
|
|
|
fileToAppend.printf("%f,", gpsStatus->getLongitude() * 1e-7); // RX Long
|
2021-03-26 02:25:20 +00:00
|
|
|
fileToAppend.printf("%d,", gpsStatus->getAltitude()); // RX Altitude
|
|
|
|
|
|
|
|
fileToAppend.printf("%f,", mp.rx_snr); // RX SNR
|
2021-02-15 00:17:40 +00:00
|
|
|
|
|
|
|
if (n->position.latitude_i && n->position.longitude_i && gpsStatus->getLatitude() && gpsStatus->getLongitude()) {
|
2021-10-09 17:28:51 +00:00
|
|
|
float distance = GeoCoord::latLongToMeter(n->position.latitude_i * 1e-7, n->position.longitude_i * 1e-7,
|
2022-01-27 06:20:13 +00:00
|
|
|
gpsStatus->getLatitude() * 1e-7, gpsStatus->getLongitude() * 1e-7);
|
2021-02-15 00:17:40 +00:00
|
|
|
fileToAppend.printf("%f,", distance); // Distance in meters
|
|
|
|
} else {
|
|
|
|
fileToAppend.printf("0,");
|
|
|
|
}
|
2021-02-14 06:21:01 +00:00
|
|
|
|
2021-12-07 17:14:31 +00:00
|
|
|
fileToAppend.printf("%d,", mp.hop_limit); // Packet Hop Limit
|
|
|
|
|
2021-02-14 06:21:01 +00:00
|
|
|
// TODO: If quotes are found in the payload, it has to be escaped.
|
|
|
|
fileToAppend.printf("\"%s\"\n", p.payload.bytes);
|
|
|
|
fileToAppend.close();
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|