mirror of
https://github.com/meshtastic/firmware.git
synced 2025-06-12 16:12:07 +00:00
commit
5678221ead
@ -144,7 +144,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
//#define DISABLE_NTP
|
//#define DISABLE_NTP
|
||||||
|
|
||||||
// Disable the welcome screen and allow
|
// Disable the welcome screen and allow
|
||||||
// #define DISABLE_WELCOME_UNSET
|
//#define DISABLE_WELCOME_UNSET
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// OLED & Input
|
// OLED & Input
|
||||||
|
@ -179,9 +179,6 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
|
|||||||
// Encapsulate as a FromRadio packet
|
// Encapsulate as a FromRadio packet
|
||||||
fromRadioScratch.which_payloadVariant = FromRadio_packet_tag;
|
fromRadioScratch.which_payloadVariant = FromRadio_packet_tag;
|
||||||
fromRadioScratch.packet = *packetForPhone;
|
fromRadioScratch.packet = *packetForPhone;
|
||||||
|
|
||||||
// TODO: Remove with compression rework
|
|
||||||
fromRadioScratch.packet.decoded.which_payloadVariant = Data_payload_tag;
|
|
||||||
}
|
}
|
||||||
releasePhonePacket();
|
releasePhonePacket();
|
||||||
break;
|
break;
|
||||||
|
@ -257,7 +257,7 @@ void printPacket(const char *prefix, const MeshPacket *p)
|
|||||||
DEBUG_MSG(" rxSNR=%g", p->rx_snr);
|
DEBUG_MSG(" rxSNR=%g", p->rx_snr);
|
||||||
}
|
}
|
||||||
if (p->rx_rssi != 0) {
|
if (p->rx_rssi != 0) {
|
||||||
DEBUG_MSG(" rxSNR=%g", p->rx_rssi);
|
DEBUG_MSG(" rxRSSI=%g", p->rx_rssi);
|
||||||
}
|
}
|
||||||
if (p->priority != 0)
|
if (p->priority != 0)
|
||||||
DEBUG_MSG(" priority=%d", p->priority);
|
DEBUG_MSG(" priority=%d", p->priority);
|
||||||
|
@ -93,278 +93,297 @@ bool RadioLibInterface::canSendImmediately()
|
|||||||
/// bluetooth comms code. If the txmit queue is empty it might return an error
|
/// bluetooth comms code. If the txmit queue is empty it might return an error
|
||||||
ErrorCode RadioLibInterface::send(MeshPacket *p)
|
ErrorCode RadioLibInterface::send(MeshPacket *p)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifndef DISABLE_WELCOME_UNSET
|
||||||
|
|
||||||
if (config.lora.region != Config_LoRaConfig_RegionCode_Unset) {
|
if (config.lora.region != Config_LoRaConfig_RegionCode_Unset) {
|
||||||
if (disabled || config.lora.tx_disabled) {
|
if (disabled || config.lora.tx_disabled) {
|
||||||
DEBUG_MSG("send - lora_tx_disabled\n");
|
|
||||||
packetPool.release(p);
|
|
||||||
return ERRNO_DISABLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
if (config.lora.region != Config_LoRaConfig_RegionCode_Unset) {
|
||||||
DEBUG_MSG("send - lora_tx_disabled because RegionCode_Unset\n");
|
if (disabled || config.lora.tx_disabled) {
|
||||||
|
DEBUG_MSG("send - lora_tx_disabled\n");
|
||||||
|
packetPool.release(p);
|
||||||
|
return ERRNO_DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
DEBUG_MSG("send - lora_tx_disabled because RegionCode_Unset\n");
|
||||||
|
packetPool.release(p);
|
||||||
|
return ERRNO_DISABLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
if (disabled || config.lora.tx_disabled) {
|
||||||
|
DEBUG_MSG("send - lora_tx_disabled\n");
|
||||||
packetPool.release(p);
|
packetPool.release(p);
|
||||||
return ERRNO_DISABLED;
|
return ERRNO_DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sometimes when testing it is useful to be able to never turn on the xmitter
|
#endif
|
||||||
|
|
||||||
|
// Sometimes when testing it is useful to be able to never turn on the xmitter
|
||||||
#ifndef LORA_DISABLE_SENDING
|
#ifndef LORA_DISABLE_SENDING
|
||||||
printPacket("enqueuing for send", p);
|
printPacket("enqueuing for send", p);
|
||||||
|
|
||||||
DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
|
DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
|
||||||
ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN;
|
ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN;
|
||||||
|
|
||||||
|
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
|
||||||
|
packetPool.release(p);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set (random) transmit delay to let others reconfigure their radio,
|
||||||
|
// to avoid collisions and implement timing-based flooding
|
||||||
|
// DEBUG_MSG("Set random delay before transmitting.\n");
|
||||||
|
setTransmitDelay();
|
||||||
|
|
||||||
if (res != ERRNO_OK) { // we weren't able to queue it, so we must drop it to prevent leaks
|
|
||||||
packetPool.release(p);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
|
||||||
|
|
||||||
// set (random) transmit delay to let others reconfigure their radio,
|
|
||||||
// to avoid collisions and implement timing-based flooding
|
|
||||||
// DEBUG_MSG("Set random delay before transmitting.\n");
|
|
||||||
setTransmitDelay();
|
|
||||||
|
|
||||||
return res;
|
|
||||||
#else
|
#else
|
||||||
packetPool.release(p);
|
packetPool.release(p);
|
||||||
return ERRNO_DISABLED;
|
return ERRNO_DISABLED;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RadioLibInterface::canSleep()
|
bool RadioLibInterface::canSleep()
|
||||||
{
|
{
|
||||||
bool res = txQueue.empty();
|
bool res = txQueue.empty();
|
||||||
if (!res) // only print debug messages if we are vetoing sleep
|
if (!res) // only print debug messages if we are vetoing sleep
|
||||||
DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res);
|
DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
|
||||||
bool RadioLibInterface::cancelSending(NodeNum from, PacketId id)
|
bool RadioLibInterface::cancelSending(NodeNum from, PacketId id)
|
||||||
{
|
{
|
||||||
auto p = txQueue.remove(from, id);
|
auto p = txQueue.remove(from, id);
|
||||||
if (p)
|
if (p)
|
||||||
packetPool.release(p); // free the packet we just removed
|
packetPool.release(p); // free the packet we just removed
|
||||||
|
|
||||||
bool result = (p != NULL);
|
bool result = (p != NULL);
|
||||||
DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, result);
|
DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** radio helper thread callback.
|
/** radio helper thread callback.
|
||||||
|
|
||||||
We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and
|
We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and
|
||||||
wait a random delay of 100ms to 100ms+shortPacketMsec to make sure we are not stomping on someone else. The 100ms delay at the
|
wait a random delay of 100ms to 100ms+shortPacketMsec to make sure we are not stomping on someone else. The 100ms delay
|
||||||
beginning ensures all possible listeners have had time to finish processing the previous packet and now have their radio in RX
|
at the beginning ensures all possible listeners have had time to finish processing the previous packet and now have their
|
||||||
state. The up to 100ms+shortPacketMsec random delay gives a chance for all possible senders to have high odds of detecting that
|
radio in RX state. The up to 100ms+shortPacketMsec random delay gives a chance for all possible senders to have high odds
|
||||||
someone else started transmitting first and then they will wait until that packet finishes.
|
of detecting that someone else started transmitting first and then they will wait until that packet finishes.
|
||||||
|
|
||||||
NOTE: the large flood rebroadcast delay might still be needed even with this approach. Because we might not be able to hear other
|
NOTE: the large flood rebroadcast delay might still be needed even with this approach. Because we might not be able to
|
||||||
transmitters that we are potentially stomping on. Requires further thought.
|
hear other transmitters that we are potentially stomping on. Requires further thought.
|
||||||
|
|
||||||
FIXME, the MIN_TX_WAIT_MSEC and MAX_TX_WAIT_MSEC values should be tuned via logic analyzer later.
|
FIXME, the MIN_TX_WAIT_MSEC and MAX_TX_WAIT_MSEC values should be tuned via logic analyzer later.
|
||||||
*/
|
*/
|
||||||
void RadioLibInterface::onNotify(uint32_t notification)
|
void RadioLibInterface::onNotify(uint32_t notification)
|
||||||
{
|
{
|
||||||
switch (notification) {
|
switch (notification) {
|
||||||
case ISR_TX:
|
case ISR_TX:
|
||||||
handleTransmitInterrupt();
|
handleTransmitInterrupt();
|
||||||
startReceive();
|
startReceive();
|
||||||
// DEBUG_MSG("tx complete - starting timer\n");
|
// DEBUG_MSG("tx complete - starting timer\n");
|
||||||
startTransmitTimer();
|
startTransmitTimer();
|
||||||
break;
|
break;
|
||||||
case ISR_RX:
|
case ISR_RX:
|
||||||
handleReceiveInterrupt();
|
handleReceiveInterrupt();
|
||||||
startReceive();
|
startReceive();
|
||||||
// DEBUG_MSG("rx complete - starting timer\n");
|
// DEBUG_MSG("rx complete - starting timer\n");
|
||||||
startTransmitTimer();
|
startTransmitTimer();
|
||||||
break;
|
break;
|
||||||
case TRANSMIT_DELAY_COMPLETED:
|
case TRANSMIT_DELAY_COMPLETED:
|
||||||
// DEBUG_MSG("delay done\n");
|
// DEBUG_MSG("delay done\n");
|
||||||
|
|
||||||
// If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
|
// If we are not currently in receive mode, then restart the random delay (this can happen if the main thread
|
||||||
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
|
// has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode?
|
||||||
if (!txQueue.empty()) {
|
if (!txQueue.empty()) {
|
||||||
if (!canSendImmediately()) {
|
if (!canSendImmediately()) {
|
||||||
// DEBUG_MSG("Currently Rx/Tx-ing: set random delay\n");
|
// DEBUG_MSG("Currently Rx/Tx-ing: set random delay\n");
|
||||||
setTransmitDelay(); // currently Rx/Tx-ing: reset random delay
|
setTransmitDelay(); // currently Rx/Tx-ing: reset random delay
|
||||||
} else {
|
|
||||||
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel
|
|
||||||
// DEBUG_MSG("Channel is active: set random delay\n");
|
|
||||||
setTransmitDelay(); // reset random delay
|
|
||||||
} else {
|
} else {
|
||||||
// Send any outgoing packets we have ready
|
if (isChannelActive()) { // check if there is currently a LoRa packet on the channel
|
||||||
MeshPacket *txp = txQueue.dequeue();
|
// DEBUG_MSG("Channel is active: set random delay\n");
|
||||||
assert(txp);
|
setTransmitDelay(); // reset random delay
|
||||||
startSend(txp);
|
} else {
|
||||||
|
// Send any outgoing packets we have ready
|
||||||
|
MeshPacket *txp = txQueue.dequeue();
|
||||||
|
assert(txp);
|
||||||
|
startSend(txp);
|
||||||
|
|
||||||
// Packet has been sent, count it toward our TX airtime utilization.
|
// Packet has been sent, count it toward our TX airtime utilization.
|
||||||
uint32_t xmitMsec = getPacketTime(txp);
|
uint32_t xmitMsec = getPacketTime(txp);
|
||||||
airTime->logAirtime(TX_LOG, xmitMsec);
|
airTime->logAirtime(TX_LOG, xmitMsec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// DEBUG_MSG("done with txqueue\n");
|
||||||
}
|
}
|
||||||
} else {
|
break;
|
||||||
// DEBUG_MSG("done with txqueue\n");
|
default:
|
||||||
}
|
assert(0); // We expected to receive a valid notification from the ISR
|
||||||
break;
|
|
||||||
default:
|
|
||||||
assert(0); // We expected to receive a valid notification from the ISR
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioLibInterface::setTransmitDelay()
|
|
||||||
{
|
|
||||||
MeshPacket *p = txQueue.getFront();
|
|
||||||
// We want all sending/receiving to be done by our daemon thread.
|
|
||||||
// We use a delay here because this packet might have been sent in response to a packet we just received.
|
|
||||||
// So we want to make sure the other side has had a chance to reconfigure its radio.
|
|
||||||
|
|
||||||
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
|
|
||||||
* This assumption is valid because of the offset generated by the radio to account for the noise
|
|
||||||
* floor.
|
|
||||||
*/
|
|
||||||
if (p->rx_snr == 0 && p->rx_rssi == 0) {
|
|
||||||
startTransmitTimer(true);
|
|
||||||
} else {
|
|
||||||
// If there is a SNR, start a timer scaled based on that SNR.
|
|
||||||
DEBUG_MSG("rx_snr found. hop_limit:%d rx_snr:%f\n", p->hop_limit, p->rx_snr);
|
|
||||||
startTransmitTimerSNR(p->rx_snr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioLibInterface::startTransmitTimer(bool withDelay)
|
|
||||||
{
|
|
||||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
|
||||||
if (!txQueue.empty()) {
|
|
||||||
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
|
|
||||||
// DEBUG_MSG("xmit timer %d\n", delay);
|
|
||||||
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioLibInterface::startTransmitTimerSNR(float snr)
|
|
||||||
{
|
|
||||||
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
|
||||||
if (!txQueue.empty()) {
|
|
||||||
uint32_t delay = getTxDelayMsecWeighted(snr);
|
|
||||||
// DEBUG_MSG("xmit timer %d\n", delay);
|
|
||||||
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioLibInterface::handleTransmitInterrupt()
|
|
||||||
{
|
|
||||||
// DEBUG_MSG("handling lora TX interrupt\n");
|
|
||||||
// This can be null if we forced the device to enter standby mode. In that case
|
|
||||||
// ignore the transmit interrupt
|
|
||||||
if (sendingPacket)
|
|
||||||
completeSending();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioLibInterface::completeSending()
|
|
||||||
{
|
|
||||||
// We are careful to clear sending packet before calling printPacket because
|
|
||||||
// that can take a long time
|
|
||||||
auto p = sendingPacket;
|
|
||||||
sendingPacket = NULL;
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
txGood++;
|
|
||||||
printPacket("Completed sending", p);
|
|
||||||
|
|
||||||
// We are done sending that packet, release it
|
|
||||||
packetPool.release(p);
|
|
||||||
// DEBUG_MSG("Done with send\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RadioLibInterface::handleReceiveInterrupt()
|
|
||||||
{
|
|
||||||
uint32_t xmitMsec;
|
|
||||||
assert(isReceiving);
|
|
||||||
isReceiving = false;
|
|
||||||
|
|
||||||
// read the number of actually received bytes
|
|
||||||
size_t length = iface->getPacketLength();
|
|
||||||
|
|
||||||
xmitMsec = getPacketTime(length);
|
|
||||||
|
|
||||||
int state = iface->readData(radiobuf, length);
|
|
||||||
if (state != ERR_NONE) {
|
|
||||||
DEBUG_MSG("ignoring received packet due to error=%d\n", state);
|
|
||||||
rxBad++;
|
|
||||||
|
|
||||||
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Skip the 4 headers that are at the beginning of the rxBuf
|
|
||||||
int32_t payloadLen = length - sizeof(PacketHeader);
|
|
||||||
const uint8_t *payload = radiobuf + sizeof(PacketHeader);
|
|
||||||
|
|
||||||
// check for short packets
|
|
||||||
if (payloadLen < 0) {
|
|
||||||
DEBUG_MSG("ignoring received packet too short\n");
|
|
||||||
rxBad++;
|
|
||||||
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
|
|
||||||
} else {
|
|
||||||
const PacketHeader *h = (PacketHeader *)radiobuf;
|
|
||||||
|
|
||||||
rxGood++;
|
|
||||||
|
|
||||||
// Note: we deliver _all_ packets to our router (i.e. our interface is intentionally promiscuous).
|
|
||||||
// This allows the router and other apps on our node to sniff packets (usually routing) between other
|
|
||||||
// nodes.
|
|
||||||
MeshPacket *mp = packetPool.allocZeroed();
|
|
||||||
|
|
||||||
mp->from = h->from;
|
|
||||||
mp->to = h->to;
|
|
||||||
mp->id = h->id;
|
|
||||||
mp->channel = h->channel;
|
|
||||||
assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
|
|
||||||
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
|
|
||||||
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
|
|
||||||
|
|
||||||
addReceiveMetadata(mp);
|
|
||||||
|
|
||||||
mp->which_payloadVariant = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
|
|
||||||
assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes));
|
|
||||||
memcpy(mp->encrypted.bytes, payload, payloadLen);
|
|
||||||
mp->encrypted.size = payloadLen;
|
|
||||||
|
|
||||||
printPacket("Lora RX", mp);
|
|
||||||
|
|
||||||
// xmitMsec = getPacketTime(mp);
|
|
||||||
airTime->logAirtime(RX_LOG, xmitMsec);
|
|
||||||
|
|
||||||
deliverToReceiver(mp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** start an immediate transmit */
|
void RadioLibInterface::setTransmitDelay()
|
||||||
void RadioLibInterface::startSend(MeshPacket *txp)
|
{
|
||||||
{
|
MeshPacket *p = txQueue.getFront();
|
||||||
printPacket("Starting low level send", txp);
|
// We want all sending/receiving to be done by our daemon thread.
|
||||||
if (disabled || config.lora.tx_disabled) {
|
// We use a delay here because this packet might have been sent in response to a packet we just received.
|
||||||
DEBUG_MSG("startSend is dropping tx packet because we are disabled\n");
|
// So we want to make sure the other side has had a chance to reconfigure its radio.
|
||||||
packetPool.release(txp);
|
|
||||||
} else {
|
|
||||||
setStandby(); // Cancel any already in process receives
|
|
||||||
|
|
||||||
configHardwareForSend(); // must be after setStandby
|
/* We assume if rx_snr = 0 and rx_rssi = 0, the packet was generated locally.
|
||||||
|
* This assumption is valid because of the offset generated by the radio to account for the noise
|
||||||
|
* floor.
|
||||||
|
*/
|
||||||
|
if (p->rx_snr == 0 && p->rx_rssi == 0) {
|
||||||
|
startTransmitTimer(true);
|
||||||
|
} else {
|
||||||
|
// If there is a SNR, start a timer scaled based on that SNR.
|
||||||
|
DEBUG_MSG("rx_snr found. hop_limit:%d rx_snr:%f\n", p->hop_limit, p->rx_snr);
|
||||||
|
startTransmitTimerSNR(p->rx_snr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t numbytes = beginSending(txp);
|
void RadioLibInterface::startTransmitTimer(bool withDelay)
|
||||||
|
{
|
||||||
|
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||||
|
if (!txQueue.empty()) {
|
||||||
|
uint32_t delay = !withDelay ? 1 : getTxDelayMsec();
|
||||||
|
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||||
|
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int res = iface->startTransmit(radiobuf, numbytes);
|
void RadioLibInterface::startTransmitTimerSNR(float snr)
|
||||||
if (res != ERR_NONE) {
|
{
|
||||||
RECORD_CRITICALERROR(CriticalErrorCode_RadioSpiBug);
|
// If we have work to do and the timer wasn't already scheduled, schedule it now
|
||||||
|
if (!txQueue.empty()) {
|
||||||
|
uint32_t delay = getTxDelayMsecWeighted(snr);
|
||||||
|
// DEBUG_MSG("xmit timer %d\n", delay);
|
||||||
|
notifyLater(delay, TRANSMIT_DELAY_COMPLETED, false); // This will implicitly enable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This send failed, but make sure to 'complete' it properly
|
void RadioLibInterface::handleTransmitInterrupt()
|
||||||
|
{
|
||||||
|
// DEBUG_MSG("handling lora TX interrupt\n");
|
||||||
|
// This can be null if we forced the device to enter standby mode. In that case
|
||||||
|
// ignore the transmit interrupt
|
||||||
|
if (sendingPacket)
|
||||||
completeSending();
|
completeSending();
|
||||||
startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits
|
|
||||||
enableInterrupt(isrTxLevel0);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
void RadioLibInterface::completeSending()
|
||||||
|
{
|
||||||
|
// We are careful to clear sending packet before calling printPacket because
|
||||||
|
// that can take a long time
|
||||||
|
auto p = sendingPacket;
|
||||||
|
sendingPacket = NULL;
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
txGood++;
|
||||||
|
printPacket("Completed sending", p);
|
||||||
|
|
||||||
|
// We are done sending that packet, release it
|
||||||
|
packetPool.release(p);
|
||||||
|
// DEBUG_MSG("Done with send\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RadioLibInterface::handleReceiveInterrupt()
|
||||||
|
{
|
||||||
|
uint32_t xmitMsec;
|
||||||
|
assert(isReceiving);
|
||||||
|
isReceiving = false;
|
||||||
|
|
||||||
|
// read the number of actually received bytes
|
||||||
|
size_t length = iface->getPacketLength();
|
||||||
|
|
||||||
|
xmitMsec = getPacketTime(length);
|
||||||
|
|
||||||
|
int state = iface->readData(radiobuf, length);
|
||||||
|
if (state != ERR_NONE) {
|
||||||
|
DEBUG_MSG("ignoring received packet due to error=%d\n", state);
|
||||||
|
rxBad++;
|
||||||
|
|
||||||
|
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Skip the 4 headers that are at the beginning of the rxBuf
|
||||||
|
int32_t payloadLen = length - sizeof(PacketHeader);
|
||||||
|
const uint8_t *payload = radiobuf + sizeof(PacketHeader);
|
||||||
|
|
||||||
|
// check for short packets
|
||||||
|
if (payloadLen < 0) {
|
||||||
|
DEBUG_MSG("ignoring received packet too short\n");
|
||||||
|
rxBad++;
|
||||||
|
airTime->logAirtime(RX_ALL_LOG, xmitMsec);
|
||||||
|
} else {
|
||||||
|
const PacketHeader *h = (PacketHeader *)radiobuf;
|
||||||
|
|
||||||
|
rxGood++;
|
||||||
|
|
||||||
|
// Note: we deliver _all_ packets to our router (i.e. our interface is intentionally promiscuous).
|
||||||
|
// This allows the router and other apps on our node to sniff packets (usually routing) between other
|
||||||
|
// nodes.
|
||||||
|
MeshPacket *mp = packetPool.allocZeroed();
|
||||||
|
|
||||||
|
mp->from = h->from;
|
||||||
|
mp->to = h->to;
|
||||||
|
mp->id = h->id;
|
||||||
|
mp->channel = h->channel;
|
||||||
|
assert(HOP_MAX <= PACKET_FLAGS_HOP_MASK); // If hopmax changes, carefully check this code
|
||||||
|
mp->hop_limit = h->flags & PACKET_FLAGS_HOP_MASK;
|
||||||
|
mp->want_ack = !!(h->flags & PACKET_FLAGS_WANT_ACK_MASK);
|
||||||
|
|
||||||
|
addReceiveMetadata(mp);
|
||||||
|
|
||||||
|
mp->which_payloadVariant = MeshPacket_encrypted_tag; // Mark that the payload is still encrypted at this point
|
||||||
|
assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes));
|
||||||
|
memcpy(mp->encrypted.bytes, payload, payloadLen);
|
||||||
|
mp->encrypted.size = payloadLen;
|
||||||
|
|
||||||
|
printPacket("Lora RX", mp);
|
||||||
|
|
||||||
|
// xmitMsec = getPacketTime(mp);
|
||||||
|
airTime->logAirtime(RX_LOG, xmitMsec);
|
||||||
|
|
||||||
|
deliverToReceiver(mp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** start an immediate transmit */
|
||||||
|
void RadioLibInterface::startSend(MeshPacket * txp)
|
||||||
|
{
|
||||||
|
printPacket("Starting low level send", txp);
|
||||||
|
if (disabled || config.lora.tx_disabled) {
|
||||||
|
DEBUG_MSG("startSend is dropping tx packet because we are disabled\n");
|
||||||
|
packetPool.release(txp);
|
||||||
|
} else {
|
||||||
|
setStandby(); // Cancel any already in process receives
|
||||||
|
|
||||||
|
configHardwareForSend(); // must be after setStandby
|
||||||
|
|
||||||
|
size_t numbytes = beginSending(txp);
|
||||||
|
|
||||||
|
int res = iface->startTransmit(radiobuf, numbytes);
|
||||||
|
if (res != ERR_NONE) {
|
||||||
|
RECORD_CRITICALERROR(CriticalErrorCode_RadioSpiBug);
|
||||||
|
|
||||||
|
// This send failed, but make sure to 'complete' it properly
|
||||||
|
completeSending();
|
||||||
|
startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register
|
||||||
|
// bits
|
||||||
|
enableInterrupt(isrTxLevel0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -274,6 +274,9 @@ void Router::sniffReceived(const MeshPacket *p, const Routing *c)
|
|||||||
|
|
||||||
bool perhapsDecode(MeshPacket *p)
|
bool perhapsDecode(MeshPacket *p)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// DEBUG_MSG("\n\n** perhapsDecode payloadVariant - %d\n\n", p->which_payloadVariant);
|
||||||
|
|
||||||
if (p->which_payloadVariant == MeshPacket_decoded_tag)
|
if (p->which_payloadVariant == MeshPacket_decoded_tag)
|
||||||
return true; // If packet was already decoded just return
|
return true; // If packet was already decoded just return
|
||||||
|
|
||||||
@ -304,9 +307,31 @@ bool perhapsDecode(MeshPacket *p)
|
|||||||
p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded
|
p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded
|
||||||
p->channel = chIndex; // change to store the index instead of the hash
|
p->channel = chIndex; // change to store the index instead of the hash
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (p->decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
|
||||||
|
DEBUG_MSG("\n\n** TEXT_MESSAGE_APP\n");
|
||||||
|
} else if (p->decoded.portnum == PortNum_TEXT_MESSAGE_COMPRESSED_APP) {
|
||||||
|
DEBUG_MSG("\n\n** PortNum_TEXT_MESSAGE_COMPRESSED_APP\n");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Decompress if needed. jm
|
// Decompress if needed. jm
|
||||||
if (p->decoded.which_payloadVariant == Data_payload_compressed_tag) {
|
if (p->decoded.portnum == PortNum_TEXT_MESSAGE_COMPRESSED_APP) {
|
||||||
// Decompress the file
|
// Decompress the payload
|
||||||
|
char compressed_in[Constants_DATA_PAYLOAD_LEN] = {};
|
||||||
|
char decompressed_out[Constants_DATA_PAYLOAD_LEN] = {};
|
||||||
|
int decompressed_len;
|
||||||
|
|
||||||
|
memcpy(compressed_in, p->decoded.payload.bytes, p->decoded.payload.size);
|
||||||
|
|
||||||
|
decompressed_len = unishox2_decompress_simple(compressed_in, p->decoded.payload.size, decompressed_out);
|
||||||
|
|
||||||
|
// DEBUG_MSG("\n\n**\n\nDecompressed length - %d \n", decompressed_len);
|
||||||
|
|
||||||
|
memcpy(p->decoded.payload.bytes, decompressed_out, decompressed_len);
|
||||||
|
|
||||||
|
// Switch the port from PortNum_TEXT_MESSAGE_COMPRESSED_APP to PortNum_TEXT_MESSAGE_APP
|
||||||
|
p->decoded.portnum = PortNum_TEXT_MESSAGE_APP;
|
||||||
}
|
}
|
||||||
|
|
||||||
printPacket("decoded message", p);
|
printPacket("decoded message", p);
|
||||||
@ -339,41 +364,28 @@ Routing_Error perhapsEncode(MeshPacket *p)
|
|||||||
char compressed_out[Constants_DATA_PAYLOAD_LEN] = {0};
|
char compressed_out[Constants_DATA_PAYLOAD_LEN] = {0};
|
||||||
|
|
||||||
int compressed_len;
|
int compressed_len;
|
||||||
// compressed_len = unishox2_compress_simple(original_payload, p->decoded.payload.size, compressed_out);
|
compressed_len = unishox2_compress_simple(original_payload, p->decoded.payload.size, compressed_out);
|
||||||
|
|
||||||
Serial.print("Original length - ");
|
DEBUG_MSG("Original length - %d \n", p->decoded.payload.size);
|
||||||
Serial.println(p->decoded.payload.size);
|
DEBUG_MSG("Compressed length - %d \n", compressed_len);
|
||||||
|
DEBUG_MSG("Original message - %s \n", p->decoded.payload.bytes);
|
||||||
Serial.print("Compressed length - ");
|
|
||||||
Serial.println(compressed_len);
|
|
||||||
// Serial.println(compressed_out);
|
|
||||||
|
|
||||||
// If the compressed length is greater than or equal to the original size, don't use the compressed form
|
// If the compressed length is greater than or equal to the original size, don't use the compressed form
|
||||||
if (compressed_len >= p->decoded.payload.size) {
|
if (compressed_len >= p->decoded.payload.size) {
|
||||||
|
|
||||||
DEBUG_MSG("Not compressing message. Not enough benefit from doing so.\n");
|
DEBUG_MSG("Not using compressing message.\n");
|
||||||
// Set the uncompressed payload varient anyway. Shouldn't hurt?
|
// Set the uncompressed payload varient anyway. Shouldn't hurt?
|
||||||
p->decoded.which_payloadVariant = Data_payload_tag;
|
// p->decoded.which_payloadVariant = Data_payload_tag;
|
||||||
|
|
||||||
// Otherwise we use the compressor
|
// Otherwise we use the compressor
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("Compressing message.\n");
|
DEBUG_MSG("Using compressed message.\n");
|
||||||
// Copy the compressed data into the meshpacket
|
// Copy the compressed data into the meshpacket
|
||||||
// p->decoded.payload_compressed.size = compressed_len;
|
|
||||||
// memcpy(p->decoded.payload_compressed.bytes, compressed_out, compressed_len);
|
|
||||||
|
|
||||||
// p->decoded.which_payloadVariant = Data_payload_compressed_tag;
|
p->decoded.payload.size = compressed_len;
|
||||||
}
|
memcpy(p->decoded.payload.bytes, compressed_out, compressed_len);
|
||||||
|
|
||||||
if (0) {
|
p->decoded.portnum = PortNum_TEXT_MESSAGE_COMPRESSED_APP;
|
||||||
char decompressed_out[Constants_DATA_PAYLOAD_LEN] = {};
|
|
||||||
int decompressed_len;
|
|
||||||
|
|
||||||
// decompressed_len = unishox2_decompress_simple(compressed_out, compressed_len, decompressed_out);
|
|
||||||
|
|
||||||
Serial.print("Decompressed length - ");
|
|
||||||
Serial.println(decompressed_len);
|
|
||||||
Serial.println(decompressed_out);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,8 +36,8 @@ int32_t RangeTestModule::runOnce()
|
|||||||
without having to configure it from the PythonAPI or WebUI.
|
without having to configure it from the PythonAPI or WebUI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// moduleConfig.range_test.enabled = 1;
|
//moduleConfig.range_test.enabled = 1;
|
||||||
// moduleConfig.range_test.sender = 45;
|
//moduleConfig.range_test.sender = 30;
|
||||||
// moduleConfig.range_test.save = 1;
|
// moduleConfig.range_test.save = 1;
|
||||||
|
|
||||||
// Fixed position is useful when testing indoors.
|
// Fixed position is useful when testing indoors.
|
||||||
@ -115,7 +115,7 @@ void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
|
|||||||
|
|
||||||
packetSequence++;
|
packetSequence++;
|
||||||
|
|
||||||
static char heartbeatString[20];
|
static char heartbeatString[MAX_RHPACKETLEN];
|
||||||
snprintf(heartbeatString, sizeof(heartbeatString), "seq %u", packetSequence);
|
snprintf(heartbeatString, sizeof(heartbeatString), "seq %u", packetSequence);
|
||||||
|
|
||||||
p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
|
p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply
|
||||||
|
Loading…
Reference in New Issue
Block a user