|
@@ -7,8 +7,7 @@
|
|
|
namespace MMU2 {
|
|
|
|
|
|
StepStatus ProtocolLogicPartBase::ProcessFINDAReqSent(StepStatus finishedRV, State nextState){
|
|
|
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
|
|
|
- if (expmsg != MessageReady)
|
|
|
+ if (auto expmsg = logic->ExpectingMessage(linkLayerTimeout); expmsg != MessageReady)
|
|
|
return expmsg;
|
|
|
logic->findaPressed = logic->rsp.paramValue;
|
|
|
state = nextState;
|
|
@@ -44,16 +43,9 @@ void ProtocolLogicPartBase::SendButton(uint8_t btn){
|
|
|
state = State::ButtonSent;
|
|
|
}
|
|
|
|
|
|
-StepStatus ProtocolLogic::ProcessUARTByte(uint8_t c) {
|
|
|
- switch (protocol.DecodeResponse(c)) {
|
|
|
- case DecodeStatus::MessageCompleted:
|
|
|
- return MessageReady;
|
|
|
- case DecodeStatus::NeedMoreData:
|
|
|
- return Processing;
|
|
|
- case DecodeStatus::Error:
|
|
|
- default:
|
|
|
- return ProtocolError;
|
|
|
- }
|
|
|
+void ProtocolLogicPartBase::SendVersion(uint8_t stage) {
|
|
|
+ logic->SendMsg(RequestMsg(RequestMsgCodes::Version, stage));
|
|
|
+ state = (State)((uint_fast8_t)State::S0Sent + stage);
|
|
|
}
|
|
|
|
|
|
// searches for "ok\n" in the incoming serial data (that's the usual response of the old MMU FW)
|
|
@@ -133,54 +125,92 @@ void ProtocolLogic::SendMsg(RequestMsg rq) {
|
|
|
}
|
|
|
|
|
|
void StartSeq::Restart() {
|
|
|
- state = State::S0Sent;
|
|
|
- logic->SendMsg(RequestMsg(RequestMsgCodes::Version, 0));
|
|
|
+ SendVersion(0);
|
|
|
}
|
|
|
|
|
|
StepStatus StartSeq::Step() {
|
|
|
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
|
|
|
- if (expmsg != MessageReady)
|
|
|
+ if (auto expmsg = logic->ExpectingMessage(linkLayerTimeout); expmsg != MessageReady)
|
|
|
return expmsg;
|
|
|
|
|
|
// solve initial handshake
|
|
|
switch (state) {
|
|
|
case State::S0Sent: // received response to S0 - major
|
|
|
- logic->mmuFwVersionMajor = logic->rsp.paramValue;
|
|
|
- if (logic->mmuFwVersionMajor != 2) {
|
|
|
- return VersionMismatch;
|
|
|
+ if( logic->rsp.request.code != RequestMsgCodes::Version || logic->rsp.request.value != 0 ){
|
|
|
+ // got a response to something else - protocol corruption probably, repeat the query
|
|
|
+ SendVersion(0);
|
|
|
+ } else {
|
|
|
+ logic->mmuFwVersionMajor = logic->rsp.paramValue;
|
|
|
+ if (logic->mmuFwVersionMajor != 2) {
|
|
|
+ return VersionMismatch;
|
|
|
+ }
|
|
|
+ logic->dataTO.Reset(); // got meaningful response from the MMU, stop data layer timeout tracking
|
|
|
+ SendVersion(1);
|
|
|
}
|
|
|
- logic->dataTO.Reset(); // got meaningful response from the MMU, stop data layer timeout tracking
|
|
|
- logic->SendMsg(RequestMsg(RequestMsgCodes::Version, 1));
|
|
|
- state = State::S1Sent;
|
|
|
break;
|
|
|
case State::S1Sent: // received response to S1 - minor
|
|
|
- logic->mmuFwVersionMinor = logic->rsp.paramValue;
|
|
|
- if (logic->mmuFwVersionMinor != 0) {
|
|
|
- return VersionMismatch;
|
|
|
+ if( logic->rsp.request.code != RequestMsgCodes::Version || logic->rsp.request.value != 1 ){
|
|
|
+ // got a response to something else - protocol corruption probably, repeat the query OR restart the comm by issuing S0?
|
|
|
+ SendVersion(1);
|
|
|
+ } else {
|
|
|
+ logic->mmuFwVersionMinor = logic->rsp.paramValue;
|
|
|
+ if (logic->mmuFwVersionMinor != 0) {
|
|
|
+ return VersionMismatch;
|
|
|
+ }
|
|
|
+ SendVersion(2);
|
|
|
}
|
|
|
- logic->SendMsg(RequestMsg(RequestMsgCodes::Version, 2));
|
|
|
- state = State::S2Sent;
|
|
|
break;
|
|
|
case State::S2Sent: // received response to S2 - revision
|
|
|
- logic->mmuFwVersionBuild = logic->rsp.paramValue;
|
|
|
- if (logic->mmuFwVersionBuild < 18) {
|
|
|
- return VersionMismatch;
|
|
|
+ if( logic->rsp.request.code != RequestMsgCodes::Version || logic->rsp.request.value != 2 ){
|
|
|
+ // got a response to something else - protocol corruption probably, repeat the query OR restart the comm by issuing S0?
|
|
|
+ SendVersion(2);
|
|
|
+ } else {
|
|
|
+ logic->mmuFwVersionBuild = logic->rsp.paramValue;
|
|
|
+ if (logic->mmuFwVersionBuild < 18) {
|
|
|
+ return VersionMismatch;
|
|
|
+ }
|
|
|
+ // Start General Interrogation after line up.
|
|
|
+ // For now we just send the state of the filament sensor, but we may request
|
|
|
+ // data point states from the MMU as well. TBD in the future, especially with another protocol
|
|
|
+ SendAndUpdateFilamentSensor();
|
|
|
}
|
|
|
- // Start General Interrogation after line up.
|
|
|
- // For now we just send the state of the filament sensor, but we may request
|
|
|
- // data point states from the MMU as well. TBD in the future, especially with another protocol
|
|
|
- SendAndUpdateFilamentSensor();
|
|
|
break;
|
|
|
case State::FilamentSensorStateSent:
|
|
|
state = State::Ready;
|
|
|
return Finished;
|
|
|
break;
|
|
|
+ case State::RecoveringProtocolError:
|
|
|
+ // timer elapsed, clear the input buffer
|
|
|
+ while (logic->uart->read() >= 0)
|
|
|
+ ;
|
|
|
+ SendVersion(0);
|
|
|
+ break;
|
|
|
default:
|
|
|
return VersionMismatch;
|
|
|
}
|
|
|
return Processing;
|
|
|
}
|
|
|
|
|
|
+void DelayedRestart::Restart() {
|
|
|
+ state = State::RecoveringProtocolError;
|
|
|
+}
|
|
|
+
|
|
|
+StepStatus DelayedRestart::Step() {
|
|
|
+ switch (state) {
|
|
|
+ case State::RecoveringProtocolError:
|
|
|
+ if (logic->Elapsed(heartBeatPeriod)) { // this basically means, that we are waiting until there is some traffic on
|
|
|
+ while (logic->uart->read() != -1)
|
|
|
+ ; // clear the input buffer
|
|
|
+ // switch to StartSeq
|
|
|
+ logic->Start();
|
|
|
+ }
|
|
|
+ return Processing;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return Finished;
|
|
|
+}
|
|
|
+
|
|
|
void Command::Restart() {
|
|
|
state = State::CommandSent;
|
|
|
logic->SendMsg(logic->command.rq);
|
|
@@ -189,8 +219,7 @@ void Command::Restart() {
|
|
|
StepStatus Command::Step() {
|
|
|
switch (state) {
|
|
|
case State::CommandSent: {
|
|
|
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
|
|
|
- if (expmsg != MessageReady)
|
|
|
+ if (auto expmsg = logic->ExpectingMessage(linkLayerTimeout); expmsg != MessageReady)
|
|
|
return expmsg;
|
|
|
|
|
|
switch (logic->rsp.paramCode) { // the response should be either accepted or rejected
|
|
@@ -217,12 +246,10 @@ StepStatus Command::Step() {
|
|
|
CheckAndReportAsyncEvents();
|
|
|
}
|
|
|
break;
|
|
|
- case State::QuerySent: {
|
|
|
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
|
|
|
- if (expmsg != MessageReady)
|
|
|
+ case State::QuerySent:
|
|
|
+ if (auto expmsg = logic->ExpectingMessage(linkLayerTimeout); expmsg != MessageReady)
|
|
|
return expmsg;
|
|
|
- }
|
|
|
- // [[fallthrough]];
|
|
|
+ [[fallthrough]];
|
|
|
case State::ContinueFromIdle:
|
|
|
switch (logic->rsp.paramCode) {
|
|
|
case ResponseMsgParamCodes::Processing:
|
|
@@ -251,21 +278,18 @@ StepStatus Command::Step() {
|
|
|
return ProtocolError;
|
|
|
}
|
|
|
break;
|
|
|
- case State::FilamentSensorStateSent:{
|
|
|
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
|
|
|
- if (expmsg != MessageReady)
|
|
|
+ case State::FilamentSensorStateSent:
|
|
|
+ if (auto expmsg = logic->ExpectingMessage(linkLayerTimeout); expmsg != MessageReady)
|
|
|
return expmsg;
|
|
|
SendFINDAQuery();
|
|
|
- } break;
|
|
|
+ break;
|
|
|
case State::FINDAReqSent:
|
|
|
return ProcessFINDAReqSent(Processing, State::Wait);
|
|
|
case State::ButtonSent:{
|
|
|
// button is never confirmed ... may be it should be
|
|
|
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
|
|
|
- if (expmsg != MessageReady)
|
|
|
+ if (auto expmsg = logic->ExpectingMessage(linkLayerTimeout); expmsg != MessageReady)
|
|
|
return expmsg;
|
|
|
- if (logic->rsp.paramCode == ResponseMsgParamCodes::Accepted)
|
|
|
- {
|
|
|
+ if (logic->rsp.paramCode == ResponseMsgParamCodes::Accepted) {
|
|
|
// Button was accepted, decrement the retry.
|
|
|
mmu2.DecrementRetryAttempts();
|
|
|
}
|
|
@@ -289,9 +313,8 @@ StepStatus Idle::Step() {
|
|
|
return Processing;
|
|
|
}
|
|
|
break;
|
|
|
- case State::QuerySent: { // check UART
|
|
|
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
|
|
|
- if (expmsg != MessageReady)
|
|
|
+ case State::QuerySent: // check UART
|
|
|
+ if (auto expmsg = logic->ExpectingMessage(linkLayerTimeout); expmsg != MessageReady)
|
|
|
return expmsg;
|
|
|
// If we are accidentally in Idle and we receive something like "T0 P1" - that means the communication dropped out while a command was in progress.
|
|
|
// That causes no issues here, we just need to switch to Command processing and continue there from now on.
|
|
@@ -331,7 +354,7 @@ StepStatus Idle::Step() {
|
|
|
}
|
|
|
SendFINDAQuery();
|
|
|
return Processing;
|
|
|
- } break;
|
|
|
+ break;
|
|
|
case State::FINDAReqSent:
|
|
|
return ProcessFINDAReqSent(Finished, State::Ready);
|
|
|
default:
|
|
@@ -351,21 +374,31 @@ StepStatus Idle::Step() {
|
|
|
ProtocolLogic::ProtocolLogic(MMU2Serial *uart)
|
|
|
: stopped(this)
|
|
|
, startSeq(this)
|
|
|
+ , delayedRestart(this)
|
|
|
, idle(this)
|
|
|
, command(this)
|
|
|
, currentState(&stopped)
|
|
|
, plannedRq(RequestMsgCodes::unknown, 0)
|
|
|
, lastUARTActivityMs(0)
|
|
|
+ , dataTO()
|
|
|
, rsp(RequestMsg(RequestMsgCodes::unknown, 0), ResponseMsgParamCodes::unknown, 0)
|
|
|
, state(State::Stopped)
|
|
|
, lrb(0)
|
|
|
, uart(uart)
|
|
|
+ , errorCode(ErrorCode::OK)
|
|
|
+ , progressCode(ProgressCode::OK)
|
|
|
+ , buttonCode(NoButton)
|
|
|
, lastFSensor((uint8_t)WhereIsFilament())
|
|
|
+ , findaPressed(false)
|
|
|
+ , mmuFwVersionMajor(0)
|
|
|
+ , mmuFwVersionMinor(0)
|
|
|
+ , mmuFwVersionBuild(0)
|
|
|
{}
|
|
|
|
|
|
void ProtocolLogic::Start() {
|
|
|
state = State::InitSequence;
|
|
|
currentState = &startSeq;
|
|
|
+ protocol.ResetResponseDecoder(); // important - finished delayed restart relies on this
|
|
|
startSeq.Restart();
|
|
|
}
|
|
|
|
|
@@ -446,13 +479,6 @@ void ProtocolLogic::SwitchToIdle() {
|
|
|
idle.Restart();
|
|
|
}
|
|
|
|
|
|
-void ProtocolLogic::HandleCommunicationTimeout() {
|
|
|
- uart->flush(); // clear the output buffer
|
|
|
- currentState = &startSeq;
|
|
|
- state = State::InitSequence;
|
|
|
- startSeq.Restart();
|
|
|
-}
|
|
|
-
|
|
|
bool ProtocolLogic::Elapsed(uint32_t timeout) const {
|
|
|
return _millis() >= (lastUARTActivityMs + timeout);
|
|
|
}
|
|
@@ -554,9 +580,7 @@ void ProtocolLogic::LogResponse(){
|
|
|
SERIAL_ECHOLN();
|
|
|
}
|
|
|
|
|
|
-StepStatus ProtocolLogic::HandleCommError(const char *msg, StepStatus ss){
|
|
|
- protocol.ResetResponseDecoder();
|
|
|
- HandleCommunicationTimeout();
|
|
|
+StepStatus ProtocolLogic::SuppressShortDropOuts(const char *msg, StepStatus ss) {
|
|
|
if( dataTO.Record(ss) ){
|
|
|
LogError(msg);
|
|
|
return dataTO.InitialCause();
|
|
@@ -565,6 +589,21 @@ StepStatus ProtocolLogic::HandleCommError(const char *msg, StepStatus ss){
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+StepStatus ProtocolLogic::HandleCommunicationTimeout() {
|
|
|
+ uart->flush(); // clear the output buffer
|
|
|
+ protocol.ResetResponseDecoder();
|
|
|
+ Start();
|
|
|
+ return SuppressShortDropOuts("Communication timeout", CommunicationTimeout);
|
|
|
+}
|
|
|
+
|
|
|
+StepStatus ProtocolLogic::HandleProtocolError() {
|
|
|
+ uart->flush(); // clear the output buffer
|
|
|
+ state = State::InitSequence;
|
|
|
+ currentState = &delayedRestart;
|
|
|
+ delayedRestart.Restart();
|
|
|
+ return SuppressShortDropOuts("Protocol Error", ProtocolError);
|
|
|
+}
|
|
|
+
|
|
|
StepStatus ProtocolLogic::Step() {
|
|
|
if( ! currentState->ExpectsResponse() ){ // if not waiting for a response, activate a planned request immediately
|
|
|
ActivatePlannedRequest();
|
|
@@ -587,8 +626,7 @@ StepStatus ProtocolLogic::Step() {
|
|
|
currentStatus = Processing;
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- break;
|
|
|
+ } break;
|
|
|
case CommandRejected:
|
|
|
// we have to repeat it - that's the only thing we can do
|
|
|
// no change in state
|
|
@@ -606,10 +644,10 @@ StepStatus ProtocolLogic::Step() {
|
|
|
Stop(); // cannot continue
|
|
|
break;
|
|
|
case ProtocolError:
|
|
|
- currentStatus = HandleCommError("Protocol error", ProtocolError);
|
|
|
+ currentStatus = HandleProtocolError();
|
|
|
break;
|
|
|
case CommunicationTimeout:
|
|
|
- currentStatus = HandleCommError("Communication timeout", CommunicationTimeout);
|
|
|
+ currentStatus = HandleCommunicationTimeout();
|
|
|
break;
|
|
|
default:
|
|
|
break;
|