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 };
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 }
{}

View File

@ -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;