123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562 |
- #include "mmu2_protocol_logic.h"
- #include "mmu2_log.h"
- #include "mmu2_fsensor.h"
- #include "system_timer.h"
- #include <string.h>
- namespace MMU2 {
- StepStatus ProtocolLogicPartBase::ProcessFINDAReqSent(StepStatus finishedRV, State nextState){
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
- if (expmsg != MessageReady)
- return expmsg;
- logic->findaPressed = logic->rsp.paramValue;
- state = nextState;
- return finishedRV;
- }
- void ProtocolLogicPartBase::CheckAndReportAsyncEvents(){
-
-
- uint8_t fs = (uint8_t)WhereIsFilament();
- if( fs != logic->lastFSensor ){
- SendAndUpdateFilamentSensor();
- }
- }
- void ProtocolLogicPartBase::SendQuery(){
- logic->SendMsg(RequestMsg(RequestMsgCodes::Query, 0));
- state = State::QuerySent;
- }
- void ProtocolLogicPartBase::SendFINDAQuery(){
- logic->SendMsg(RequestMsg(RequestMsgCodes::Finda, 0 ) );
- state = State::FINDAReqSent;
- }
- void ProtocolLogicPartBase::SendAndUpdateFilamentSensor(){
- logic->SendMsg(RequestMsg(RequestMsgCodes::FilamentSensor, logic->lastFSensor = (uint8_t)WhereIsFilament() ) );
- state = State::FilamentSensorStateSent;
- }
- void ProtocolLogicPartBase::SendButton(uint8_t btn){
- logic->SendMsg(RequestMsg(RequestMsgCodes::Button, 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;
- }
- }
- StepStatus ProtocolLogic::ExpectingMessage(uint32_t timeout) {
- int bytesConsumed = 0;
- int c = -1;
-
-
- while((c = uart->read()) >= 0){
- ++bytesConsumed;
- RecordReceivedByte(c);
- switch (protocol.DecodeResponse(c)) {
- case DecodeStatus::MessageCompleted:
- rsp = protocol.GetResponseMsg();
- LogResponse();
- RecordUARTActivity();
- return MessageReady;
- case DecodeStatus::NeedMoreData:
- break;
- case DecodeStatus::Error:
- default:
- RecordUARTActivity();
- return ProtocolError;
- }
- }
- if( bytesConsumed != 0 ){
- RecordUARTActivity();
- return Processing;
- } else if (Elapsed(timeout)) {
- return CommunicationTimeout;
- }
- return Processing;
- }
- void ProtocolLogic::SendMsg(RequestMsg rq) {
- uint8_t txbuff[Protocol::MaxRequestSize()];
- uint8_t len = Protocol::EncodeRequest(rq, txbuff);
- uart->write(txbuff, len);
- LogRequestMsg(txbuff, len);
- RecordUARTActivity();
- }
- void StartSeq::Restart() {
- state = State::S0Sent;
- logic->SendMsg(RequestMsg(RequestMsgCodes::Version, 0));
- }
- StepStatus StartSeq::Step() {
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
- if (expmsg != MessageReady)
- return expmsg;
-
- switch (state) {
- case State::S0Sent:
- if (logic->rsp.paramValue != 2) {
- return VersionMismatch;
- }
- logic->dataTO.Reset();
- logic->SendMsg(RequestMsg(RequestMsgCodes::Version, 1));
- state = State::S1Sent;
- break;
- case State::S1Sent:
- if (logic->rsp.paramValue != 0) {
- return VersionMismatch;
- }
- logic->SendMsg(RequestMsg(RequestMsgCodes::Version, 2));
- state = State::S2Sent;
- break;
- case State::S2Sent:
- if (logic->rsp.paramValue != 0) {
- return VersionMismatch;
- }
-
-
-
- SendAndUpdateFilamentSensor();
- break;
- case State::FilamentSensorStateSent:
- state = State::Ready;
- return Finished;
- break;
- default:
- return VersionMismatch;
- }
- return Processing;
- }
- void Command::Restart() {
- state = State::CommandSent;
- logic->SendMsg(logic->command.rq);
- }
- StepStatus Command::Step() {
- switch (state) {
- case State::CommandSent: {
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
- if (expmsg != MessageReady)
- return expmsg;
- switch (logic->rsp.paramCode) {
- case ResponseMsgParamCodes::Accepted:
- logic->progressCode = ProgressCode::OK;
- logic->errorCode = ErrorCode::RUNNING;
- state = State::Wait;
- break;
- case ResponseMsgParamCodes::Rejected:
-
- logic->progressCode = ProgressCode::OK;
- logic->errorCode = ErrorCode::PROTOCOL_ERROR;
- return CommandRejected;
- default:
- return ProtocolError;
- }
- } break;
- case State::Wait:
- if (logic->Elapsed(heartBeatPeriod)) {
- SendQuery();
- } else {
-
-
- CheckAndReportAsyncEvents();
- }
- break;
- case State::QuerySent: {
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
- if (expmsg != MessageReady)
- return expmsg;
- }
-
- case State::ContinueFromIdle:
- switch (logic->rsp.paramCode) {
- case ResponseMsgParamCodes::Processing:
- logic->progressCode = static_cast<ProgressCode>(logic->rsp.paramValue);
- logic->errorCode = ErrorCode::OK;
- SendAndUpdateFilamentSensor();
- break;
- case ResponseMsgParamCodes::Error:
-
- logic->errorCode = static_cast<ErrorCode>(logic->rsp.paramValue);
-
-
- SendAndUpdateFilamentSensor();
- return CommandError;
- case ResponseMsgParamCodes::Finished:
- logic->progressCode = ProgressCode::OK;
- state = State::Ready;
- return Finished;
- default:
- return ProtocolError;
- }
- break;
- case State::FilamentSensorStateSent:{
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
- if (expmsg != MessageReady)
- return expmsg;
- SendFINDAQuery();
- } break;
- case State::FINDAReqSent:
- return ProcessFINDAReqSent(Processing, State::Wait);
- case State::ButtonSent:{
-
-
-
-
- SendQuery();
- } break;
- default:
- return ProtocolError;
- }
- return Processing;
- }
- void Idle::Restart() {
- state = State::Ready;
- }
- StepStatus Idle::Step() {
- switch (state) {
- case State::Ready:
- if (logic->Elapsed(heartBeatPeriod)) {
- logic->SendMsg(RequestMsg(RequestMsgCodes::Query, 0));
- state = State::QuerySent;
- return Processing;
- }
- break;
- case State::QuerySent: {
- auto expmsg = logic->ExpectingMessage(linkLayerTimeout);
- if (expmsg != MessageReady)
- return expmsg;
-
-
-
- switch( logic->rsp.request.code ){
- case RequestMsgCodes::Cut:
- case RequestMsgCodes::Eject:
- case RequestMsgCodes::Load:
- case RequestMsgCodes::Mode:
- case RequestMsgCodes::Tool:
- case RequestMsgCodes::Unload:
- if( logic->rsp.paramCode != ResponseMsgParamCodes::Finished ){
- logic->SwitchFromIdleToCommand();
- return Processing;
- }
- default:
- break;
- }
- SendFINDAQuery();
- return Processing;
- } break;
- case State::FINDAReqSent:
- return ProcessFINDAReqSent(Finished, State::Ready);
- default:
- return ProtocolError;
- }
-
-
-
-
-
-
-
- return Finished;
- }
- ProtocolLogic::ProtocolLogic(MMU2Serial *uart)
- : stopped(this)
- , startSeq(this)
- , idle(this)
- , command(this)
- , currentState(&stopped)
- , plannedRq(RequestMsgCodes::unknown, 0)
- , lastUARTActivityMs(0)
- , rsp(RequestMsg(RequestMsgCodes::unknown, 0), ResponseMsgParamCodes::unknown, 0)
- , state(State::Stopped)
- , lrb(0)
- , uart(uart)
- , lastFSensor((uint8_t)WhereIsFilament())
- {}
- void ProtocolLogic::Start() {
- state = State::InitSequence;
- currentState = &startSeq;
- startSeq.Restart();
- }
- void ProtocolLogic::Stop() {
- state = State::Stopped;
- currentState = &stopped;
- }
- void ProtocolLogic::ToolChange(uint8_t slot) {
- PlanGenericRequest(RequestMsg(RequestMsgCodes::Tool, slot));
- }
- void ProtocolLogic::UnloadFilament() {
- PlanGenericRequest(RequestMsg(RequestMsgCodes::Unload, 0));
- }
- void ProtocolLogic::LoadFilament(uint8_t slot) {
- PlanGenericRequest(RequestMsg(RequestMsgCodes::Load, slot));
- }
- void ProtocolLogic::EjectFilament(uint8_t slot) {
- PlanGenericRequest(RequestMsg(RequestMsgCodes::Eject, slot));
- }
- void ProtocolLogic::CutFilament(uint8_t slot){
- PlanGenericRequest(RequestMsg(RequestMsgCodes::Cut, slot));
- }
- void ProtocolLogic::ResetMMU() {
- PlanGenericRequest(RequestMsg(RequestMsgCodes::Reset, 0));
- }
- void ProtocolLogic::Button(uint8_t index){
- PlanGenericRequest(RequestMsg(RequestMsgCodes::Button, index));
- }
- void ProtocolLogic::Home(uint8_t mode){
- PlanGenericRequest(RequestMsg(RequestMsgCodes::Home, mode));
- }
- void ProtocolLogic::PlanGenericRequest(RequestMsg rq) {
- plannedRq = rq;
- if( ! currentState->ExpectsResponse() ){
- ActivatePlannedRequest();
- }
- }
- bool MMU2::ProtocolLogic::ActivatePlannedRequest(){
- if( plannedRq.code == RequestMsgCodes::Button ){
-
- command.SendButton(plannedRq.value);
- plannedRq = RequestMsg(RequestMsgCodes::unknown, 0);
- return true;
- } else if( plannedRq.code != RequestMsgCodes::unknown ){
- currentState = &command;
- command.SetRequestMsg(plannedRq);
- plannedRq = RequestMsg(RequestMsgCodes::unknown, 0);
- command.Restart();
- return true;
- }
- return false;
- }
- void ProtocolLogic::SwitchFromIdleToCommand(){
- currentState = &command;
- command.SetRequestMsg(rsp.request);
-
-
- command.ContinueFromIdle();
- }
- void ProtocolLogic::SwitchToIdle() {
- state = State::Running;
- currentState = &idle;
- idle.Restart();
- }
- void ProtocolLogic::HandleCommunicationTimeout() {
- uart->flush();
- currentState = &startSeq;
- state = State::InitSequence;
- startSeq.Restart();
- }
- bool ProtocolLogic::Elapsed(uint32_t timeout) const {
- return _millis() >= (lastUARTActivityMs + timeout);
- }
- void ProtocolLogic::RecordUARTActivity() {
- lastUARTActivityMs = _millis();
- }
- void ProtocolLogic::RecordReceivedByte(uint8_t c){
- lastReceivedBytes[lrb] = c;
- lrb = (lrb+1) % lastReceivedBytes.size();
- }
- char NibbleToChar(uint8_t c){
- switch (c) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- return c + '0';
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- return (c - 10) + 'a';
- default:
- return 0;
- }
- }
- void ProtocolLogic::FormatLastReceivedBytes(char *dst){
- for(uint8_t i = 0; i < lastReceivedBytes.size(); ++i){
- uint8_t b = lastReceivedBytes[ (lrb-i-1) % lastReceivedBytes.size() ];
- dst[i*3] = NibbleToChar(b >> 4);
- dst[i*3+1] = NibbleToChar(b & 0xf);
- dst[i*3+2] = ' ';
- }
- dst[ (lastReceivedBytes.size() - 1) * 3 + 2] = 0;
- }
- void ProtocolLogic::FormatLastResponseMsgAndClearLRB(char *dst){
- *dst++ = '<';
- for(uint8_t i = 0; i < lrb; ++i){
- uint8_t b = lastReceivedBytes[ i ];
- if( b < 32 )b = '.';
- if( b > 127 )b = '.';
- *dst++ = b;
- }
- *dst = 0;
- lrb = 0;
- }
- void ProtocolLogic::LogRequestMsg(const uint8_t *txbuff, uint8_t size){
- constexpr uint_fast8_t rqs = modules::protocol::Protocol::MaxRequestSize() + 2;
- char tmp[rqs] = ">";
- static char lastMsg[rqs] = "";
- for(uint8_t i = 0; i < size; ++i){
- uint8_t b = txbuff[i];
- if( b < 32 )b = '.';
- if( b > 127 )b = '.';
- tmp[i+1] = b;
- }
- tmp[size+1] = '\n';
- tmp[size+2] = 0;
- if( !strncmp(tmp, ">S0.\n", rqs) && !strncmp(lastMsg, tmp, rqs) ){
-
-
-
-
-
-
- } else {
- MMU2_ECHO_MSG(tmp);
- }
- memcpy(lastMsg, tmp, rqs);
- }
- void MMU2::ProtocolLogic::LogError(const char *reason){
- char lrb[lastReceivedBytes.size() * 3];
- FormatLastReceivedBytes(lrb);
-
- MMU2_ERROR_MSG(reason);
- SERIAL_ECHO(", last bytes: ");
- SERIAL_ECHOLN(lrb);
- }
- void ProtocolLogic::LogResponse(){
- char lrb[lastReceivedBytes.size()];
- FormatLastResponseMsgAndClearLRB(lrb);
- MMU2_ECHO_MSG(lrb);
- SERIAL_ECHOLN();
- }
- StepStatus MMU2::ProtocolLogic::HandleCommError(const char *msg, StepStatus ss){
- protocol.ResetResponseDecoder();
- HandleCommunicationTimeout();
- if( dataTO.Record(ss) ){
- LogError(msg);
- return dataTO.InitialCause();
- } else {
- return Processing;
- }
- }
- StepStatus ProtocolLogic::Step() {
- if( ! currentState->ExpectsResponse() ){
- ActivatePlannedRequest();
- }
- auto currentStatus = currentState->Step();
- switch (currentStatus) {
- case Processing:
-
- break;
- case Finished: {
-
-
-
- bool previousCommandFinished = currentState == &command;
- if( ! ActivatePlannedRequest() ){
- SwitchToIdle();
- } else {
-
- if( ! previousCommandFinished && currentState == &command){
- currentStatus = Processing;
- }
- }
- }
- break;
- case CommandRejected:
-
-
-
- LogError("Command rejected");
- command.Restart();
- break;
- case CommandError:
- LogError("Command Error");
-
-
- break;
- case VersionMismatch:
- LogError("Version mismatch");
- Stop();
- break;
- case ProtocolError:
- currentStatus = HandleCommError("Protocol error", ProtocolError);
- break;
- case CommunicationTimeout:
- currentStatus = HandleCommError("Communication timeout", CommunicationTimeout);
- break;
- default:
- break;
- }
- return currentStatus;
- }
- uint8_t ProtocolLogic::CommandInProgress() const {
- if( currentState != &command )
- return 0;
- return (uint8_t)command.ReqMsg().code;
- }
- bool DropOutFilter::Record(StepStatus ss){
- if( occurrences == maxOccurrences ){
- cause = ss;
- }
- --occurrences;
- return occurrences == 0;
- }
- }
|