Browse Source

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.
D.R.racer 2 years ago
parent
commit
013ce588a5
2 changed files with 82 additions and 31 deletions
  1. 58 22
      Firmware/mmu2_protocol_logic.cpp
  2. 24 9
      Firmware/mmu2_protocol_logic.h

+ 58 - 22
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<Buttons>(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<ErrorCode>(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 }
 {}
 

+ 24 - 9
Firmware/mmu2_protocol_logic.h

@@ -1,5 +1,6 @@
 #pragma once
 #include <stdint.h>
+#include <avr/pgmspace.h>
 // #include <array> //@@TODO Don't we have STL for AVR somewhere?
 template<typename T, uint8_t N>
 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<uint8_t, 16> 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;