diff --git a/proto b/proto index b1aed0644..0cadaed39 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit b1aed06442025624841b2288fac273d9bc41c438 +Subproject commit 0cadaed3953f66cf1edc99d0fa53e4fd5ebf56d6 diff --git a/src/commands.h b/src/commands.h index c9d519dee..803ea2b55 100644 --- a/src/commands.h +++ b/src/commands.h @@ -9,6 +9,7 @@ enum class Cmd { SET_OFF, ON_PRESS, START_BLUETOOTH_PIN_SCREEN, + START_FIRMWARE_UPDATE_SCREEN, STOP_BLUETOOTH_PIN_SCREEN, STOP_BOOT_SCREEN, PRINT, diff --git a/src/esp32/BluetoothSoftwareUpdate.cpp b/src/esp32/BluetoothSoftwareUpdate.cpp index 03e156b0b..33707c57a 100644 --- a/src/esp32/BluetoothSoftwareUpdate.cpp +++ b/src/esp32/BluetoothSoftwareUpdate.cpp @@ -7,6 +7,8 @@ #include "configuration.h" #include "nimble/BluetoothUtil.h" #include "NodeDB.h" +#include "../graphics/Screen.h" +#include "../main.h" #include #include @@ -47,8 +49,9 @@ int update_size_callback(uint16_t conn_handle, uint16_t attr_handle, struct ble_ // void stopMeshBluetoothService(); // stopMeshBluetoothService(); + screen->startFirmwareUpdateScreen(); if (RadioLibInterface::instance) - RadioLibInterface::instance->sleep(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are + RadioLibInterface::instance->disable(); // FIXME, nasty hack - the RF95 ISR/SPI code on ESP32 can fail while we are // writing flash - shut the radio off during updates } } diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 853cdc29c..40ea25237 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -164,6 +164,20 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state, display->drawString(64 + x, 48 + y, buf); } +static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +{ + display->setTextAlignment(TEXT_ALIGN_CENTER); + display->setFont(FONT_MEDIUM); + display->drawString(64 + x, y, "Updating"); + + display->setFont(FONT_SMALL); + display->drawString(64 + x, FONT_HEIGHT_SMALL + y + 2, "Please wait..."); + + //display->setFont(FONT_LARGE); + //display->drawString(64 + x, 26 + y, btPIN); +} + + /// Draw the last text message we received static void drawCriticalFaultFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { @@ -798,6 +812,9 @@ int32_t Screen::runOnce() case Cmd::START_BLUETOOTH_PIN_SCREEN: handleStartBluetoothPinScreen(cmd.bluetooth_pin); break; + case Cmd::START_FIRMWARE_UPDATE_SCREEN: + handleStartFirmwareUpdateScreen(); + break; case Cmd::STOP_BLUETOOTH_PIN_SCREEN: case Cmd::STOP_BOOT_SCREEN: setFrames(); @@ -928,6 +945,18 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin) setFastFramerate(); } +void Screen::handleStartFirmwareUpdateScreen() +{ + DEBUG_MSG("showing firmware screen\n"); + showingNormalScreen = false; + + static FrameCallback btFrames[] = {drawFrameFirmware}; + + ui.disableAllIndicators(); + ui.setFrames(btFrames, 1); + setFastFramerate(); +} + void Screen::blink() { setFastFramerate(); diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 888f31011..041da4865 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -128,6 +128,14 @@ class Screen : public concurrency::OSThread enqueueCmd(cmd); } + void startFirmwareUpdateScreen() + { + ScreenCmd cmd; + cmd.cmd = Cmd::START_FIRMWARE_UPDATE_SCREEN; + enqueueCmd(cmd); + } + + /// Stops showing the bluetooth PIN screen. void stopBluetoothPinScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BLUETOOTH_PIN_SCREEN}); } @@ -233,6 +241,7 @@ class Screen : public concurrency::OSThread void handleOnPress(); void handleStartBluetoothPinScreen(uint32_t pin); void handlePrint(const char *text); + void handleStartFirmwareUpdateScreen(); /// Rebuilds our list of frames (screens) to default ones. void setFrames(); diff --git a/src/mesh/MeshTypes.h b/src/mesh/MeshTypes.h index 8fd098f43..69e782b12 100644 --- a/src/mesh/MeshTypes.h +++ b/src/mesh/MeshTypes.h @@ -13,6 +13,7 @@ typedef uint32_t PacketId; // A packet sequence number #define ERRNO_OK 0 #define ERRNO_NO_INTERFACES 33 #define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER +#define ERRNO_DISABLED 34 // the itnerface is disabled /** * the max number of hops a message can pass through, used as the default max for hop_limit in MeshPacket. diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index c49421d11..e1e23ba29 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -54,6 +54,8 @@ class RadioInterface uint32_t shortPacketMsec; protected: + bool disabled = false; + float bw = 125; uint8_t sf = 9; uint8_t cr = 7; @@ -98,6 +100,9 @@ class RadioInterface /// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep. virtual bool sleep() { return true; } + /// Disable this interface (while disabled, no packets can be sent or received) + void disable() { disabled = true; sleep(); } + /** * 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. diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 84fd37ee6..63d7095c5 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -2,8 +2,8 @@ #include "MeshTypes.h" #include "NodeDB.h" #include "SPILock.h" -#include "mesh-pb-constants.h" #include "error.h" +#include "mesh-pb-constants.h" #include #include #include @@ -68,13 +68,12 @@ bool RadioLibInterface::canSendImmediately() bool busyTx = sendingPacket != NULL; bool busyRx = isReceiving && isActivelyReceiving(); - if (busyTx || busyRx) { if (busyTx) DEBUG_MSG("Can not send yet, busyTx\n"); // If we've been trying to send the same packet more than one minute and we haven't gotten a // TX IRQ from the radio, the radio is probably broken. - if (busyTx && (millis() - lastTxStart > 60000)){ + if (busyTx && (millis() - lastTxStart > 60000)) { DEBUG_MSG("Hardware Failure! busyTx for more than 60s\n"); recordCriticalError(CriticalErrorCode_TransmitFailed); #ifndef NO_ESP32 @@ -94,6 +93,11 @@ bool RadioLibInterface::canSendImmediately() /// bluetooth comms code. If the txmit queue is empty it might return an error ErrorCode RadioLibInterface::send(MeshPacket *p) { + if (disabled) { + packetPool.release(p); + return ERRNO_DISABLED; + } + // Sometimes when testing it is useful to be able to never turn on the xmitter #ifndef LORA_DISABLE_SENDING printPacket("enqueuing for send", p); @@ -110,7 +114,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) // Count the packet toward our TX airtime utilization. // We only count it if it can be added to the TX queue. airTime->logAirtime(TX_LOG, xmitMsec); - //airTime.logAirtime(TX_LOG, xmitMsec); + // airTime.logAirtime(TX_LOG, xmitMsec); // 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 @@ -119,7 +123,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) return res; #else packetPool.release(p); - return ERRNO_UNKNOWN; + return ERRNO_DISABLED; #endif } @@ -133,17 +137,17 @@ bool RadioLibInterface::canSleep() } /** 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); - if(p) + if (p) packetPool.release(p); // free the packet we just removed bool result = (p != NULL); - DEBUG_MSG("cancelSending id=0x%x, removed=%d", id, result); + DEBUG_MSG("cancelSending id=0x%x, removed=%d\n", id, result); return result; } - /** radio helper thread callback. We never immediately transmit after any operation (either rx or tx). Instead we should start receiving and @@ -242,7 +246,7 @@ void RadioLibInterface::handleReceiveInterrupt() xmitMsec = getPacketTime(length); airTime->logAirtime(RX_ALL_LOG, xmitMsec); - //airTime.logAirtime(RX_ALL_LOG, xmitMsec); + // airTime.logAirtime(RX_ALL_LOG, xmitMsec); int state = iface->readData(radiobuf, length); if (state != ERR_NONE) { @@ -277,7 +281,7 @@ void RadioLibInterface::handleReceiveInterrupt() 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)); + assert(((uint32_t)payloadLen) <= sizeof(mp->encrypted.bytes)); memcpy(mp->encrypted.bytes, payload, payloadLen); mp->encrypted.size = payloadLen; @@ -285,7 +289,7 @@ void RadioLibInterface::handleReceiveInterrupt() xmitMsec = getPacketTime(mp); airTime->logAirtime(RX_LOG, xmitMsec); - //airTime.logAirtime(RX_LOG, xmitMsec); + // airTime.logAirtime(RX_LOG, xmitMsec); deliverToReceiver(mp); } @@ -295,16 +299,21 @@ void RadioLibInterface::handleReceiveInterrupt() /** start an immediate transmit */ void RadioLibInterface::startSend(MeshPacket *txp) { - printPacket("Starting low level send", txp); - setStandby(); // Cancel any already in process receives + printPacket("Starting low level send", txp); + if (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 + configHardwareForSend(); // must be after setStandby - size_t numbytes = beginSending(txp); + size_t numbytes = beginSending(txp); - int res = iface->startTransmit(radiobuf, numbytes); - assert(res == ERR_NONE); + int res = iface->startTransmit(radiobuf, numbytes); + assert(res == ERR_NONE); - // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits - enableInterrupt(isrTxLevel0); + // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register bits + enableInterrupt(isrTxLevel0); + } }