2020-04-01 04:56:35 +00:00
|
|
|
#pragma once
|
|
|
|
|
2020-08-12 17:42:25 +00:00
|
|
|
#include "../concurrency/NotifiedWorkerThread.h"
|
2020-04-01 04:56:35 +00:00
|
|
|
#include "MemoryPool.h"
|
|
|
|
#include "MeshTypes.h"
|
2020-05-09 23:32:26 +00:00
|
|
|
#include "Observer.h"
|
2020-04-01 04:56:35 +00:00
|
|
|
#include "PointerQueue.h"
|
2020-12-26 00:10:38 +00:00
|
|
|
#include "airtime.h"
|
2020-04-01 04:56:35 +00:00
|
|
|
|
|
|
|
#define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission
|
|
|
|
|
2020-04-30 16:44:16 +00:00
|
|
|
#define MAX_RHPACKETLEN 256
|
|
|
|
|
2020-05-19 17:27:28 +00:00
|
|
|
#define PACKET_FLAGS_HOP_MASK 0x07
|
|
|
|
#define PACKET_FLAGS_WANT_ACK_MASK 0x08
|
|
|
|
|
2020-04-30 16:44:16 +00:00
|
|
|
/**
|
2020-05-01 04:42:11 +00:00
|
|
|
* This structure has to exactly match the wire layout when sent over the radio link. Used to keep compatibility
|
2020-04-30 16:44:16 +00:00
|
|
|
* wtih the old radiohead implementation.
|
|
|
|
*/
|
|
|
|
typedef struct {
|
2020-06-03 20:46:31 +00:00
|
|
|
NodeNum to, from; // can be 1 byte or four bytes
|
|
|
|
|
|
|
|
PacketId id; // can be 1 byte or 4 bytes
|
2020-05-19 00:35:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Usage of flags:
|
|
|
|
*
|
|
|
|
* The bottom three bits of flags are use to store hop_limit when sent over the wire.
|
|
|
|
**/
|
|
|
|
uint8_t flags;
|
2021-02-22 04:57:26 +00:00
|
|
|
|
|
|
|
/** The channel hash - used as a hint for the decoder to limit which channels we consider */
|
|
|
|
uint8_t channel;
|
2020-04-30 16:44:16 +00:00
|
|
|
} PacketHeader;
|
|
|
|
|
2020-04-01 04:56:35 +00:00
|
|
|
/**
|
|
|
|
* Basic operations all radio chipsets must implement.
|
|
|
|
*
|
|
|
|
* This defines the SOLE API for talking to radios (because soon we will have alternate radio implementations)
|
|
|
|
*/
|
2020-12-26 00:10:38 +00:00
|
|
|
class RadioInterface
|
2020-04-01 04:56:35 +00:00
|
|
|
{
|
|
|
|
friend class MeshRadio; // for debugging we let that class touch pool
|
|
|
|
|
2020-05-09 23:32:26 +00:00
|
|
|
CallbackObserver<RadioInterface, void *> configChangedObserver =
|
|
|
|
CallbackObserver<RadioInterface, void *>(this, &RadioInterface::reloadConfig);
|
|
|
|
|
|
|
|
CallbackObserver<RadioInterface, void *> preflightSleepObserver =
|
|
|
|
CallbackObserver<RadioInterface, void *>(this, &RadioInterface::preflightSleepCb);
|
|
|
|
|
|
|
|
CallbackObserver<RadioInterface, void *> notifyDeepSleepObserver =
|
2020-10-30 09:05:32 +00:00
|
|
|
CallbackObserver<RadioInterface, void *>(this, &RadioInterface::notifyDeepSleepCb);
|
2020-05-09 23:32:26 +00:00
|
|
|
|
2020-11-14 02:07:25 +00:00
|
|
|
/// Number of msecs we expect our shortest actual packet to be over the wire (used in retry timeout calcs)
|
|
|
|
uint32_t shortPacketMsec;
|
|
|
|
|
2020-04-01 04:56:35 +00:00
|
|
|
protected:
|
2021-02-12 05:48:12 +00:00
|
|
|
bool disabled = false;
|
|
|
|
|
2020-11-14 02:07:25 +00:00
|
|
|
float bw = 125;
|
|
|
|
uint8_t sf = 9;
|
|
|
|
uint8_t cr = 7;
|
|
|
|
|
2020-11-14 02:19:55 +00:00
|
|
|
uint16_t preambleLength = 32; // 8 is default, but we use longer to increase the amount of sleep time when receiving
|
2020-11-14 02:07:25 +00:00
|
|
|
|
2020-04-01 04:56:35 +00:00
|
|
|
MeshPacket *sendingPacket = NULL; // The packet we are currently sending
|
2020-04-30 16:44:16 +00:00
|
|
|
uint32_t lastTxStart = 0L;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A temporary buffer used for sending/receving packets, sized to hold the biggest buffer we might need
|
|
|
|
* */
|
|
|
|
uint8_t radiobuf[MAX_RHPACKETLEN];
|
2020-04-17 16:48:54 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Enqueue a received packet for the registered receiver
|
|
|
|
*/
|
2020-04-18 21:22:24 +00:00
|
|
|
void deliverToReceiver(MeshPacket *p);
|
2020-04-17 16:48:54 +00:00
|
|
|
|
2020-04-01 04:56:35 +00:00
|
|
|
public:
|
2020-08-12 17:42:25 +00:00
|
|
|
float freq = 915.0;
|
2020-04-30 01:46:32 +00:00
|
|
|
|
2020-04-01 04:56:35 +00:00
|
|
|
/** pool is the pool we will alloc our rx packets from
|
|
|
|
*/
|
2020-04-17 16:48:54 +00:00
|
|
|
RadioInterface();
|
2020-04-01 04:56:35 +00:00
|
|
|
|
2020-10-11 01:18:47 +00:00
|
|
|
virtual ~RadioInterface() {}
|
|
|
|
|
2020-04-23 19:47:41 +00:00
|
|
|
/**
|
|
|
|
* Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving)
|
|
|
|
*
|
|
|
|
* This method must be used before putting the CPU into deep or light sleep.
|
|
|
|
*/
|
2020-04-30 22:50:07 +00:00
|
|
|
virtual bool canSleep() { return true; }
|
2020-04-23 19:47:41 +00:00
|
|
|
|
|
|
|
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
|
|
|
|
virtual bool sleep() { return true; }
|
|
|
|
|
2021-02-12 05:48:12 +00:00
|
|
|
/// Disable this interface (while disabled, no packets can be sent or received)
|
2021-03-30 15:34:13 +00:00
|
|
|
void disable()
|
|
|
|
{
|
|
|
|
disabled = true;
|
|
|
|
sleep();
|
|
|
|
}
|
2021-02-12 05:48:12 +00:00
|
|
|
|
2020-04-17 16:48:54 +00:00
|
|
|
/**
|
|
|
|
* Send a packet (possibly by enquing in a private fifo). This routine will
|
|
|
|
* later free() the packet to pool. This routine is not allowed to stall.
|
|
|
|
* If the txmit queue is full it might return an error
|
|
|
|
*/
|
2020-04-01 04:56:35 +00:00
|
|
|
virtual ErrorCode send(MeshPacket *p) = 0;
|
2020-04-29 21:54:03 +00:00
|
|
|
|
2021-02-11 09:39:53 +00:00
|
|
|
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
|
|
|
virtual bool cancelSending(NodeNum from, PacketId id) { return false; }
|
|
|
|
|
2020-04-29 21:54:03 +00:00
|
|
|
// methods from radiohead
|
|
|
|
|
|
|
|
/// Initialise the Driver transport hardware and software.
|
|
|
|
/// Make sure the Driver is properly configured before calling init().
|
|
|
|
/// \return true if initialisation succeeded.
|
2020-05-01 19:11:04 +00:00
|
|
|
virtual bool init();
|
2020-04-29 21:54:03 +00:00
|
|
|
|
2020-04-30 01:46:32 +00:00
|
|
|
/// Apply any radio provisioning changes
|
|
|
|
/// Make sure the Driver is properly configured before calling init().
|
|
|
|
/// \return true if initialisation succeeded.
|
2021-03-30 15:34:13 +00:00
|
|
|
virtual bool reconfigure();
|
2020-04-30 16:44:16 +00:00
|
|
|
|
2020-11-12 09:49:04 +00:00
|
|
|
/** The delay to use for retransmitting dropped packets */
|
|
|
|
uint32_t getRetransmissionMsec(const MeshPacket *p);
|
|
|
|
|
|
|
|
/** The delay to use when we want to send something but the ether is busy */
|
|
|
|
uint32_t getTxDelayMsec();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculate airtime per
|
|
|
|
* https://www.rs-online.com/designspark/rel-assets/ds-assets/uploads/knowledge-items/application-notes-for-the-internet-of-things/LoRa%20Design%20Guide.pdf
|
|
|
|
* section 4
|
|
|
|
*
|
|
|
|
* @return num msecs for the packet
|
|
|
|
*/
|
|
|
|
uint32_t getPacketTime(MeshPacket *p);
|
2020-11-14 02:07:25 +00:00
|
|
|
uint32_t getPacketTime(uint32_t totalPacketLen);
|
2020-11-12 09:49:04 +00:00
|
|
|
|
2021-02-10 05:59:00 +00:00
|
|
|
/**
|
|
|
|
* Get the channel we saved.
|
|
|
|
*/
|
|
|
|
uint32_t getChannelNum();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the frequency we saved.
|
|
|
|
*/
|
|
|
|
float getFreq();
|
|
|
|
|
2021-04-22 00:49:05 +00:00
|
|
|
/// Some boards (1st gen Pinetab Lora module) have broken IRQ wires, so we need to poll via i2c registers
|
|
|
|
virtual bool isIRQPending() { return false; }
|
|
|
|
|
2020-04-30 16:44:16 +00:00
|
|
|
protected:
|
2020-08-12 17:42:25 +00:00
|
|
|
int8_t power = 17; // Set by applyModemConfig()
|
|
|
|
|
2021-02-10 05:59:00 +00:00
|
|
|
float savedFreq;
|
|
|
|
uint32_t savedChannelNum;
|
|
|
|
|
2020-04-30 16:44:16 +00:00
|
|
|
/***
|
2020-05-01 04:42:11 +00:00
|
|
|
* given a packet set sendingPacket and decode the protobufs into radiobuf. Returns # of bytes to send (including the
|
|
|
|
* PacketHeader & payload).
|
|
|
|
*
|
|
|
|
* Used as the first step of
|
2020-04-30 16:44:16 +00:00
|
|
|
*/
|
|
|
|
size_t beginSending(MeshPacket *p);
|
2020-05-01 19:11:04 +00:00
|
|
|
|
2020-09-16 01:54:50 +00:00
|
|
|
/**
|
|
|
|
* Some regulatory regions limit xmit power.
|
|
|
|
* This function should be called by subclasses after setting their desired power. It might lower it
|
|
|
|
*/
|
|
|
|
void limitPower();
|
|
|
|
|
2021-02-10 05:59:00 +00:00
|
|
|
/**
|
|
|
|
* Save the frequency we selected for later reuse.
|
|
|
|
*/
|
|
|
|
virtual void saveFreq(float savedFreq);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Save the chanel we selected for later reuse.
|
|
|
|
*/
|
|
|
|
virtual void saveChannelNum(uint32_t savedChannelNum);
|
|
|
|
|
2020-05-09 23:32:26 +00:00
|
|
|
private:
|
2021-03-30 15:34:13 +00:00
|
|
|
/**
|
|
|
|
* Convert our modemConfig enum into wf, sf, etc...
|
|
|
|
*
|
|
|
|
* These paramaters will be pull from the channelSettings global
|
|
|
|
*/
|
|
|
|
void applyModemConfig();
|
|
|
|
|
2020-05-09 23:32:26 +00:00
|
|
|
/// Return 0 if sleep is okay
|
|
|
|
int preflightSleepCb(void *unused = NULL) { return canSleep() ? 0 : 1; }
|
|
|
|
|
2020-10-30 09:05:32 +00:00
|
|
|
int notifyDeepSleepCb(void *unused = NULL);
|
2020-05-09 23:32:26 +00:00
|
|
|
|
|
|
|
int reloadConfig(void *unused)
|
|
|
|
{
|
|
|
|
reconfigure();
|
|
|
|
return 0;
|
|
|
|
}
|
2020-04-01 04:56:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class SimRadio : public RadioInterface
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual ErrorCode send(MeshPacket *p);
|
|
|
|
};
|
2020-06-14 22:30:42 +00:00
|
|
|
|
|
|
|
/// Debug printing for packets
|
|
|
|
void printPacket(const char *prefix, const MeshPacket *p);
|