2020-02-02 20:45:32 +00:00
|
|
|
|
|
|
|
#include <Arduino.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
2020-02-03 17:13:19 +00:00
|
|
|
#include "mesh-pb-constants.h"
|
2020-02-02 20:45:32 +00:00
|
|
|
#include "MeshService.h"
|
2020-02-03 04:54:40 +00:00
|
|
|
#include "MeshBluetoothService.h"
|
2020-02-03 17:13:19 +00:00
|
|
|
#include "NodeDB.h"
|
2020-02-06 16:49:33 +00:00
|
|
|
#include "GPS.h"
|
2020-02-02 20:45:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
receivedPacketQueue - this is a queue of messages we've received from the mesh, which we are keeping to deliver to the phone.
|
|
|
|
It is implemented with a FreeRTos queue (wrapped with a little RTQueue class) of pointers to MeshPacket protobufs (which were alloced with new).
|
|
|
|
After a packet ptr is removed from the queue and processed it should be deleted. (eventually we should move sent packets into a 'sentToPhone' queue
|
|
|
|
of packets we can delete just as soon as we are sure the phone has acked those packets - when the phone writes to FromNum)
|
|
|
|
|
|
|
|
mesh - an instance of Mesh class. Which manages the interface to the mesh radio library, reception of packets from other nodes, arbitrating to select
|
|
|
|
a node number and keeping the current nodedb.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
MeshService service;
|
|
|
|
|
2020-02-06 16:49:33 +00:00
|
|
|
#define MAX_PACKETS 32 // max number of packets which can be in flight (either queued from reception or queued for sending)
|
2020-02-03 17:13:19 +00:00
|
|
|
|
2020-02-03 04:54:40 +00:00
|
|
|
#define MAX_RX_FROMRADIO 4 // max number of packets destined to our queue, we dispatch packets quickly so it doesn't need to be big
|
|
|
|
|
|
|
|
MeshService::MeshService()
|
2020-02-06 16:49:33 +00:00
|
|
|
: packetPool(MAX_PACKETS),
|
|
|
|
toPhoneQueue(MAX_RX_TOPHONE),
|
|
|
|
fromRadioQueue(MAX_RX_FROMRADIO),
|
|
|
|
fromNum(0),
|
|
|
|
radio(packetPool, fromRadioQueue)
|
2020-02-02 20:45:32 +00:00
|
|
|
{
|
2020-02-03 17:13:19 +00:00
|
|
|
// assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro
|
2020-02-02 20:45:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void MeshService::init()
|
|
|
|
{
|
2020-02-04 17:00:17 +00:00
|
|
|
nodeDB.init();
|
2020-02-06 16:49:33 +00:00
|
|
|
|
2020-02-02 20:45:32 +00:00
|
|
|
if (!radio.init())
|
2020-02-04 16:17:44 +00:00
|
|
|
DEBUG_MSG("radio init failed\n");
|
2020-02-06 16:49:33 +00:00
|
|
|
|
|
|
|
gps.addObserver(this);
|
2020-02-06 18:58:19 +00:00
|
|
|
sendOurOwner();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeshService::sendOurOwner(NodeNum dest)
|
|
|
|
{
|
|
|
|
MeshPacket *p = allocForSending();
|
|
|
|
p->to = dest;
|
|
|
|
p->payload.which_variant = SubPacket_user_tag;
|
|
|
|
User &u = p->payload.variant.user;
|
|
|
|
u = owner;
|
|
|
|
|
|
|
|
sendToMesh(p);
|
2020-02-02 20:45:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Do idle processing (mostly processing messages which have been queued from the radio)
|
|
|
|
void MeshService::loop()
|
|
|
|
{
|
|
|
|
radio.loop(); // FIXME, possibly move radio interaction to own thread
|
2020-02-03 04:54:40 +00:00
|
|
|
|
|
|
|
MeshPacket *mp;
|
|
|
|
uint32_t oldFromNum = fromNum;
|
2020-02-06 16:49:33 +00:00
|
|
|
while ((mp = fromRadioQueue.dequeuePtr(0)) != NULL)
|
|
|
|
{
|
|
|
|
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
2020-02-06 19:07:44 +00:00
|
|
|
if(mp->has_payload && mp->payload.which_variant == SubPacket_user_tag && mp->to == NODENUM_BROADCAST) {
|
|
|
|
// Someone just sent us a User, reply with our Owner
|
|
|
|
DEBUG_MSG("Received broadcast Owner from 0x%x, replying with our owner\n", mp->from);
|
|
|
|
sendOurOwner(mp->from);
|
|
|
|
}
|
2020-02-03 04:54:40 +00:00
|
|
|
|
|
|
|
fromNum++;
|
2020-02-06 16:49:33 +00:00
|
|
|
assert(toPhoneQueue.enqueue(mp, 0) == pdTRUE); // FIXME, instead of failing for full queue, delete the oldest mssages
|
2020-02-03 04:54:40 +00:00
|
|
|
}
|
2020-02-06 16:49:33 +00:00
|
|
|
if (oldFromNum != fromNum) // We don't want to generate extra notifies for multiple new packets
|
2020-02-03 04:54:40 +00:00
|
|
|
bluetoothNotifyFromNum(fromNum);
|
2020-02-02 20:45:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Given a ToRadio buffer parse it and properly handle it (setup radio, owner or send packet into the mesh)
|
|
|
|
void MeshService::handleToRadio(std::string s)
|
|
|
|
{
|
|
|
|
static ToRadio r; // this is a static scratch object, any data must be copied elsewhere before returning
|
|
|
|
|
2020-02-03 19:15:17 +00:00
|
|
|
if (pb_decode_from_bytes((const uint8_t *)s.c_str(), s.length(), ToRadio_fields, &r))
|
2020-02-02 20:45:32 +00:00
|
|
|
{
|
|
|
|
switch (r.which_variant)
|
|
|
|
{
|
|
|
|
case ToRadio_packet_tag:
|
2020-02-06 16:49:33 +00:00
|
|
|
sendToMesh(packetPool.allocCopy(r.variant.packet));
|
2020-02-02 20:45:32 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2020-02-04 16:17:44 +00:00
|
|
|
DEBUG_MSG("Error: unexpected ToRadio variant\n");
|
2020-02-02 20:45:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-06 16:49:33 +00:00
|
|
|
void MeshService::sendToMesh(MeshPacket *p)
|
2020-02-02 20:45:32 +00:00
|
|
|
{
|
2020-02-06 16:49:33 +00:00
|
|
|
nodeDB.updateFrom(*p);
|
|
|
|
assert(radio.send(p) == pdTRUE);
|
|
|
|
}
|
2020-02-02 20:45:32 +00:00
|
|
|
|
2020-02-06 18:58:19 +00:00
|
|
|
MeshPacket *MeshService::allocForSending()
|
2020-02-06 16:49:33 +00:00
|
|
|
{
|
|
|
|
MeshPacket *p = packetPool.allocZeroed();
|
|
|
|
|
|
|
|
p->has_payload = true;
|
|
|
|
p->from = nodeDB.getNodeNum();
|
|
|
|
p->to = NODENUM_BROADCAST;
|
2020-02-06 18:58:19 +00:00
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeshService::onGPSChanged()
|
|
|
|
{
|
|
|
|
MeshPacket *p = allocForSending();
|
2020-02-06 16:49:33 +00:00
|
|
|
p->payload.which_variant = SubPacket_position_tag;
|
|
|
|
Position &pos = p->payload.variant.position;
|
|
|
|
if (gps.altitude.isValid())
|
|
|
|
pos.altitude = gps.altitude.value();
|
|
|
|
pos.latitude = gps.location.lat();
|
|
|
|
pos.longitude = gps.location.lng();
|
|
|
|
|
|
|
|
sendToMesh(p);
|
2020-02-02 20:45:32 +00:00
|
|
|
}
|
2020-02-06 16:49:33 +00:00
|
|
|
|
|
|
|
void MeshService::onNotify(Observable *o)
|
|
|
|
{
|
|
|
|
DEBUG_MSG("got gps notify\n");
|
|
|
|
onGPSChanged();
|
|
|
|
}
|