From 013ce588a5f5c9d523ee9400110e62dfcad406b8 Mon Sep 17 00:00:00 2001 From: "D.R.racer" Date: Mon, 10 Oct 2022 12:35:31 +0200 Subject: [PATCH] Support reading/polling multiple registers In Idle and Command mode it is now possible to specify a list of registers which shall be periodically read from the MMU. To keep the code and RAM size down registers are intentionally separated into 8bit and 16bit sets. Adding a register into the set is just a matter of parametrization, there is no need to change the state machines anymore. --- Firmware/mmu2_protocol_logic.cpp | 80 +++++++++++++++++++++++--------- Firmware/mmu2_protocol_logic.h | 33 +++++++++---- 2 files changed, 82 insertions(+), 31 deletions(-) diff --git a/Firmware/mmu2_protocol_logic.cpp b/Firmware/mmu2_protocol_logic.cpp index ce1cecebc..8b716085d 100644 --- a/Firmware/mmu2_protocol_logic.cpp +++ b/Firmware/mmu2_protocol_logic.cpp @@ -8,6 +8,17 @@ namespace MMU2 { static const uint8_t supportedMmuFWVersion[3] PROGMEM = { 2, 1, 3 }; +const uint8_t ProtocolLogic::regs8Addrs[ProtocolLogic::regs8Count] PROGMEM = { + 8, // FINDA state + 0x1b, // Selector slot + 0x1c, // Idler slot +}; + +const uint8_t ProtocolLogic::regs16Addrs[ProtocolLogic::regs16Count] PROGMEM = { + 4, // MMU errors - aka statistics + 0x1a, // Pulley position [mm] +}; + void ProtocolLogic::CheckAndReportAsyncEvents() { // even when waiting for a query period, we need to report a change in filament sensor's state // - it is vital for a precise synchronization of moves of the printer and the MMU @@ -22,9 +33,36 @@ void ProtocolLogic::SendQuery() { scopeState = ScopeState::QuerySent; } -void ProtocolLogic::SendFINDAQuery() { - SendMsg(RequestMsg(RequestMsgCodes::Finda, 0)); - scopeState = ScopeState::FINDAReqSent; +void ProtocolLogic::StartReading8bitRegisters() { + regIndex = 0; + SendReadRegister(pgm_read_byte(regs8Addrs + regIndex), ScopeState::Reading8bitRegisters); +} + +void ProtocolLogic::ProcessRead8bitRegister(){ + regs8[regIndex] = rsp.paramValue; + ++regIndex; + if(regIndex >= regs8Count){ + // proceed with reading 16bit registers + StartReading16bitRegisters(); + } else { + SendReadRegister(pgm_read_byte(regs8Addrs + regIndex), ScopeState::Reading8bitRegisters); + } +} + +void ProtocolLogic::StartReading16bitRegisters() { + regIndex = 0; + SendReadRegister(pgm_read_byte(regs16Addrs + regIndex), ScopeState::Reading16bitRegisters); +} + +ProtocolLogic::ScopeState __attribute__((noinline)) ProtocolLogic::ProcessRead16bitRegister(ProtocolLogic::ScopeState stateAtEnd){ + regs16[regIndex] = rsp.paramValue; + ++regIndex; + if(regIndex >= regs16Count){ + return stateAtEnd; + } else { + SendReadRegister(pgm_read_byte(regs16Addrs + regIndex), ScopeState::Reading16bitRegisters); + } + return ScopeState::Reading16bitRegisters; } void ProtocolLogic::SendAndUpdateFilamentSensor() { @@ -313,14 +351,13 @@ StepStatus ProtocolLogic::CommandStep() { case ScopeState::QuerySent: return ProcessCommandQueryResponse(); case ScopeState::FilamentSensorStateSent: - SendFINDAQuery(); + StartReading8bitRegisters(); return Processing; - case ScopeState::FINDAReqSent: - findaPressed = rsp.paramValue; - SendReadRegister(4, ScopeState::StatisticsSent); + case ScopeState::Reading8bitRegisters: + ProcessRead8bitRegister(); return Processing; - case ScopeState::StatisticsSent: - scopeState = ScopeState::Wait; + case ScopeState::Reading16bitRegisters: + scopeState = ProcessRead16bitRegister(ScopeState::Wait); return Processing; case ScopeState::ButtonSent: if (rsp.paramCode == ResponseMsgParamCodes::Accepted) { @@ -371,7 +408,7 @@ StepStatus ProtocolLogic::IdleStep() { // The user pushed a button on the MMU. Save it, do what we need to do // to prepare, then pass it back to the MMU so it can work its magic. buttonCode = static_cast(rsp.paramValue); - SendFINDAQuery(); + StartReading8bitRegisters(); return ButtonPushed; case ResponseMsgParamCodes::Processing: // @@TODO we may actually use this branch to report progress of manual operation on the MMU @@ -382,29 +419,27 @@ StepStatus ProtocolLogic::IdleStep() { break; default: errorCode = static_cast(rsp.paramValue); - SendFINDAQuery(); // continue Idle state without restarting the communication + StartReading8bitRegisters(); // continue Idle state without restarting the communication return CommandError; } break; default: return ProtocolError; } - SendFINDAQuery(); + StartReading8bitRegisters(); return Processing; - case ScopeState::FINDAReqSent: - findaPressed = rsp.paramValue; - SendReadRegister(4, ScopeState::StatisticsSent); + case ScopeState::Reading8bitRegisters: + ProcessRead8bitRegister(); return Processing; - case ScopeState::StatisticsSent: - failStatistics = rsp.paramValue; - scopeState = ScopeState::Ready; - return Finished; + case ScopeState::Reading16bitRegisters: + scopeState = ProcessRead16bitRegister(ScopeState::Ready); + return scopeState == ScopeState::Ready ? Finished : Processing; case ScopeState::ButtonSent: if (rsp.paramCode == ResponseMsgParamCodes::Accepted) { // Button was accepted, decrement the retry. mmu2.DecrementRetryAttempts(); } - SendFINDAQuery(); + StartReading8bitRegisters(); return Processing; case ScopeState::ReadRegisterSent: if (rsp.paramCode == ResponseMsgParamCodes::Accepted) { @@ -444,8 +479,9 @@ ProtocolLogic::ProtocolLogic(MMU2Serial *uart) , progressCode(ProgressCode::OK) , buttonCode(NoButton) , lastFSensor((uint8_t)WhereIsFilament()) - , findaPressed(false) - , failStatistics(0) + , regs8 { 0, 0, 0 } + , regs16 { 0, 0 } + , regIndex(0) , mmuFwVersion { 0, 0, 0 } {} diff --git a/Firmware/mmu2_protocol_logic.h b/Firmware/mmu2_protocol_logic.h index ea1372406..7facfe280 100644 --- a/Firmware/mmu2_protocol_logic.h +++ b/Firmware/mmu2_protocol_logic.h @@ -1,5 +1,6 @@ #pragma once #include +#include // #include //@@TODO Don't we have STL for AVR somewhere? template class array { @@ -110,11 +111,11 @@ public: } inline bool FindaPressed() const { - return findaPressed; + return regs8[0]; } inline uint16_t FailStatistics() const { - return failStatistics; + return regs16[0]; } inline uint8_t MmuFwVersionMajor() const { @@ -187,10 +188,10 @@ private: QuerySent, CommandSent, FilamentSensorStateSent, - FINDAReqSent, - StatisticsSent, + Reading8bitRegisters, + Reading16bitRegisters, ButtonSent, - ReadRegisterSent, + ReadRegisterSent, // standalone requests for reading registers - from higher layers WriteRegisterSent, // States which do not expect a message - MSb set @@ -217,7 +218,10 @@ private: /// So far, the only such a case is the filament sensor, but there can be more like this in the future. void CheckAndReportAsyncEvents(); void SendQuery(); - void SendFINDAQuery(); + void StartReading8bitRegisters(); + void ProcessRead8bitRegister(); + void StartReading16bitRegisters(); + ScopeState ProcessRead16bitRegister(ProtocolLogic::ScopeState stateAtEnd); void SendAndUpdateFilamentSensor(); void SendButton(uint8_t btn); void SendVersion(uint8_t stage); @@ -278,7 +282,7 @@ private: State state; ///< internal state of ProtocolLogic Protocol protocol; ///< protocol codec - + array lastReceivedBytes; ///< remembers the last few bytes of incoming communication for diagnostic purposes uint8_t lrb; @@ -290,8 +294,19 @@ private: uint8_t lastFSensor; ///< last state of filament sensor - bool findaPressed; - uint16_t failStatistics; + // 8bit registers + static constexpr uint8_t regs8Count = 3; + static_assert(regs8Count > 0); // code is not ready for empty lists of registers + static const uint8_t regs8Addrs[regs8Count] PROGMEM; + uint8_t regs8[regs8Count]; + + // 16bit registers + static constexpr uint8_t regs16Count = 2; + static_assert(regs16Count > 0); // code is not ready for empty lists of registers + static const uint8_t regs16Addrs[regs16Count] PROGMEM; + uint16_t regs16[regs16Count]; + + uint8_t regIndex; uint8_t mmuFwVersion[3]; uint16_t mmuFwVersionBuild;