Prusa3d Marlin fork
mmu2_protocol_logic.h
1 #pragma once
2 #include <stdint.h>
3 #include <avr/pgmspace.h>
4 
5 #ifdef __AVR__
6  #include "mmu2/error_codes.h"
7  #include "mmu2/progress_codes.h"
8  #include "mmu2/buttons.h"
9  #include "mmu2/registers.h"
10  #include "mmu2_protocol.h"
11 
12 // #include <array> std array is not available on AVR ... we need to "fake" it
13 namespace std {
14 template <typename T, uint8_t N>
15 class array {
16  T data[N];
17 
18 public:
19  array() = default;
20  inline constexpr T *begin() const { return data; }
21  inline constexpr T *end() const { return data + N; }
22  static constexpr uint8_t size() { return N; }
23  inline T &operator[](uint8_t i) {
24  return data[i];
25  }
26 };
27 } // namespace std
28 #else
29 
30  #include <array>
31  #include "../../../../../../Prusa-Firmware-MMU/src/logic/error_codes.h"
32  #include "../../../../../../Prusa-Firmware-MMU/src/logic/progress_codes.h"
33 
34  // prevent ARM HAL macros from breaking our code
35  #undef CRC
36  #include "../../../../../../Prusa-Firmware-MMU/src/modules/protocol.h"
37  #include "buttons.h"
38  #include "registers.h"
39 #endif
40 
41 #include "mmu2_serial.h"
42 
44 namespace MMU2 {
45 
46 static constexpr uint8_t MAX_RETRIES = 3U;
47 
48 using namespace modules::protocol;
49 
50 class ProtocolLogic;
51 
53 enum StepStatus : uint_fast8_t {
54  Processing = 0,
64  CommunicationRecovered,
66 };
67 
68 inline constexpr uint32_t linkLayerTimeout = 2000;
69 inline constexpr uint32_t dataLayerTimeout = linkLayerTimeout * 3;
70 inline constexpr uint32_t heartBeatPeriod = linkLayerTimeout / 2;
71 
72 static_assert(heartBeatPeriod < linkLayerTimeout && linkLayerTimeout < dataLayerTimeout, "Incorrect ordering of timeouts");
73 
76 public:
77  static constexpr uint8_t maxOccurrences = 10; // ideally set this to >8 seconds -> 12x heartBeatPeriod
78  static_assert(maxOccurrences > 1, "we should really silently ignore at least 1 comm drop out if recovered immediately afterwards");
79  DropOutFilter() = default;
80 
82  bool Record(StepStatus ss);
83 
85  inline StepStatus InitialCause() const { return cause; }
86 
88  inline void Reset() { occurrences = maxOccurrences; }
89 
90 private:
91  StepStatus cause;
92  uint8_t occurrences = maxOccurrences;
93 };
94 
97 public:
98  ProtocolLogic(MMU2Serial *uart, uint8_t extraLoadDistance, uint8_t pulleySlowFeedrate);
99 
101  void Start();
102 
104  void Stop();
105 
106  // Issue commands to the MMU
107  void ToolChange(uint8_t slot);
108  void Statistics();
109  void UnloadFilament();
110  void LoadFilament(uint8_t slot);
111  void EjectFilament(uint8_t slot);
112  void CutFilament(uint8_t slot);
113  void ResetMMU(uint8_t mode = 0);
114  void Button(uint8_t index);
115  void Home(uint8_t mode);
116  void ReadRegister(uint8_t address);
117  void WriteRegister(uint8_t address, uint16_t data);
118 
122  inline void PlanExtraLoadDistance(uint8_t eld_mm) {
123  initRegs8[0] = eld_mm;
124  }
126  inline uint8_t ExtraLoadDistance() const {
127  return initRegs8[0];
128  }
129 
133  inline void PlanPulleySlowFeedRate(uint8_t psfr) {
134  initRegs8[1] = psfr;
135  }
137  inline uint8_t PulleySlowFeedRate() const {
138  return initRegs8[1]; // even though MMU register 0x14 is 16bit, reasonable speeds are way below 255mm/s - saving space ;)
139  }
140 
142  StepStatus Step();
143 
145  ErrorCode Error() const { return errorCode; }
146 
148  ProgressCode Progress() const { return progressCode; }
149 
151  Buttons Button() const { return buttonCode; }
152 
153  uint8_t CommandInProgress() const;
154 
155  inline bool Running() const {
156  return state == State::Running;
157  }
158 
159  inline bool FindaPressed() const {
160  return regs8[0];
161  }
162 
163  inline uint16_t FailStatistics() const {
164  return regs16[0];
165  }
166 
167  inline uint8_t MmuFwVersionMajor() const {
168  return mmuFwVersion[0];
169  }
170 
171  inline uint8_t MmuFwVersionMinor() const {
172  return mmuFwVersion[1];
173  }
174 
175  inline uint8_t MmuFwVersionRevision() const {
176  return mmuFwVersion[2];
177  }
178 
180  constexpr uint8_t RetryAttempts() const { return retryAttempts; }
181 
184  void DecrementRetryAttempts();
185 
187  void ResetRetryAttempts();
188 
189  void ResetCommunicationTimeoutAttempts();
190 
191  constexpr bool InAutoRetry() const { return inAutoRetry; }
192  void SetInAutoRetry(bool iar) {
193  inAutoRetry = iar;
194  }
195 
196  inline void SetPrinterError(ErrorCode ec) {
197  explicitPrinterError = ec;
198  }
199  inline void ClearPrinterError() {
200  explicitPrinterError = ErrorCode::OK;
201  }
202  inline bool IsPrinterError() const {
203  return explicitPrinterError != ErrorCode::OK;
204  }
205  inline ErrorCode PrinterError() const {
206  return explicitPrinterError;
207  }
208 #ifndef UNITTEST
209 private:
210 #endif
211  StepStatus ExpectingMessage();
212  void SendMsg(RequestMsg rq);
213  void SendWriteMsg(RequestMsg rq);
214  void SwitchToIdle();
215  StepStatus SuppressShortDropOuts(const char *msg_P, StepStatus ss);
216  StepStatus HandleCommunicationTimeout();
217  StepStatus HandleProtocolError();
218  bool Elapsed(uint32_t timeout) const;
219  void RecordUARTActivity();
220  void RecordReceivedByte(uint8_t c);
221  void FormatLastReceivedBytes(char *dst);
222  void FormatLastResponseMsgAndClearLRB(char *dst);
223  void LogRequestMsg(const uint8_t *txbuff, uint8_t size);
224  void LogError(const char *reason_P);
225  void LogResponse();
226  StepStatus SwitchFromIdleToCommand();
227  void SwitchFromStartToIdle();
228 
229  ErrorCode explicitPrinterError;
230 
231  enum class State : uint_fast8_t {
232  Stopped,
233  InitSequence,
234  Running
235  };
236 
237  enum class Scope : uint_fast8_t {
238  Stopped,
239  StartSeq,
240  DelayedRestart,
241  Idle,
242  Command
243  };
244  Scope currentScope;
245 
246  // basic scope members
248  bool ExpectsResponse() const { return ((uint8_t)scopeState & (uint8_t)ScopeState::NotExpectsResponse) == 0; }
249 
252  enum class ScopeState : uint_fast8_t {
253  S0Sent, // beware - due to optimization reasons these SxSent must be kept one after another
254  S1Sent,
255  S2Sent,
256  S3Sent,
257  QuerySent,
258  CommandSent,
259  FilamentSensorStateSent,
260  Reading8bitRegisters,
261  Reading16bitRegisters,
262  WritingInitRegisters,
263  ButtonSent,
264  ReadRegisterSent, // standalone requests for reading registers - from higher layers
265  WriteRegisterSent,
266 
267  // States which do not expect a message - MSb set
268  NotExpectsResponse = 0x80,
269  Wait = NotExpectsResponse + 1,
270  Ready = NotExpectsResponse + 2,
271  RecoveringProtocolError = NotExpectsResponse + 3,
272  };
273 
274  ScopeState scopeState;
275 
279  // StepStatus ProcessFINDAReqSent(StepStatus finishedRV, State nextState);
280 
284  // StepStatus ProcessStatisticsReqSent(StepStatus finishedRV, State nextState);
285 
289  void CheckAndReportAsyncEvents();
290  void SendQuery();
291  void StartReading8bitRegisters();
292  void ProcessRead8bitRegister();
293  void StartReading16bitRegisters();
294  ScopeState ProcessRead16bitRegister(ProtocolLogic::ScopeState stateAtEnd);
295  void StartWritingInitRegisters();
297  bool ProcessWritingInitRegister();
298  void SendAndUpdateFilamentSensor();
299  void SendButton(uint8_t btn);
300  void SendVersion(uint8_t stage);
301  void SendReadRegister(uint8_t index, ScopeState nextState);
302  void SendWriteRegister(uint8_t index, uint16_t value, ScopeState nextState);
303 
304  StepStatus ProcessVersionResponse(uint8_t stage);
305 
307  StepStatus ScopeStep();
308 
309  static constexpr uint8_t maxRetries = 6;
310  uint8_t retries;
311 
312  void StartSeqRestart();
313  void DelayedRestartRestart();
314  void IdleRestart();
315  void CommandRestart();
316 
317  StepStatus StartSeqStep();
318  StepStatus DelayedRestartWait();
319  StepStatus IdleStep();
320  StepStatus IdleWait();
321  StepStatus CommandStep();
322  StepStatus CommandWait();
323  StepStatus StoppedStep() { return Processing; }
324 
325  StepStatus ProcessCommandQueryResponse();
326 
327  inline void SetRequestMsg(RequestMsg msg) {
328  rq = msg;
329  }
330  inline const RequestMsg &ReqMsg() const { return rq; }
331  RequestMsg rq = RequestMsg(RequestMsgCodes::unknown, 0);
332 
343  RequestMsg plannedRq;
344 
346  void PlanGenericRequest(RequestMsg rq);
348  bool ActivatePlannedRequest();
349 
350  uint32_t lastUARTActivityMs;
351  DropOutFilter dataTO;
352 
353  ResponseMsg rsp;
354 
355  State state;
356 
357  Protocol protocol;
358 
359  std::array<uint8_t, 16> lastReceivedBytes;
360  uint8_t lrb;
361 
362  MMU2Serial *uart;
363 
364  ErrorCode errorCode;
365  ProgressCode progressCode;
366  Buttons buttonCode;
367 
368  uint8_t lastFSensor;
369 
370 #ifndef __AVR__
371  uint8_t txbuff[Protocol::MaxRequestSize()];
373 #endif
374 
375  // 8bit registers
376  static constexpr uint8_t regs8Count = 3;
377  static_assert(regs8Count > 0); // code is not ready for empty lists of registers
378  static const Register regs8Addrs[regs8Count] PROGMEM;
379  uint8_t regs8[regs8Count] = { 0, 0, 0 };
380 
381  // 16bit registers
382  static constexpr uint8_t regs16Count = 2;
383  static_assert(regs16Count > 0); // code is not ready for empty lists of registers
384  static const Register regs16Addrs[regs16Count] PROGMEM;
385  uint16_t regs16[regs16Count] = { 0, 0 };
386 
387  // 8bit init values to be sent to the MMU after line up
388  static constexpr uint8_t initRegs8Count = 2;
389  static_assert(initRegs8Count > 0); // code is not ready for empty lists of registers
390  static const Register initRegs8Addrs[initRegs8Count] PROGMEM;
391  uint8_t initRegs8[initRegs8Count];
392 
393  uint8_t regIndex;
394 
395  uint8_t mmuFwVersion[3] = { 0, 0, 0 };
396  uint16_t mmuFwVersionBuild;
397 
398  uint8_t retryAttempts;
399  bool inAutoRetry;
400 
401  friend class MMU2;
402 };
403 
404 } // namespace MMU2
Filter of short consecutive drop outs which are recovered instantly.
Definition: mmu2_protocol_logic.h:75
void Reset()
Rearms the object for further processing - basically call this once the MMU responds with something m...
Definition: mmu2_protocol_logic.h:88
StepStatus InitialCause() const
Definition: mmu2_protocol_logic.h:85
A minimal serial interface for the MMU.
Definition: mmu2_serial.h:8
Logic layer of the MMU vs. printer communication protocol.
Definition: mmu2_protocol_logic.h:96
ErrorCode Error() const
Definition: mmu2_protocol_logic.h:145
void PlanExtraLoadDistance(uint8_t eld_mm)
Definition: mmu2_protocol_logic.h:122
void PlanPulleySlowFeedRate(uint8_t psfr)
Definition: mmu2_protocol_logic.h:133
uint8_t ExtraLoadDistance() const
Definition: mmu2_protocol_logic.h:126
uint8_t PulleySlowFeedRate() const
Definition: mmu2_protocol_logic.h:137
constexpr uint8_t RetryAttempts() const
Current number of retry attempts left.
Definition: mmu2_protocol_logic.h:180
Buttons Button() const
Definition: mmu2_protocol_logic.h:151
ProgressCode Progress() const
Definition: mmu2_protocol_logic.h:148
Definition: mmu2_protocol.h:133
static constexpr uint8_t MaxRequestSize()
Definition: mmu2_protocol.h:162
Definition: mmu2_protocol_logic.h:15
New MMU2 protocol logic.
Definition: mmu2.cpp:26
constexpr uint32_t dataLayerTimeout
data layer communication timeout
Definition: mmu2_protocol_logic.h:69
constexpr uint32_t linkLayerTimeout
default link layer communication timeout
Definition: mmu2_protocol_logic.h:68
StepStatus
ProtocolLogic stepping statuses.
Definition: mmu2_protocol_logic.h:53
@ VersionMismatch
the MMU reports its firmware version incompatible with our implementation
Definition: mmu2_protocol_logic.h:62
@ Finished
Scope finished successfully.
Definition: mmu2_protocol_logic.h:56
@ ProtocolError
bytes read from the MMU didn't form a valid response
Definition: mmu2_protocol_logic.h:59
@ Interrupted
received "Finished" message related to a different command than originally issued (most likely the MM...
Definition: mmu2_protocol_logic.h:57
@ ButtonPushed
The MMU reported the user pushed one of its three buttons.
Definition: mmu2_protocol_logic.h:65
@ CommandRejected
the MMU rejected the command due to some other command in progress, may be the user is operating the ...
Definition: mmu2_protocol_logic.h:60
@ PrinterError
printer's explicit error - MMU is fine, but the printer was unable to complete the requested operatio...
Definition: mmu2_protocol_logic.h:63
@ MessageReady
a message has been successfully decoded from the received bytes
Definition: mmu2_protocol_logic.h:55
@ CommunicationTimeout
the MMU failed to respond to a request within a specified time frame
Definition: mmu2_protocol_logic.h:58
@ CommandError
the command in progress stopped due to unrecoverable error, user interaction required
Definition: mmu2_protocol_logic.h:61
constexpr uint32_t heartBeatPeriod
period of heart beat messages (Q0)
Definition: mmu2_protocol_logic.h:70
The MMU communication protocol implementation and related stuff.
Definition: mmu2_protocol.cpp:15
A request message - requests are being sent by the printer into the MMU.
Definition: mmu2_protocol.h:46
A response message - responses are being sent from the MMU into the printer as a response to a reques...
Definition: mmu2_protocol.h:88