2020-05-01 04:42:11 +00:00
|
|
|
#include "RadioInterface.h"
|
2021-02-17 05:06:23 +00:00
|
|
|
#include "Channels.h"
|
2020-05-09 23:32:26 +00:00
|
|
|
#include "MeshRadio.h"
|
|
|
|
#include "MeshService.h"
|
2020-04-01 04:56:35 +00:00
|
|
|
#include "NodeDB.h"
|
2021-03-06 03:13:33 +00:00
|
|
|
#include "Router.h"
|
2021-03-30 15:34:13 +00:00
|
|
|
#include "assert.h"
|
2022-02-15 03:32:31 +00:00
|
|
|
#include "configuration.h"
|
2020-05-09 23:32:26 +00:00
|
|
|
#include "sleep.h"
|
2020-04-17 16:48:54 +00:00
|
|
|
#include <assert.h>
|
2020-04-01 04:56:35 +00:00
|
|
|
#include <pb_decode.h>
|
|
|
|
#include <pb_encode.h>
|
|
|
|
|
2022-02-15 03:32:31 +00:00
|
|
|
#define RDEF(name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching) \
|
2020-09-25 19:52:08 +00:00
|
|
|
{ \
|
2022-02-15 03:32:31 +00:00
|
|
|
RegionCode_##name, freq_start, freq_end, duty_cycle, spacing, power_limit, audio_permitted, frequency_switching, #name \
|
2020-09-25 19:52:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const RegionInfo regions[] = {
|
2022-02-15 03:32:31 +00:00
|
|
|
/*
|
|
|
|
https://link.springer.com/content/pdf/bbm%3A978-1-4842-4357-2%2F1.pdf
|
|
|
|
https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/
|
|
|
|
*/
|
|
|
|
RDEF(US, 902.0f, 928.0f, 100, 0, 30, true, false),
|
|
|
|
|
|
|
|
/*
|
|
|
|
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
|
|
|
*/
|
|
|
|
RDEF(EU433, 433.0f, 434.0f, 10, 0, 12, true, false),
|
|
|
|
|
|
|
|
/*
|
|
|
|
https://www.thethingsnetwork.org/docs/lorawan/duty-cycle/
|
|
|
|
https://www.thethingsnetwork.org/docs/lorawan/regional-parameters/
|
|
|
|
https://www.legislation.gov.uk/uksi/1999/930/schedule/6/part/III/made/data.xht?view=snippet&wrap=true
|
2022-02-15 15:36:28 +00:00
|
|
|
|
|
|
|
audio_permitted = false per regulation
|
2022-02-15 03:32:31 +00:00
|
|
|
*/
|
|
|
|
RDEF(EU868, 869.4f, 869.65f, 10, 0, 16, false, false),
|
2020-09-25 19:52:08 +00:00
|
|
|
|
2022-02-15 03:32:31 +00:00
|
|
|
/*
|
|
|
|
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
|
|
|
*/
|
|
|
|
RDEF(CN, 470.0f, 510.0f, 100, 0, 19, true, false),
|
|
|
|
|
|
|
|
/*
|
|
|
|
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
|
|
|
*/
|
|
|
|
RDEF(JP, 920.8f, 927.8f, 100, 0, 16, true, false),
|
2021-03-06 13:10:36 +00:00
|
|
|
|
2022-02-15 03:32:31 +00:00
|
|
|
/*
|
|
|
|
???
|
|
|
|
*/
|
|
|
|
RDEF(ANZ, 915.0f, 928.0f, 100, 0, 0, true, false),
|
2021-03-06 13:10:36 +00:00
|
|
|
|
2022-02-15 03:32:31 +00:00
|
|
|
/*
|
|
|
|
https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf
|
2021-03-06 13:10:36 +00:00
|
|
|
|
2022-02-15 03:32:31 +00:00
|
|
|
Note:
|
|
|
|
- We do LBT, so 100% is allowed.
|
|
|
|
*/
|
|
|
|
RDEF(RU, 868.7f, 869.2f, 100, 0, 20, true, false),
|
|
|
|
|
|
|
|
/*
|
|
|
|
???
|
|
|
|
*/
|
|
|
|
RDEF(KR, 920.0f, 923.0f, 100, 0, 0, true, false),
|
|
|
|
|
|
|
|
/*
|
|
|
|
???
|
|
|
|
*/
|
|
|
|
RDEF(TW, 920.0f, 925.0f, 100, 0, 0, true, false),
|
|
|
|
|
|
|
|
/*
|
|
|
|
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
|
|
|
*/
|
|
|
|
RDEF(IN, 865.0f, 867.0f, 100, 0, 30, true, false),
|
|
|
|
|
|
|
|
/*
|
|
|
|
https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf
|
|
|
|
*/
|
|
|
|
RDEF(TH, 920.0f, 925.0f, 100, 0, 16, true, false),
|
|
|
|
|
|
|
|
/*
|
|
|
|
This needs to be last. Same as US.
|
|
|
|
*/
|
|
|
|
RDEF(Unset, 902.0f, 928.0f, 100, 0, 30, true, false)
|
|
|
|
|
|
|
|
};
|
2021-03-06 13:10:36 +00:00
|
|
|
|
2020-10-21 09:27:13 +00:00
|
|
|
const RegionInfo *myRegion;
|
|
|
|
|
|
|
|
void initRegion()
|
|
|
|
{
|
2020-10-29 05:26:36 +00:00
|
|
|
const RegionInfo *r = regions;
|
|
|
|
for (; r->code != RegionCode_Unset && r->code != radioConfig.preferences.region; r++)
|
|
|
|
;
|
|
|
|
myRegion = r;
|
|
|
|
DEBUG_MSG("Wanted region %d, using %s\n", radioConfig.preferences.region, r->name);
|
2020-10-21 09:27:13 +00:00
|
|
|
}
|
2020-09-25 19:52:08 +00:00
|
|
|
|
2020-05-09 23:32:26 +00:00
|
|
|
/**
|
|
|
|
* ## LoRaWAN for North America
|
|
|
|
|
|
|
|
LoRaWAN defines 64, 125 kHz channels from 902.3 to 914.9 MHz increments.
|
|
|
|
|
|
|
|
The maximum output power for North America is +30 dBM.
|
|
|
|
|
|
|
|
The band is from 902 to 928 MHz. It mentions channel number and its respective channel frequency. All the 13 channels are
|
|
|
|
separated by 2.16 MHz with respect to the adjacent channels. Channel zero starts at 903.08 MHz center frequency.
|
|
|
|
*/
|
|
|
|
|
2020-05-01 19:31:36 +00:00
|
|
|
// 1kb was too small
|
2020-05-01 19:11:04 +00:00
|
|
|
#define RADIO_STACK_SIZE 4096
|
|
|
|
|
2020-11-12 09:49:04 +00:00
|
|
|
/**
|
2020-11-14 02:07:25 +00:00
|
|
|
* 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
|
2020-11-12 09:49:04 +00:00
|
|
|
* section 4
|
2020-11-14 02:07:25 +00:00
|
|
|
*
|
2020-11-12 09:49:04 +00:00
|
|
|
* @return num msecs for the packet
|
|
|
|
*/
|
2020-11-14 02:07:25 +00:00
|
|
|
uint32_t RadioInterface::getPacketTime(uint32_t pl)
|
2020-11-12 09:49:04 +00:00
|
|
|
{
|
2020-11-14 02:07:25 +00:00
|
|
|
float bandwidthHz = bw * 1000.0f;
|
2020-11-12 09:49:04 +00:00
|
|
|
bool headDisable = false; // we currently always use the header
|
|
|
|
float tSym = (1 << sf) / bandwidthHz;
|
2020-11-14 02:07:25 +00:00
|
|
|
|
|
|
|
bool lowDataOptEn = tSym > 16e-3 ? true : false; // Needed if symbol time is >16ms
|
|
|
|
|
|
|
|
float tPreamble = (preambleLength + 4.25f) * tSym;
|
2020-11-12 09:49:04 +00:00
|
|
|
float numPayloadSym =
|
2020-11-14 02:07:25 +00:00
|
|
|
8 + max(ceilf(((8.0f * pl - 4 * sf + 28 + 16 - 20 * headDisable) / (4 * (sf - 2 * lowDataOptEn))) * cr), 0.0f);
|
2020-11-12 09:49:04 +00:00
|
|
|
float tPayload = numPayloadSym * tSym;
|
|
|
|
float tPacket = tPreamble + tPayload;
|
|
|
|
|
2020-11-14 02:07:25 +00:00
|
|
|
uint32_t msecs = tPacket * 1000;
|
|
|
|
|
|
|
|
DEBUG_MSG("(bw=%d, sf=%d, cr=4/%d) packet symLen=%d ms, payloadSize=%u, time %d ms\n", (int)bw, sf, cr, (int)(tSym * 1000),
|
|
|
|
pl, msecs);
|
2020-11-12 09:49:04 +00:00
|
|
|
return msecs;
|
|
|
|
}
|
|
|
|
|
2020-11-14 02:07:25 +00:00
|
|
|
uint32_t RadioInterface::getPacketTime(MeshPacket *p)
|
|
|
|
{
|
2021-02-10 08:18:41 +00:00
|
|
|
assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // It should have already been encoded by now
|
2020-11-14 02:07:25 +00:00
|
|
|
uint32_t pl = p->encrypted.size + sizeof(PacketHeader);
|
|
|
|
|
|
|
|
return getPacketTime(pl);
|
|
|
|
}
|
|
|
|
|
2020-11-12 09:49:04 +00:00
|
|
|
/** The delay to use for retransmitting dropped packets */
|
|
|
|
uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
|
|
|
|
{
|
2021-03-30 15:39:51 +00:00
|
|
|
assert(shortPacketMsec); // Better be non zero
|
|
|
|
|
2020-11-14 02:07:25 +00:00
|
|
|
// was 20 and 22 secs respectively, but now with shortPacketMsec as 2269, this should give the same range
|
|
|
|
return random(9 * shortPacketMsec, 10 * shortPacketMsec);
|
2020-11-12 09:49:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** The delay to use when we want to send something but the ether is busy */
|
|
|
|
uint32_t RadioInterface::getTxDelayMsec()
|
|
|
|
{
|
2020-11-14 02:07:25 +00:00
|
|
|
/** At the low end we want to pick a delay large enough that anyone who just completed sending (some other node)
|
|
|
|
* has had enough time to switch their radio back into receive mode.
|
|
|
|
*/
|
|
|
|
const uint32_t MIN_TX_WAIT_MSEC = 100;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* At the high end, this value is used to spread node attempts across time so when they are replying to a packet
|
|
|
|
* they don't both check that the airwaves are clear at the same moment. As long as they are off by some amount
|
|
|
|
* one of the two will be first to start transmitting and the other will see that. I bet 500ms is more than enough
|
|
|
|
* to guarantee this.
|
|
|
|
*/
|
|
|
|
// const uint32_t MAX_TX_WAIT_MSEC = 2000; // stress test would still fail occasionally with 1000
|
|
|
|
|
|
|
|
return random(MIN_TX_WAIT_MSEC, shortPacketMsec);
|
2020-11-12 09:49:04 +00:00
|
|
|
}
|
|
|
|
|
2020-06-14 22:30:42 +00:00
|
|
|
void printPacket(const char *prefix, const MeshPacket *p)
|
|
|
|
{
|
2021-03-06 03:13:33 +00:00
|
|
|
DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff,
|
|
|
|
p->want_ack, p->hop_limit, p->channel);
|
2021-02-10 08:18:41 +00:00
|
|
|
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
|
2020-06-14 22:30:42 +00:00
|
|
|
auto &s = p->decoded;
|
2021-03-06 03:13:33 +00:00
|
|
|
|
2021-02-17 05:06:23 +00:00
|
|
|
DEBUG_MSG(" Portnum=%d", s.portnum);
|
|
|
|
|
2020-06-14 22:30:42 +00:00
|
|
|
if (s.want_response)
|
|
|
|
DEBUG_MSG(" WANTRESP");
|
|
|
|
|
|
|
|
if (s.source != 0)
|
|
|
|
DEBUG_MSG(" source=%08x", s.source);
|
|
|
|
|
|
|
|
if (s.dest != 0)
|
|
|
|
DEBUG_MSG(" dest=%08x", s.dest);
|
|
|
|
|
2021-03-30 15:34:13 +00:00
|
|
|
if (s.request_id)
|
2021-03-12 06:10:36 +00:00
|
|
|
DEBUG_MSG(" requestId=%0x", s.request_id);
|
|
|
|
|
2021-02-17 05:06:23 +00:00
|
|
|
/* now inside Data and therefore kinda opaque
|
2021-02-10 08:18:41 +00:00
|
|
|
if (s.which_ackVariant == SubPacket_success_id_tag)
|
|
|
|
DEBUG_MSG(" successId=%08x", s.ackVariant.success_id);
|
|
|
|
else if (s.which_ackVariant == SubPacket_fail_id_tag)
|
2021-02-17 05:06:23 +00:00
|
|
|
DEBUG_MSG(" failId=%08x", s.ackVariant.fail_id); */
|
2020-06-14 22:30:42 +00:00
|
|
|
} else {
|
|
|
|
DEBUG_MSG(" encrypted");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p->rx_time != 0) {
|
|
|
|
DEBUG_MSG(" rxtime=%u", p->rx_time);
|
|
|
|
}
|
2020-08-25 19:06:36 +00:00
|
|
|
if (p->rx_snr != 0.0) {
|
|
|
|
DEBUG_MSG(" rxSNR=%g", p->rx_snr);
|
|
|
|
}
|
2021-02-17 05:06:23 +00:00
|
|
|
if (p->priority != 0)
|
2021-02-11 11:00:17 +00:00
|
|
|
DEBUG_MSG(" priority=%d", p->priority);
|
2021-02-17 05:06:23 +00:00
|
|
|
|
2020-06-14 22:30:42 +00:00
|
|
|
DEBUG_MSG(")\n");
|
|
|
|
}
|
|
|
|
|
2020-10-21 09:27:13 +00:00
|
|
|
RadioInterface::RadioInterface()
|
2020-04-30 16:44:16 +00:00
|
|
|
{
|
2021-02-22 04:57:26 +00:00
|
|
|
assert(sizeof(PacketHeader) == 16); // make sure the compiler did what we expected
|
2020-05-09 23:32:26 +00:00
|
|
|
|
|
|
|
// Can't print strings this early - serial not setup yet
|
|
|
|
// DEBUG_MSG("Set meshradio defaults name=%s\n", channelSettings.name);
|
2020-04-30 16:44:16 +00:00
|
|
|
}
|
2020-04-01 04:56:35 +00:00
|
|
|
|
2021-03-30 15:34:13 +00:00
|
|
|
bool RadioInterface::reconfigure()
|
|
|
|
{
|
|
|
|
applyModemConfig();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-05-01 19:11:04 +00:00
|
|
|
bool RadioInterface::init()
|
|
|
|
{
|
2020-05-09 23:32:26 +00:00
|
|
|
DEBUG_MSG("Starting meshradio init...\n");
|
|
|
|
|
|
|
|
configChangedObserver.observe(&service.configChanged);
|
|
|
|
preflightSleepObserver.observe(&preflightSleep);
|
|
|
|
notifyDeepSleepObserver.observe(¬ifyDeepSleep);
|
|
|
|
|
|
|
|
// we now expect interfaces to operate in promiscous mode
|
|
|
|
// radioIf.setThisAddress(nodeDB.getNodeNum()); // Note: we must do this here, because the nodenum isn't inited at constructor
|
|
|
|
// time.
|
2020-10-21 09:27:13 +00:00
|
|
|
|
2021-03-30 15:34:13 +00:00
|
|
|
applyModemConfig();
|
|
|
|
|
2020-05-01 19:11:04 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-10-30 09:05:32 +00:00
|
|
|
int RadioInterface::notifyDeepSleepCb(void *unused)
|
|
|
|
{
|
|
|
|
sleep();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-09 23:32:26 +00:00
|
|
|
/** hash a string into an integer
|
|
|
|
*
|
|
|
|
* djb2 by Dan Bernstein.
|
|
|
|
* http://www.cse.yorku.ca/~oz/hash.html
|
|
|
|
*/
|
2020-09-16 04:05:57 +00:00
|
|
|
unsigned long hash(const char *str)
|
2020-05-09 23:32:26 +00:00
|
|
|
{
|
|
|
|
unsigned long hash = 5381;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
while ((c = *str++) != 0)
|
|
|
|
hash = ((hash << 5) + hash) + (unsigned char)c; /* hash * 33 + c */
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
2021-02-10 05:59:00 +00:00
|
|
|
/**
|
|
|
|
* Save our frequency for later reuse.
|
|
|
|
*/
|
|
|
|
void RadioInterface::saveFreq(float freq)
|
|
|
|
{
|
|
|
|
savedFreq = freq;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Save our channel for later reuse.
|
|
|
|
*/
|
|
|
|
void RadioInterface::saveChannelNum(uint32_t channel_num)
|
|
|
|
{
|
|
|
|
savedChannelNum = channel_num;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Save our frequency for later reuse.
|
|
|
|
*/
|
|
|
|
float RadioInterface::getFreq()
|
|
|
|
{
|
|
|
|
return savedFreq;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Save our channel for later reuse.
|
|
|
|
*/
|
|
|
|
uint32_t RadioInterface::getChannelNum()
|
|
|
|
{
|
|
|
|
return savedChannelNum;
|
|
|
|
}
|
|
|
|
|
2020-05-09 23:32:26 +00:00
|
|
|
/**
|
|
|
|
* Pull our channel settings etc... from protobufs to the dumb interface settings
|
|
|
|
*/
|
|
|
|
void RadioInterface::applyModemConfig()
|
|
|
|
{
|
|
|
|
// Set up default configuration
|
2020-08-12 17:42:25 +00:00
|
|
|
// No Sync Words in LORA mode
|
|
|
|
|
2021-02-16 07:41:52 +00:00
|
|
|
auto channelSettings = channels.getPrimary();
|
2020-11-14 02:07:25 +00:00
|
|
|
if (channelSettings.spread_factor == 0) {
|
|
|
|
switch (channelSettings.modem_config) {
|
2022-02-15 03:32:31 +00:00
|
|
|
case ChannelSettings_ModemConfig_ShortFast:
|
|
|
|
bw = 250;
|
|
|
|
cr = 8;
|
2020-11-14 02:07:25 +00:00
|
|
|
sf = 7;
|
|
|
|
break;
|
2022-02-15 03:32:31 +00:00
|
|
|
case ChannelSettings_ModemConfig_ShortSlow:
|
|
|
|
bw = 250;
|
|
|
|
cr = 8;
|
|
|
|
sf = 8;
|
2020-11-14 02:07:25 +00:00
|
|
|
break;
|
2022-02-15 03:32:31 +00:00
|
|
|
case ChannelSettings_ModemConfig_MidFast:
|
|
|
|
bw = 250;
|
2020-11-14 02:07:25 +00:00
|
|
|
cr = 8;
|
|
|
|
sf = 9;
|
|
|
|
break;
|
2022-02-15 03:32:31 +00:00
|
|
|
case ChannelSettings_ModemConfig_MidSlow:
|
|
|
|
bw = 250;
|
2020-11-14 02:07:25 +00:00
|
|
|
cr = 8;
|
2022-02-15 03:32:31 +00:00
|
|
|
sf = 10;
|
2020-11-14 02:07:25 +00:00
|
|
|
break;
|
2022-02-16 02:48:54 +00:00
|
|
|
case ChannelSettings_ModemConfig_LongFast:
|
2021-12-06 23:03:35 +00:00
|
|
|
bw = 250;
|
2022-02-15 03:32:31 +00:00
|
|
|
cr = 8;
|
2021-12-06 23:03:35 +00:00
|
|
|
sf = 11;
|
|
|
|
break;
|
2022-02-16 02:48:54 +00:00
|
|
|
case ChannelSettings_ModemConfig_LongSlow:
|
2022-02-15 03:32:31 +00:00
|
|
|
bw = 125;
|
|
|
|
cr = 8;
|
|
|
|
sf = 12;
|
|
|
|
break;
|
|
|
|
case ChannelSettings_ModemConfig_VLongSlow:
|
|
|
|
bw = 31.25;
|
|
|
|
cr = 8;
|
|
|
|
sf = 12;
|
2021-12-06 23:03:35 +00:00
|
|
|
break;
|
2020-11-14 02:07:25 +00:00
|
|
|
default:
|
|
|
|
assert(0); // Unknown enum
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sf = channelSettings.spread_factor;
|
|
|
|
cr = channelSettings.coding_rate;
|
|
|
|
bw = channelSettings.bandwidth;
|
|
|
|
|
|
|
|
if (bw == 31) // This parameter is not an integer
|
|
|
|
bw = 31.25;
|
2021-11-01 09:31:53 +00:00
|
|
|
if (bw == 62) // Fix for 62.5Khz bandwidth
|
|
|
|
bw = 62.5;
|
2020-11-14 02:07:25 +00:00
|
|
|
}
|
|
|
|
|
2020-08-12 17:42:25 +00:00
|
|
|
power = channelSettings.tx_power;
|
2020-11-14 02:07:25 +00:00
|
|
|
shortPacketMsec = getPacketTime(sizeof(PacketHeader));
|
2020-09-25 19:52:08 +00:00
|
|
|
assert(myRegion); // Should have been found in init
|
|
|
|
|
2022-02-15 03:32:31 +00:00
|
|
|
// Calculate the number of channels
|
2022-02-16 02:48:54 +00:00
|
|
|
uint32_t numChannels = floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000)));
|
2022-02-15 03:32:31 +00:00
|
|
|
|
2020-08-12 17:46:44 +00:00
|
|
|
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
|
2021-02-16 07:41:52 +00:00
|
|
|
const char *channelName = channels.getName(channels.getPrimaryIndex());
|
2022-02-15 03:32:31 +00:00
|
|
|
int channel_num = channelSettings.channel_num ? channelSettings.channel_num - 1 : hash(channelName) % numChannels;
|
2022-02-16 02:48:54 +00:00
|
|
|
float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num);
|
|
|
|
|
2021-09-15 09:09:11 +00:00
|
|
|
saveChannelNum(channel_num);
|
|
|
|
saveFreq(freq);
|
|
|
|
|
2021-02-10 05:59:00 +00:00
|
|
|
DEBUG_MSG("Set radio: name=%s, config=%u, ch=%d, power=%d\n", channelName, channelSettings.modem_config, channel_num, power);
|
2022-02-16 02:48:54 +00:00
|
|
|
DEBUG_MSG("Radio myRegion->freqStart / myRegion->freqEnd: %f -> %f (%f mhz)\n", myRegion->freqStart, myRegion->freqEnd,
|
|
|
|
myRegion->freqEnd - myRegion->freqStart);
|
2022-02-15 03:32:31 +00:00
|
|
|
DEBUG_MSG("Radio myRegion->numChannels: %d\n", numChannels);
|
2020-09-29 07:59:26 +00:00
|
|
|
DEBUG_MSG("Radio channel_num: %d\n", channel_num);
|
2022-02-15 03:32:31 +00:00
|
|
|
DEBUG_MSG("Radio frequency: %f\n", getFreq());
|
2020-11-14 02:07:25 +00:00
|
|
|
DEBUG_MSG("Short packet time: %u msec\n", shortPacketMsec);
|
2020-05-09 23:32:26 +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 RadioInterface::limitPower()
|
|
|
|
{
|
|
|
|
uint8_t maxPower = 255; // No limit
|
|
|
|
|
2020-09-25 19:52:08 +00:00
|
|
|
if (myRegion->powerLimit)
|
|
|
|
maxPower = myRegion->powerLimit;
|
|
|
|
|
2020-09-16 01:54:50 +00:00
|
|
|
if (power > maxPower) {
|
|
|
|
DEBUG_MSG("Lowering transmit power because of regulatory limits\n");
|
|
|
|
power = maxPower;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEBUG_MSG("Set radio: final power level=%d\n", power);
|
|
|
|
}
|
|
|
|
|
2020-04-01 04:56:35 +00:00
|
|
|
ErrorCode SimRadio::send(MeshPacket *p)
|
|
|
|
{
|
|
|
|
DEBUG_MSG("SimRadio.send\n");
|
2020-04-17 16:48:54 +00:00
|
|
|
packetPool.release(p);
|
2020-04-01 04:56:35 +00:00
|
|
|
return ERRNO_OK;
|
2020-04-17 16:48:54 +00:00
|
|
|
}
|
|
|
|
|
2020-04-18 21:22:24 +00:00
|
|
|
void RadioInterface::deliverToReceiver(MeshPacket *p)
|
2020-04-17 16:48:54 +00:00
|
|
|
{
|
2021-03-06 03:13:33 +00:00
|
|
|
if (router)
|
2021-04-05 01:24:00 +00:00
|
|
|
router->enqueueReceivedMessage(p);
|
2020-04-30 01:46:32 +00:00
|
|
|
}
|
|
|
|
|
2020-04-30 16:44:16 +00:00
|
|
|
/***
|
|
|
|
* given a packet set sendingPacket and decode the protobufs into radiobuf. Returns # of payload bytes to send
|
|
|
|
*/
|
|
|
|
size_t RadioInterface::beginSending(MeshPacket *p)
|
|
|
|
{
|
|
|
|
assert(!sendingPacket);
|
|
|
|
|
|
|
|
// DEBUG_MSG("sending queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)\n", rf95.txGood(), rf95.rxGood(), rf95.rxBad());
|
2021-02-10 08:18:41 +00:00
|
|
|
assert(p->which_payloadVariant == MeshPacket_encrypted_tag); // It should have already been encoded by now
|
2020-04-30 16:44:16 +00:00
|
|
|
|
2020-09-05 19:34:48 +00:00
|
|
|
lastTxStart = millis();
|
2020-04-30 16:44:16 +00:00
|
|
|
|
|
|
|
PacketHeader *h = (PacketHeader *)radiobuf;
|
|
|
|
|
|
|
|
h->from = p->from;
|
|
|
|
h->to = p->to;
|
|
|
|
h->id = p->id;
|
2021-02-22 04:57:26 +00:00
|
|
|
h->channel = p->channel;
|
2020-05-19 00:35:23 +00:00
|
|
|
assert(p->hop_limit <= HOP_MAX);
|
2020-05-19 17:27:28 +00:00
|
|
|
h->flags = p->hop_limit | (p->want_ack ? PACKET_FLAGS_WANT_ACK_MASK : 0);
|
2020-04-30 16:44:16 +00:00
|
|
|
|
|
|
|
// if the sender nodenum is zero, that means uninitialized
|
|
|
|
assert(h->from);
|
|
|
|
|
2020-05-10 00:51:20 +00:00
|
|
|
memcpy(radiobuf + sizeof(PacketHeader), p->encrypted.bytes, p->encrypted.size);
|
2020-04-30 16:44:16 +00:00
|
|
|
|
|
|
|
sendingPacket = p;
|
2020-05-10 00:51:20 +00:00
|
|
|
return p->encrypted.size + sizeof(PacketHeader);
|
2020-04-30 16:44:16 +00:00
|
|
|
}
|