diff --git a/protobufs b/protobufs index 98a888f8..40b82242 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 98a888f863a750464cd44526568af20c7bf12227 +Subproject commit 40b822424221f4f7704e291d2b422c9dcca84c83 diff --git a/src/configuration.h b/src/configuration.h index 16262d97..1f4864f8 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -144,7 +144,7 @@ along with this program. If not, see . //#define DISABLE_NTP // Disable the welcome screen and allow -// #define DISABLE_WELCOME_UNSET +//#define DISABLE_WELCOME_UNSET // ----------------------------------------------------------------------------- // OLED & Input diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index d804aa8e..47b9d0bc 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -146,6 +146,13 @@ bool NodeDB::resetRadioConfig() void NodeDB::installDefaultConfig() { memset(&config, 0, sizeof(LocalConfig)); + config.has_device = true; + config.has_display = true; + config.has_lora = true; + config.has_position = true; + config.has_power = true; + config.has_wifi = true; + config.lora.region = Config_LoRaConfig_RegionCode_Unset; config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LongFast; resetRadioConfig(); @@ -158,6 +165,13 @@ void NodeDB::installDefaultConfig() void NodeDB::installDefaultModuleConfig() { memset(&moduleConfig, 0, sizeof(ModuleConfig)); + moduleConfig.has_canned_message = true; + moduleConfig.has_external_notification = true; + moduleConfig.has_mqtt = true; + moduleConfig.has_range_test = true; + moduleConfig.has_serial = true; + moduleConfig.has_store_forward = true; + moduleConfig.has_telemetry = true; } // void NodeDB::installDefaultRadioConfig() @@ -341,7 +355,7 @@ void NodeDB::loadFromDisk() installDefaultConfig(); // Our in RAM copy might now be corrupt } - if (!loadProto(moduleConfigfile, ModuleConfig_size, sizeof(ModuleConfig), ModuleConfig_fields, &moduleConfig)) { + if (!loadProto(moduleConfigfile, LocalModuleConfig_size, sizeof(LocalModuleConfig), LocalModuleConfig_fields, &moduleConfig)) { installDefaultModuleConfig(); // Our in RAM copy might now be corrupt } @@ -402,6 +416,7 @@ void NodeDB::saveToDisk() FSCom.mkdir("/prefs"); #endif saveProto(preffile, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate); + // save all config segments config.has_device = true; config.has_display = true; @@ -410,7 +425,16 @@ void NodeDB::saveToDisk() config.has_power = true; config.has_wifi = true; saveProto(configfile, LocalConfig_size, sizeof(LocalConfig), LocalConfig_fields, &config); - saveProto(moduleConfigfile, Module_Config_size, sizeof(ModuleConfig), ModuleConfig_fields, &moduleConfig); + + moduleConfig.has_canned_message = true; + moduleConfig.has_external_notification = true; + moduleConfig.has_mqtt = true; + moduleConfig.has_range_test = true; + moduleConfig.has_serial = true; + moduleConfig.has_store_forward = true; + moduleConfig.has_telemetry = true; + saveProto(moduleConfigfile, LocalModuleConfig_size, sizeof(LocalModuleConfig), LocalModuleConfig_fields, &moduleConfig); + saveChannelsToDisk(); } else { diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index cc40ff72..033ef490 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -179,9 +179,6 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Encapsulate as a FromRadio packet fromRadioScratch.which_payloadVariant = FromRadio_packet_tag; fromRadioScratch.packet = *packetForPhone; - - // TODO: Remove with compression rework - fromRadioScratch.packet.decoded.which_payloadVariant = Data_payload_tag; } releasePhonePacket(); break; diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 11183151..d949c462 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -257,7 +257,7 @@ void printPacket(const char *prefix, const MeshPacket *p) DEBUG_MSG(" rxSNR=%g", p->rx_snr); } if (p->rx_rssi != 0) { - DEBUG_MSG(" rxSNR=%g", p->rx_rssi); + DEBUG_MSG(" rxRSSI=%g", p->rx_rssi); } if (p->priority != 0) DEBUG_MSG(" priority=%d", p->priority); diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index c0007ade..c665ea35 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -93,278 +93,297 @@ bool RadioLibInterface::canSendImmediately() /// bluetooth comms code. If the txmit queue is empty it might return an error ErrorCode RadioLibInterface::send(MeshPacket *p) { + +#ifndef DISABLE_WELCOME_UNSET + if (config.lora.region != Config_LoRaConfig_RegionCode_Unset) { 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"); + if (config.lora.region != Config_LoRaConfig_RegionCode_Unset) { + 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); 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 - printPacket("enqueuing for send", p); + printPacket("enqueuing for send", p); - DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad); - ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN; + DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad); + 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; - } - - // 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 packetPool.release(p); return ERRNO_DISABLED; #endif -} + } -bool RadioLibInterface::canSleep() -{ - bool res = txQueue.empty(); - if (!res) // only print debug messages if we are vetoing sleep - DEBUG_MSG("radio wait to sleep, txEmpty=%d\n", res); + bool RadioLibInterface::canSleep() + { + bool res = txQueue.empty(); + if (!res) // only print debug messages if we are vetoing sleep + 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 */ -bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) -{ - auto p = txQueue.remove(from, id); - if (p) - packetPool.release(p); // free the packet we just removed + /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ + bool RadioLibInterface::cancelSending(NodeNum from, PacketId id) + { + auto p = txQueue.remove(from, id); + if (p) + packetPool.release(p); // free the packet we just removed - bool result = (p != NULL); - DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, result); - return result; -} + bool result = (p != NULL); + DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, 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 -wait a random delay of 100ms to 100ms+shortPacketMsec to make sure we are not stomping on someone else. The 100ms delay at the -beginning ensures all possible listeners have had time to finish processing the previous packet and now have their radio in RX -state. The up to 100ms+shortPacketMsec random delay gives a chance for all possible senders to have high odds of detecting that -someone else started transmitting first and then they will wait until that packet finishes. + 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 beginning ensures all possible listeners have had time to finish processing the previous packet and now have their + radio in RX state. The up to 100ms+shortPacketMsec random delay gives a chance for all possible senders to have high odds + 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 -transmitters that we are potentially stomping on. Requires further thought. + NOTE: the large flood rebroadcast delay might still be needed even with this approach. Because we might not be able to + 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. -*/ -void RadioLibInterface::onNotify(uint32_t notification) -{ - switch (notification) { - case ISR_TX: - handleTransmitInterrupt(); - startReceive(); - // DEBUG_MSG("tx complete - starting timer\n"); - startTransmitTimer(); - break; - case ISR_RX: - handleReceiveInterrupt(); - startReceive(); - // DEBUG_MSG("rx complete - starting timer\n"); - startTransmitTimer(); - break; - case TRANSMIT_DELAY_COMPLETED: - // DEBUG_MSG("delay done\n"); + 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) + { + switch (notification) { + case ISR_TX: + handleTransmitInterrupt(); + startReceive(); + // DEBUG_MSG("tx complete - starting timer\n"); + startTransmitTimer(); + break; + case ISR_RX: + handleReceiveInterrupt(); + startReceive(); + // DEBUG_MSG("rx complete - starting timer\n"); + startTransmitTimer(); + break; + case TRANSMIT_DELAY_COMPLETED: + // 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 - // has placed the unit into standby) FIXME, how will this work if the chipset is in sleep mode? - if (!txQueue.empty()) { - if (!canSendImmediately()) { - // DEBUG_MSG("Currently Rx/Tx-ing: set random delay\n"); - 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 + // 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? + if (!txQueue.empty()) { + if (!canSendImmediately()) { + // DEBUG_MSG("Currently Rx/Tx-ing: set random delay\n"); + setTransmitDelay(); // currently Rx/Tx-ing: reset random delay } else { - // Send any outgoing packets we have ready - MeshPacket *txp = txQueue.dequeue(); - assert(txp); - startSend(txp); + 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 { + // 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. - uint32_t xmitMsec = getPacketTime(txp); - airTime->logAirtime(TX_LOG, xmitMsec); + // Packet has been sent, count it toward our TX airtime utilization. + uint32_t xmitMsec = getPacketTime(txp); + airTime->logAirtime(TX_LOG, xmitMsec); + } } + } else { + // DEBUG_MSG("done with txqueue\n"); } - } else { - // DEBUG_MSG("done with txqueue\n"); - } - 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); + break; + default: + assert(0); // We expected to receive a valid notification from the ISR } } -} -/** 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 + 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. - 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); - if (res != ERR_NONE) { - RECORD_CRITICALERROR(CriticalErrorCode_RadioSpiBug); + 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 + } + } - // 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(); - 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); + } + } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 87e319d8..d7dd7afc 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -274,6 +274,9 @@ void Router::sniffReceived(const MeshPacket *p, const Routing *c) bool perhapsDecode(MeshPacket *p) { + + // DEBUG_MSG("\n\n** perhapsDecode payloadVariant - %d\n\n", p->which_payloadVariant); + if (p->which_payloadVariant == MeshPacket_decoded_tag) 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->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 - if (p->decoded.which_payloadVariant == Data_payload_compressed_tag) { - // Decompress the file + if (p->decoded.portnum == PortNum_TEXT_MESSAGE_COMPRESSED_APP) { + // 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); @@ -339,41 +364,28 @@ Routing_Error perhapsEncode(MeshPacket *p) char compressed_out[Constants_DATA_PAYLOAD_LEN] = {0}; 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 - "); - Serial.println(p->decoded.payload.size); - - Serial.print("Compressed length - "); - Serial.println(compressed_len); - // Serial.println(compressed_out); + DEBUG_MSG("Original length - %d \n", p->decoded.payload.size); + DEBUG_MSG("Compressed length - %d \n", compressed_len); + DEBUG_MSG("Original message - %s \n", p->decoded.payload.bytes); // 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) { - 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? - p->decoded.which_payloadVariant = Data_payload_tag; + // p->decoded.which_payloadVariant = Data_payload_tag; // Otherwise we use the compressor } else { - DEBUG_MSG("Compressing message.\n"); + DEBUG_MSG("Using compressed message.\n"); // 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) { - 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); + p->decoded.portnum = PortNum_TEXT_MESSAGE_COMPRESSED_APP; } } diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index bc784d69..893760ab 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -464,7 +464,6 @@ typedef struct _User { } User; typedef PB_BYTES_ARRAY_T(237) Data_payload_t; -typedef PB_BYTES_ARRAY_T(237) Data_payload_compressed_t; /* (Formerly called SubPacket) The payload portion fo a packet, this is the actual bytes that are sent inside a radio packet (because from/to are broken out by the comms library) */ @@ -472,34 +471,30 @@ typedef struct _Data { /* Formerly named typ and of type Type */ PortNum portnum; /* TODO: REPLACE */ - pb_size_t which_payloadVariant; - union { - Data_payload_t payload; - Data_payload_compressed_t payload_compressed; - }; - /* TODO: REPLACE */ - bool want_response; + Data_payload_t payload; /* Not normally used, but for testing a sender can request that recipient responds in kind (i.e. if it received a position, it should unicast back it's position). Note: that if you set this on a broadcast you will receive many replies. */ - uint32_t dest; + bool want_response; /* The address of the destination node. This field is is filled in by the mesh radio device software, application layer software should never need it. RouteDiscovery messages _must_ populate this. Other message types might need to if they are doing multihop routing. */ - uint32_t source; + uint32_t dest; /* The address of the original sender for this message. This field should _only_ be populated for reliable multihop packets (to keep packets small). */ - uint32_t request_id; + uint32_t source; /* Only used in routing or response messages. Indicates the original message ID that this message is reporting failure on. (formerly called original_id) */ - uint32_t reply_id; + uint32_t request_id; /* If set, this message is intened to be a reply to a previously sent message with the defined id. */ - uint32_t emoji; + uint32_t reply_id; /* Defaults to false. If true, then what is in the payload should be treated as an emoji like giving a message a heart or poop emoji. */ + uint32_t emoji; + /* Location structure */ bool has_location; Location location; } Data; @@ -703,7 +698,7 @@ extern "C" { #define User_init_default {"", "", "", {0}, _HardwareModel_MIN, 0, 0, 0, 0} #define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define Routing_init_default {0, {RouteDiscovery_init_default}} -#define Data_init_default {_PortNum_MIN, 0, {{0, {0}}}, 0, 0, 0, 0, 0, 0, false, Location_init_default} +#define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, Location_init_default} #define Location_init_default {0, 0, 0, 0, 0} #define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0, false, DeviceMetrics_init_default} @@ -717,7 +712,7 @@ extern "C" { #define User_init_zero {"", "", "", {0}, _HardwareModel_MIN, 0, 0, 0, 0} #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define Routing_init_zero {0, {RouteDiscovery_init_zero}} -#define Data_init_zero {_PortNum_MIN, 0, {{0, {0}}}, 0, 0, 0, 0, 0, 0, false, Location_init_zero} +#define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, Location_init_zero} #define Location_init_zero {0, 0, 0, 0, 0} #define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0, false, DeviceMetrics_init_zero} @@ -792,7 +787,6 @@ extern "C" { #define User_ant_azimuth_tag 12 #define Data_portnum_tag 1 #define Data_payload_tag 2 -#define Data_payload_compressed_tag 10 #define Data_want_response_tag 3 #define Data_dest_tag 4 #define Data_source_tag 5 @@ -890,15 +884,14 @@ X(a, STATIC, ONEOF, UENUM, (variant,error_reason,error_reason), 3) #define Data_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UENUM, portnum, 1) \ -X(a, STATIC, ONEOF, BYTES, (payloadVariant,payload,payload), 2) \ +X(a, STATIC, SINGULAR, BYTES, payload, 2) \ X(a, STATIC, SINGULAR, BOOL, want_response, 3) \ X(a, STATIC, SINGULAR, FIXED32, dest, 4) \ X(a, STATIC, SINGULAR, FIXED32, source, 5) \ X(a, STATIC, SINGULAR, FIXED32, request_id, 6) \ X(a, STATIC, SINGULAR, FIXED32, reply_id, 7) \ X(a, STATIC, SINGULAR, FIXED32, emoji, 8) \ -X(a, STATIC, OPTIONAL, MESSAGE, location, 9) \ -X(a, STATIC, ONEOF, BYTES, (payloadVariant,payload_compressed,payload_compressed), 10) +X(a, STATIC, OPTIONAL, MESSAGE, location, 9) #define Data_CALLBACK NULL #define Data_DEFAULT NULL #define Data_location_MSGTYPE Location diff --git a/src/mesh/generated/module_config.pb.h b/src/mesh/generated/module_config.pb.h index 9ec763e6..f68b1655 100644 --- a/src/mesh/generated/module_config.pb.h +++ b/src/mesh/generated/module_config.pb.h @@ -13,21 +13,21 @@ /* Enum definitions */ typedef enum _ModuleConfig_SerialConfig_Serial_Baud { ModuleConfig_SerialConfig_Serial_Baud_BAUD_Default = 0, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_2400 = 1, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_4800 = 2, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_9600 = 3, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_19200 = 4, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_38400 = 5, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_57600 = 6, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_115200 = 7, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_230400 = 8, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_460800 = 9, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_576000 = 10, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600 = 11, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_110 = 12, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_300 = 13, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_600 = 14, - ModuleConfig_SerialConfig_Serial_Baud_BAUD_1200 = 15 + ModuleConfig_SerialConfig_Serial_Baud_BAUD_110 = 1, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_300 = 2, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_600 = 3, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_1200 = 4, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_2400 = 5, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_4800 = 6, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_9600 = 7, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_19200 = 8, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_38400 = 9, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_57600 = 10, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_115200 = 11, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_230400 = 12, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_460800 = 13, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_576000 = 14, + ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600 = 15 } ModuleConfig_SerialConfig_Serial_Baud; typedef enum _ModuleConfig_SerialConfig_Serial_Mode { @@ -133,8 +133,8 @@ typedef struct _ModuleConfig { /* Helper constants for enums */ #define _ModuleConfig_SerialConfig_Serial_Baud_MIN ModuleConfig_SerialConfig_Serial_Baud_BAUD_Default -#define _ModuleConfig_SerialConfig_Serial_Baud_MAX ModuleConfig_SerialConfig_Serial_Baud_BAUD_1200 -#define _ModuleConfig_SerialConfig_Serial_Baud_ARRAYSIZE ((ModuleConfig_SerialConfig_Serial_Baud)(ModuleConfig_SerialConfig_Serial_Baud_BAUD_1200+1)) +#define _ModuleConfig_SerialConfig_Serial_Baud_MAX ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600 +#define _ModuleConfig_SerialConfig_Serial_Baud_ARRAYSIZE ((ModuleConfig_SerialConfig_Serial_Baud)(ModuleConfig_SerialConfig_Serial_Baud_BAUD_921600+1)) #define _ModuleConfig_SerialConfig_Serial_Mode_MIN ModuleConfig_SerialConfig_Serial_Mode_MODE_Default #define _ModuleConfig_SerialConfig_Serial_Mode_MAX ModuleConfig_SerialConfig_Serial_Mode_MODE_PROTO diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index f824ce76..b4fd3738 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -46,6 +46,8 @@ typedef enum _PortNum { /* Admin control packets. Payload is a [AdminMessage](/docs/developers/protobufs/api#adminmessage) message */ PortNum_ADMIN_APP = 6, + /* Compressed TEXT_MESSAGE payloads. */ + PortNum_TEXT_MESSAGE_COMPRESSED_APP = 7, /* Provides a 'ping' service that replies to any packet it receives. Also serves as a small example module. */ PortNum_REPLY_APP = 32, @@ -69,8 +71,6 @@ typedef enum _PortNum { Maintained by Github user a-f-G-U-C (a Meshtastic contributor) Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS */ PortNum_ZPS_APP = 68, - /* Compressed payloads. */ - PortNum_COMPRESSION_APP = 69, /* Private applications should use portnums >= 256. To simplify initial development and testing you can use "PRIVATE_APP" in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/Meshtastic-device/blob/master/bin/regen-protos.sh)) */ diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index decce029..9f6f55fe 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -176,26 +176,32 @@ void AdminModule::handleSetConfig(const Config &c) switch (c.which_payloadVariant) { case Config_device_tag: DEBUG_MSG("Setting config: Device\n"); + config.has_device = true; config.device = c.payloadVariant.device; break; case Config_position_tag: DEBUG_MSG("Setting config: Position\n"); + config.has_position = true; config.position = c.payloadVariant.position; break; case Config_power_tag: DEBUG_MSG("Setting config: Power\n"); + config.has_power = true; config.power = c.payloadVariant.power; break; case Config_wifi_tag: DEBUG_MSG("Setting config: WiFi\n"); + config.has_wifi = true; config.wifi = c.payloadVariant.wifi; break; case Config_display_tag: DEBUG_MSG("Setting config: Display\n"); + config.has_display = true; config.display = c.payloadVariant.display; break; case Config_lora_tag: DEBUG_MSG("Setting config: LoRa\n"); + config.has_lora = true; config.lora = c.payloadVariant.lora; break; } @@ -208,30 +214,37 @@ void AdminModule::handleSetModuleConfig(const ModuleConfig &c) switch (c.which_payloadVariant) { case ModuleConfig_mqtt_tag: DEBUG_MSG("Setting module config: MQTT\n"); + moduleConfig.has_mqtt = true; moduleConfig.mqtt = c.payloadVariant.mqtt; break; case ModuleConfig_serial_tag: DEBUG_MSG("Setting module config: Serial\n"); + moduleConfig.has_serial = true; moduleConfig.serial = c.payloadVariant.serial; break; case ModuleConfig_external_notification_tag: DEBUG_MSG("Setting module config: External Notification\n"); + moduleConfig.has_external_notification = true; moduleConfig.external_notification = c.payloadVariant.external_notification; break; case ModuleConfig_store_forward_tag: DEBUG_MSG("Setting module config: Store & Forward\n"); + moduleConfig.has_store_forward = true; moduleConfig.store_forward = c.payloadVariant.store_forward; break; case ModuleConfig_range_test_tag: DEBUG_MSG("Setting module config: Range Test\n"); + moduleConfig.has_range_test = true; moduleConfig.range_test = c.payloadVariant.range_test; break; case ModuleConfig_telemetry_tag: DEBUG_MSG("Setting module config: Telemetry\n"); + moduleConfig.has_telemetry = true; moduleConfig.telemetry = c.payloadVariant.telemetry; break; case ModuleConfig_canned_message_tag: DEBUG_MSG("Setting module config: Canned Message\n"); + moduleConfig.has_canned_message = true; moduleConfig.canned_message = c.payloadVariant.canned_message; break; } diff --git a/src/modules/esp32/RangeTestModule.cpp b/src/modules/esp32/RangeTestModule.cpp index 71b1bbb5..1a871e81 100644 --- a/src/modules/esp32/RangeTestModule.cpp +++ b/src/modules/esp32/RangeTestModule.cpp @@ -36,8 +36,8 @@ int32_t RangeTestModule::runOnce() without having to configure it from the PythonAPI or WebUI. */ - // moduleConfig.range_test.enabled = 1; - // moduleConfig.range_test.sender = 45; + //moduleConfig.range_test.enabled = 1; + //moduleConfig.range_test.sender = 30; // moduleConfig.range_test.save = 1; // Fixed position is useful when testing indoors. @@ -115,7 +115,7 @@ void RangeTestModuleRadio::sendPayload(NodeNum dest, bool wantReplies) packetSequence++; - static char heartbeatString[20]; + static char heartbeatString[MAX_RHPACKETLEN]; snprintf(heartbeatString, sizeof(heartbeatString), "seq %u", packetSequence); p->decoded.payload.size = strlen(heartbeatString); // You must specify how many bytes are in the reply