diff options
author | David Crocker <dcrocker@eschertech.com> | 2022-07-20 16:57:02 +0300 |
---|---|---|
committer | David Crocker <dcrocker@eschertech.com> | 2022-07-20 16:57:02 +0300 |
commit | 5501f6d9885d73c96c180f98721d9524bd96290c (patch) | |
tree | 1a4dc530748814c73e8cf3d589da25fd4459dfac | |
parent | ec894c2d7a27b61348928b9cbfa64c8aa98b34ac (diff) |
Implemented remote reset and remote firmware update (needs CAN IAP)
-rw-r--r-- | src/CAN/CommandProcessor.cpp | 43 | ||||
-rw-r--r-- | src/Config/Pins_Duet3Mini.h | 1 | ||||
-rw-r--r-- | src/Config/Pins_Duet3_MB6HC.h | 1 | ||||
-rw-r--r-- | src/Config/Pins_Duet3_MB6XD.h | 1 | ||||
-rw-r--r-- | src/GCodes/GCodes4.cpp | 4 | ||||
-rw-r--r-- | src/Platform/RepRap.cpp | 82 | ||||
-rw-r--r-- | src/Platform/RepRap.h | 15 |
7 files changed, 119 insertions, 28 deletions
diff --git a/src/CAN/CommandProcessor.cpp b/src/CAN/CommandProcessor.cpp index f7c5ed0a..9b5b61b5 100644 --- a/src/CAN/CommandProcessor.cpp +++ b/src/CAN/CommandProcessor.cpp @@ -382,7 +382,30 @@ static GCodeResult EutGetInfo(const CanMessageReturnInfo& msg, const StringRef& return GCodeResult::ok; } -#endif +static GCodeResult InitiateFirmwareUpdate(const CanMessageUpdateYourFirmware& msg, const StringRef& reply) +{ + if (msg.boardId != CanInterface::GetCanAddress() || msg.invertedBoardId != (uint8_t)~CanInterface::GetCanAddress() || (msg.module != 0 && msg.module != 3)) + { + reply.printf("Invalid firmware update command received"); + return GCodeResult::error; + } + + if (msg.module == 0) + { + if (!reprap.GetPlatform().FileExists(FIRMWARE_DIRECTORY, IAP_CAN_LOADER_FILE)) + { + reply.printf("In-application programming binary \"%s\" not found on board %u", FIRMWARE_DIRECTORY IAP_CAN_LOADER_FILE, CanInterface::GetCanAddress()); + return GCodeResult::error; + } + reply.printf("Board %u starting firmware update", CanInterface::GetCanAddress()); + reprap.ScheduleFirmwareUpdateOverCan(); + return GCodeResult::ok; + } + reply.copy("unknown firmware module number"); + return GCodeResult::error; +} + +#endif // SUPPORT_REMOTE_COMMANDS // Process a received broadcast or request message. Don't free the message buffer void CommandProcessor::ProcessReceivedMessage(CanMessageBuffer *buf) noexcept @@ -410,6 +433,11 @@ void CommandProcessor::ProcessReceivedMessage(CanMessageBuffer *buf) noexcept StepTimer::ProcessTimeSyncMessage(buf->msg.sync, buf->dataLength, buf->timeStamp); return; // no reply needed + case CanMessageType::emergencyStop: + reprap.EmergencyStop(); + reprap.ScheduleReset(); + return; // no reply needed + case CanMessageType::movementLinear: reprap.GetMove().AddMoveFromRemote(buf->msg.moveLinear); return; // no reply needed @@ -432,6 +460,19 @@ void CommandProcessor::ProcessReceivedMessage(CanMessageBuffer *buf) noexcept CanInterface::MainBoardAcknowledgedAnnounce(); return; + case CanMessageType::updateFirmware: + requestId = buf->msg.updateYourFirmware.requestId; + rslt = InitiateFirmwareUpdate(buf->msg.updateYourFirmware, replyRef); + break; + + case CanMessageType::reset: + requestId = buf->msg.reset.requestId; + reply.printf("Board %u resetting", CanInterface::GetCanAddress()); + reprap.EmergencyStop(); + reprap.ScheduleReset(); + rslt = GCodeResult::ok; + break; + case CanMessageType::returnInfo: requestId = buf->msg.getInfo.requestId; rslt = EutGetInfo(buf->msg.getInfo, replyRef, extra); diff --git a/src/Config/Pins_Duet3Mini.h b/src/Config/Pins_Duet3Mini.h index 188c7f79..42612f96 100644 --- a/src/Config/Pins_Duet3Mini.h +++ b/src/Config/Pins_Duet3Mini.h @@ -23,6 +23,7 @@ #define IAP_FIRMWARE_FILE "Duet3Firmware_" BOARD_SHORT_NAME ".uf2" #define IAP_UPDATE_FILE "Duet3_SDiap32_" BOARD_SHORT_NAME ".bin" #define IAP_UPDATE_FILE_SBC "Duet3_SBCiap32_" BOARD_SHORT_NAME ".bin" +#define IAP_CAN_LOADER_FILE "Duet3_CANiap32" BOARD_SHORT_NAME ".bin" constexpr uint32_t IAP_IMAGE_START = 0x20038000; #define WIFI_FIRMWARE_FILE "DuetWiFiServer.bin" diff --git a/src/Config/Pins_Duet3_MB6HC.h b/src/Config/Pins_Duet3_MB6HC.h index 5574ff1e..6d7ea386 100644 --- a/src/Config/Pins_Duet3_MB6HC.h +++ b/src/Config/Pins_Duet3_MB6HC.h @@ -11,6 +11,7 @@ #define IAP_UPDATE_FILE "Duet3_SDiap32_" BOARD_SHORT_NAME ".bin" #define IAP_UPDATE_FILE_SBC "Duet3_SBCiap32_" BOARD_SHORT_NAME ".bin" +#define IAP_CAN_LOADER_FILE "Duet3_CANiap32" BOARD_SHORT_NAME ".bin" constexpr uint32_t IAP_IMAGE_START = 0x20458000; // last 32kb of RAM // Features definition diff --git a/src/Config/Pins_Duet3_MB6XD.h b/src/Config/Pins_Duet3_MB6XD.h index 514cb4ed..c1df8adf 100644 --- a/src/Config/Pins_Duet3_MB6XD.h +++ b/src/Config/Pins_Duet3_MB6XD.h @@ -11,6 +11,7 @@ #define IAP_UPDATE_FILE "Duet3_SDiap32_" BOARD_SHORT_NAME ".bin" #define IAP_UPDATE_FILE_SBC "Duet3_SBCiap32_" BOARD_SHORT_NAME ".bin" +#define IAP_CAN_LOADER_FILE "Duet3_CANiap32" BOARD_SHORT_NAME ".bin" constexpr uint32_t IAP_IMAGE_START = 0x20458000; // last 32kb of RAM // Features definition diff --git a/src/GCodes/GCodes4.cpp b/src/GCodes/GCodes4.cpp index 48256718..5c0a6cf5 100644 --- a/src/GCodes/GCodes4.cpp +++ b/src/GCodes/GCodes4.cpp @@ -591,12 +591,12 @@ void GCodes::RunStateMachine(GCodeBuffer& gb, const StringRef& reply) noexcept { // Update main firmware firmwareUpdateModuleMap.Clear(); - String<MaxFilenameLength> filenameString; try { + String<MaxFilenameLength> filenameString; bool dummy; gb.TryGetQuotedString('P', filenameString.GetRef(), dummy); - reprap.UpdateFirmware(filenameString.GetRef()); + reprap.UpdateFirmware(IAP_UPDATE_FILE, filenameString.c_str()); // The above call does not return unless an error occurred } catch (const GCodeException&) { } diff --git a/src/Platform/RepRap.cpp b/src/Platform/RepRap.cpp index ae951908..43dafec1 100644 --- a/src/Platform/RepRap.cpp +++ b/src/Platform/RepRap.cpp @@ -792,8 +792,30 @@ void RepRap::Spin() noexcept diagnosticsDestination = MessageType::NoDestinationMessage; } - // Check if we need to display a cold extrusion warning const uint32_t now = millis(); + +#if SUPPORT_REMOTE_COMMANDS + const DeferredCommand defCom = deferredCommand; // capture volatile variable + if (defCom != DeferredCommand::none && now - whenDeferredCommandScheduled >= 250) + { + switch (defCom) + { + case DeferredCommand::reboot: + SoftwareReset(SoftwareResetReason::user); + break; + + case DeferredCommand::updateFirmware: + UpdateFirmware(IAP_CAN_LOADER_FILE, ""); + break; + + default: + deferredCommand = DeferredCommand::none; + break; + } + } +#endif + + // Check if we need to display a cold extrusion warning if (now - lastWarningMillis >= MinimumWarningInterval) { ReadLocker lock(toolListLock); @@ -958,44 +980,58 @@ void RepRap::Diagnostics(MessageType mtype) noexcept justSentDiagnostics = true; } -// Turn off the heaters, disable the motors, and deactivate the Heat and Move classes. Leave everything else working. +// Turn off the heaters, disable the motors, and deactivate the Heat, Move and GCodes classes. Leave everything else working. void RepRap::EmergencyStop() noexcept { #ifdef DUET3_ATE Duet3Ate::PowerOffEUT(); #endif - stopped = true; // a useful side effect of setting this is that it prevents Platform::Tick being called, which is needed when loading IAP into RAM + stopped = true; // a useful side effect of setting this is that it prevents Platform::Tick being called, which is needed when loading IAP into RAM // Do not turn off ATX power here. If the nozzles are still hot, don't risk melting any surrounding parts by turning fans off. //platform->SetAtxPower(false); - platform->DisableAllDrivers(); // need to do this to ensure that any motor brakes are re-engaged - - switch (gCodes->GetMachineType()) +#if SUPPORT_REMOTE_COMMANDS + if (CanInterface::InExpansionMode()) { - case MachineType::cnc: - for (size_t i = 0; i < MaxSpindles; i++) + platform->EmergencyDisableDrivers(); // disable all local drivers - need to do this to ensure that any motor brakes are re-engaged + } + else +#endif + { + platform->DisableAllDrivers(); // disable all local and remote drivers - need to do this to ensure that any motor brakes are re-engaged + + switch (gCodes->GetMachineType()) { - platform->AccessSpindle(i).SetState(SpindleState::stopped); - } - break; + case MachineType::cnc: + for (size_t i = 0; i < MaxSpindles; i++) + { + platform->AccessSpindle(i).SetState(SpindleState::stopped); + } + break; #if SUPPORT_LASER - case MachineType::laser: - platform->SetLaserPwm(0); - break; + case MachineType::laser: + platform->SetLaserPwm(0); + break; #endif - default: - break; + default: + break; + } } - heat->Exit(); // this also turns off all heaters - move->Exit(); // this stops the motors stepping + heat->Exit(); // this also turns off all heaters + move->Exit(); // this stops the motors stepping #if SUPPORT_CAN_EXPANSION - expansion->EmergencyStop(); +# if SUPPORT_REMOTE_COMMANDS + if (!CanInterface::InExpansionMode()) +# endif + { + expansion->EmergencyStop(); + } #endif gCodes->EmergencyStop(); @@ -2916,13 +2952,13 @@ bool RepRap::CheckFirmwareUpdatePrerequisites(const StringRef& reply, const Stri } // Update the firmware. Prerequisites should be checked before calling this. -void RepRap::UpdateFirmware(const StringRef& filenameRef) noexcept +void RepRap::UpdateFirmware(const char *iapFilename, const char *iapParam) noexcept { #if HAS_MASS_STORAGE - FileStore * iapFile = platform->OpenFile(FIRMWARE_DIRECTORY, IAP_UPDATE_FILE, OpenMode::read); + FileStore * iapFile = platform->OpenFile(FIRMWARE_DIRECTORY, iapFilename, OpenMode::read); if (iapFile == nullptr) { - iapFile = platform->OpenFile(DEFAULT_SYS_DIR, IAP_UPDATE_FILE, OpenMode::read); + iapFile = platform->OpenFile(DEFAULT_SYS_DIR, iapFilename, OpenMode::read); if (iapFile == nullptr) { // This should not happen because we already checked that the file exists, so use a simplified error message @@ -2936,7 +2972,7 @@ void RepRap::UpdateFirmware(const StringRef& filenameRef) noexcept // Use RAM-based IAP iapFile->Read(reinterpret_cast<char *>(IAP_IMAGE_START), iapFile->Length()); iapFile->Close(); - StartIap(filenameRef.c_str()); + StartIap(iapParam); #endif } diff --git a/src/Platform/RepRap.h b/src/Platform/RepRap.h index b380bb51..49c6dfd6 100644 --- a/src/Platform/RepRap.h +++ b/src/Platform/RepRap.h @@ -61,7 +61,7 @@ public: RepRap(const RepRap&) = delete; void EmergencyStop() noexcept; - void Init() noexcept; + void Init() noexcept; void Spin() noexcept; void Exit() noexcept; void Diagnostics(MessageType mtype) noexcept; @@ -134,6 +134,11 @@ public: ExpansionManager& GetExpansion() const noexcept { return *expansion; } #endif +#if SUPPORT_REMOTE_COMMANDS + void ScheduleReset() noexcept { whenDeferredCommandScheduled = millis(); deferredCommand = DeferredCommand::reboot; } + void ScheduleFirmwareUpdateOverCan() noexcept { whenDeferredCommandScheduled = millis(); deferredCommand = DeferredCommand::updateFirmware; } +#endif + void Tick() noexcept; bool SpinTimeoutImminent() const noexcept; bool IsStopped() const noexcept; @@ -171,7 +176,7 @@ public: // Firmware update operations bool CheckFirmwareUpdatePrerequisites(const StringRef& reply, const StringRef& filenameRef) noexcept; - void UpdateFirmware(const StringRef& filenameRef) noexcept; + void UpdateFirmware(const char *iapFilename, const char *iapParam) noexcept; void PrepareToLoadIap() noexcept; [[noreturn]] void StartIap(const char *filename) noexcept; @@ -280,6 +285,12 @@ private: uint16_t heatTaskIdleTicks; uint32_t fastLoop, slowLoop; +#if SUPPORT_REMOTE_COMMANDS + enum class DeferredCommand : uint8_t { none, reboot, updateFirmware }; + volatile uint32_t whenDeferredCommandScheduled; + volatile DeferredCommand deferredCommand; +#endif + DebugFlags debugMaps[Module::numModules]; String<RepRapPasswordLength> password; |