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.
This commit is contained in:
D.R.racer 2022-10-10 12:35:31 +02:00 committed by DRracer
parent ebb79351a7
commit 013ce588a5
2 changed files with 82 additions and 31 deletions

View File

@ -8,6 +8,17 @@ namespace MMU2 {
static const uint8_t supportedMmuFWVersion[3] PROGMEM = { 2, 1, 3 }; 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() { void ProtocolLogic::CheckAndReportAsyncEvents() {
// even when waiting for a query period, we need to report a change in filament sensor's state // 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 // - 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; scopeState = ScopeState::QuerySent;
} }
void ProtocolLogic::SendFINDAQuery() { void ProtocolLogic::StartReading8bitRegisters() {
SendMsg(RequestMsg(RequestMsgCodes::Finda, 0)); regIndex = 0;
scopeState = ScopeState::FINDAReqSent; 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() { void ProtocolLogic::SendAndUpdateFilamentSensor() {
@ -313,14 +351,13 @@ StepStatus ProtocolLogic::CommandStep() {
case ScopeState::QuerySent: case ScopeState::QuerySent:
return ProcessCommandQueryResponse(); return ProcessCommandQueryResponse();
case ScopeState::FilamentSensorStateSent: case ScopeState::FilamentSensorStateSent:
SendFINDAQuery(); StartReading8bitRegisters();
return Processing; return Processing;
case ScopeState::FINDAReqSent: case ScopeState::Reading8bitRegisters:
findaPressed = rsp.paramValue; ProcessRead8bitRegister();
SendReadRegister(4, ScopeState::StatisticsSent);
return Processing; return Processing;
case ScopeState::StatisticsSent: case ScopeState::Reading16bitRegisters:
scopeState = ScopeState::Wait; scopeState = ProcessRead16bitRegister(ScopeState::Wait);
return Processing; return Processing;
case ScopeState::ButtonSent: case ScopeState::ButtonSent:
if (rsp.paramCode == ResponseMsgParamCodes::Accepted) { 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 // 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. // to prepare, then pass it back to the MMU so it can work its magic.
buttonCode = static_cast<Buttons>(rsp.paramValue); buttonCode = static_cast<Buttons>(rsp.paramValue);
SendFINDAQuery(); StartReading8bitRegisters();
return ButtonPushed; return ButtonPushed;
case ResponseMsgParamCodes::Processing: case ResponseMsgParamCodes::Processing:
// @@TODO we may actually use this branch to report progress of manual operation on the MMU // @@TODO we may actually use this branch to report progress of manual operation on the MMU
@ -382,29 +419,27 @@ StepStatus ProtocolLogic::IdleStep() {
break; break;
default: default:
errorCode = static_cast<ErrorCode>(rsp.paramValue); errorCode = static_cast<ErrorCode>(rsp.paramValue);
SendFINDAQuery(); // continue Idle state without restarting the communication StartReading8bitRegisters(); // continue Idle state without restarting the communication
return CommandError; return CommandError;
} }
break; break;
default: default:
return ProtocolError; return ProtocolError;
} }
SendFINDAQuery(); StartReading8bitRegisters();
return Processing; return Processing;
case ScopeState::FINDAReqSent: case ScopeState::Reading8bitRegisters:
findaPressed = rsp.paramValue; ProcessRead8bitRegister();
SendReadRegister(4, ScopeState::StatisticsSent);
return Processing; return Processing;
case ScopeState::StatisticsSent: case ScopeState::Reading16bitRegisters:
failStatistics = rsp.paramValue; scopeState = ProcessRead16bitRegister(ScopeState::Ready);
scopeState = ScopeState::Ready; return scopeState == ScopeState::Ready ? Finished : Processing;
return Finished;
case ScopeState::ButtonSent: case ScopeState::ButtonSent:
if (rsp.paramCode == ResponseMsgParamCodes::Accepted) { if (rsp.paramCode == ResponseMsgParamCodes::Accepted) {
// Button was accepted, decrement the retry. // Button was accepted, decrement the retry.
mmu2.DecrementRetryAttempts(); mmu2.DecrementRetryAttempts();
} }
SendFINDAQuery(); StartReading8bitRegisters();
return Processing; return Processing;
case ScopeState::ReadRegisterSent: case ScopeState::ReadRegisterSent:
if (rsp.paramCode == ResponseMsgParamCodes::Accepted) { if (rsp.paramCode == ResponseMsgParamCodes::Accepted) {
@ -444,8 +479,9 @@ ProtocolLogic::ProtocolLogic(MMU2Serial *uart)
, progressCode(ProgressCode::OK) , progressCode(ProgressCode::OK)
, buttonCode(NoButton) , buttonCode(NoButton)
, lastFSensor((uint8_t)WhereIsFilament()) , lastFSensor((uint8_t)WhereIsFilament())
, findaPressed(false) , regs8 { 0, 0, 0 }
, failStatistics(0) , regs16 { 0, 0 }
, regIndex(0)
, mmuFwVersion { 0, 0, 0 } , mmuFwVersion { 0, 0, 0 }
{} {}

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#include <avr/pgmspace.h>
// #include <array> //@@TODO Don't we have STL for AVR somewhere? // #include <array> //@@TODO Don't we have STL for AVR somewhere?
template<typename T, uint8_t N> template<typename T, uint8_t N>
class array { class array {
@ -110,11 +111,11 @@ public:
} }
inline bool FindaPressed() const { inline bool FindaPressed() const {
return findaPressed; return regs8[0];
} }
inline uint16_t FailStatistics() const { inline uint16_t FailStatistics() const {
return failStatistics; return regs16[0];
} }
inline uint8_t MmuFwVersionMajor() const { inline uint8_t MmuFwVersionMajor() const {
@ -187,10 +188,10 @@ private:
QuerySent, QuerySent,
CommandSent, CommandSent,
FilamentSensorStateSent, FilamentSensorStateSent,
FINDAReqSent, Reading8bitRegisters,
StatisticsSent, Reading16bitRegisters,
ButtonSent, ButtonSent,
ReadRegisterSent, ReadRegisterSent, // standalone requests for reading registers - from higher layers
WriteRegisterSent, WriteRegisterSent,
// States which do not expect a message - MSb set // 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. /// So far, the only such a case is the filament sensor, but there can be more like this in the future.
void CheckAndReportAsyncEvents(); void CheckAndReportAsyncEvents();
void SendQuery(); void SendQuery();
void SendFINDAQuery(); void StartReading8bitRegisters();
void ProcessRead8bitRegister();
void StartReading16bitRegisters();
ScopeState ProcessRead16bitRegister(ProtocolLogic::ScopeState stateAtEnd);
void SendAndUpdateFilamentSensor(); void SendAndUpdateFilamentSensor();
void SendButton(uint8_t btn); void SendButton(uint8_t btn);
void SendVersion(uint8_t stage); void SendVersion(uint8_t stage);
@ -278,7 +282,7 @@ private:
State state; ///< internal state of ProtocolLogic State state; ///< internal state of ProtocolLogic
Protocol protocol; ///< protocol codec Protocol protocol; ///< protocol codec
array<uint8_t, 16> lastReceivedBytes; ///< remembers the last few bytes of incoming communication for diagnostic purposes array<uint8_t, 16> lastReceivedBytes; ///< remembers the last few bytes of incoming communication for diagnostic purposes
uint8_t lrb; uint8_t lrb;
@ -290,8 +294,19 @@ private:
uint8_t lastFSensor; ///< last state of filament sensor uint8_t lastFSensor; ///< last state of filament sensor
bool findaPressed; // 8bit registers
uint16_t failStatistics; 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]; uint8_t mmuFwVersion[3];
uint16_t mmuFwVersionBuild; uint16_t mmuFwVersionBuild;