Add bit masks for error codes for the TMC drivers
+ add common error handling for idler and selector + improve error handling in command_base + rename ERR1xxxx errors to ERRxxxx (remove the '1')pull/78/head
parent
df2c1ba7fe
commit
751ee46450
|
|
@ -1,25 +1,25 @@
|
|||
#include "command_base.h"
|
||||
#include "../modules/idler.h"
|
||||
#include "../modules/selector.h"
|
||||
|
||||
namespace mi = modules::idler;
|
||||
namespace ms = modules::selector;
|
||||
|
||||
namespace logic {
|
||||
|
||||
bool CommandBase::Step() {
|
||||
// check the global HW errors - may be we should avoid the modules layer and check for the HAL layer errors directly
|
||||
// @@TODO discuss...
|
||||
bool any_error = mi::idler.State() == mi::Idler::Failed;
|
||||
|
||||
// @@TODO check all other HW issues here to be able to respond with the appropriate error code into the printer
|
||||
|
||||
if (any_error) {
|
||||
state = ProgressCode::ERR1TMCInitFailed;
|
||||
error = ErrorCode::TMC_INIT_ERROR;
|
||||
return true; // the HW error prevents us from continuing with the with the state machine
|
||||
// the MMU must be restarted/fixed before continuing
|
||||
} else {
|
||||
return StepInner();
|
||||
if (mi::idler.State() == mi::Idler::Failed) {
|
||||
state = ProgressCode::ERRTMCFailed;
|
||||
error = ErrorCode::TMC_IOIN_MISMATCH;
|
||||
return true; // the HW error prevents us from continuing with the with the state machine - the MMU must be restarted/fixed before continuing
|
||||
} else if (ms::selector.State() == ms::Selector::Failed) {
|
||||
state = ProgressCode::ERRTMCFailed;
|
||||
error = ErrorCode::TMC_IOIN_MISMATCH;
|
||||
return true; // the HW error prevents us from continuing with the with the state machine - the MMU must be restarted/fixed before continuing
|
||||
}
|
||||
|
||||
return StepInner();
|
||||
}
|
||||
|
||||
} // namespace logic
|
||||
|
|
|
|||
|
|
@ -1,25 +1,54 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
/// A complete set of error codes which may be a result of a high-level command/operation
|
||||
/// A complete set of error codes which may be a result of a high-level command/operation.
|
||||
/// This header file shall be included in the printer's firmware as well as a reference,
|
||||
/// therefore the error codes have been extracted to one place
|
||||
enum class ErrorCode : int_fast8_t {
|
||||
RUNNING = 0, ///< the operation is still running
|
||||
OK, ///< the operation finished OK
|
||||
/// therefore the error codes have been extracted to one place.
|
||||
///
|
||||
/// Please note the errors are intentionally coded as "negative" values (highest bit set),
|
||||
/// becase they are a complement to reporting the state of the high-level state machines -
|
||||
/// positive values are considered as normal progress, negative values are errors.
|
||||
///
|
||||
/// Please note, that multiple TMC errors can occur at once, thus they are defined as a bitmask of the higher byte.
|
||||
/// Also, as there are 3 TMC drivers on the board, each error is added a bit for the corresponding TMC -
|
||||
/// TMC_PULLEY_BIT, TMC_SELECTOR_BIT, TMC_IDLER_BIT,
|
||||
/// The resulting error is a bitwise OR over 3 TMC drivers and their status, which should cover most of the situations correctly.
|
||||
enum class ErrorCode : uint_fast16_t {
|
||||
RUNNING = 0x0000, ///< the operation is still running
|
||||
OK = 0x0001, ///< the operation finished OK
|
||||
|
||||
/// Unload Filament related error codes
|
||||
FINDA_DIDNT_SWITCH_ON = -1, ///< FINDA didn't switch on while loading filament - either there is something blocking the metal ball or a cable is broken/disconnected
|
||||
FINDA_DIDNT_SWITCH_OFF = -2, ///< FINDA didn't switch off while unloading filament
|
||||
FINDA_DIDNT_SWITCH_ON = 0x8001, ///< FINDA didn't switch on while loading filament - either there is something blocking the metal ball or a cable is broken/disconnected
|
||||
FINDA_DIDNT_SWITCH_OFF = 0x8002, ///< FINDA didn't switch off while unloading filament
|
||||
|
||||
FSENSOR_DIDNT_SWITCH_ON = -3, ///< Filament sensor didn't switch on while performing LoadFilament
|
||||
FSENSOR_DIDNT_SWITCH_OFF = -4, ///< Filament sensor didn't switch off while performing UnloadFilament
|
||||
FSENSOR_DIDNT_SWITCH_ON = 0x8003, ///< Filament sensor didn't switch on while performing LoadFilament
|
||||
FSENSOR_DIDNT_SWITCH_OFF = 0x8004, ///< Filament sensor didn't switch off while performing UnloadFilament
|
||||
|
||||
FILAMENT_ALREADY_LOADED = -5, ///< cannot perform operation LoadFilament or move the selector as the filament is already loaded
|
||||
FILAMENT_ALREADY_LOADED = 0x8005, ///< cannot perform operation LoadFilament or move the selector as the filament is already loaded
|
||||
|
||||
TMC_INIT_ERROR = -6, ///< TMC driver init error - the MMU cannot move one motor due to a HW problem
|
||||
MMU_NOT_RESPONDING = 0x807e, ///< internal error of the printer - communication with the MMU is not working
|
||||
|
||||
MMU_NOT_RESPONDING = -126, ///< internal error of the printer - communication with the MMU is not working
|
||||
INTERNAL = 0x807f, ///< internal runtime error (software)
|
||||
|
||||
INTERNAL = -127, ///< internal runtime error (software)
|
||||
// TMC bit masks
|
||||
|
||||
TMC_PULLEY_BIT = 0x0080, ///< TMC Pulley bit
|
||||
TMC_SELECTOR_BIT = 0x00A0, ///< TMC Pulley bit
|
||||
TMC_IDLER_BIT = 0x00C0, ///< TMC Pulley bit
|
||||
|
||||
TMC_IOIN_MISMATCH = 0x8100, ///< TMC driver init error - TMC dead or bad communication
|
||||
|
||||
/// TMC driver reset - recoverable, we just need to rehome the axis
|
||||
/// Idler: can be rehomed any time
|
||||
/// Selector: if there is a filament, remove it and rehome, if there is no filament, just rehome
|
||||
/// Pulley: do nothing - for the loading sequence - just restart and move slowly, for the unload sequence just restart
|
||||
TMC_RESET = 0x8200,
|
||||
|
||||
TMC_UNDERVOLTAGE_ON_CHARGE_PUMP = 0x8400, ///< not enough current for the TMC, NOT RECOVERABLE
|
||||
|
||||
TMC_SERIOUS_ERROR = 0x8800, ///< TMC driver serious error coil A or coil B - dangerous to recover
|
||||
TMC_ERROR_A = 0x9000, ///< TMC driver error coil A or coil B - can be recovered
|
||||
|
||||
TMC_OVER_TEMPERATURE_WARN = 0xA000, ///< TMC driver over temperature warning - can be recovered by restarting the driver
|
||||
TMC_OVER_TEMPERATURE_ERROR = 0xC000, ///< TMC driver over temperature error - the TMC probably fried
|
||||
};
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ bool LoadFilament::StepInner() {
|
|||
if (feed.Step()) {
|
||||
if (feed.State() == FeedToFinda::Failed) {
|
||||
// @@TODO - try to repeat 6x - push/pull sequence - probably something to put into feed_to_finda as an option
|
||||
state = ProgressCode::ERR1DisengagingIdler;
|
||||
state = ProgressCode::ERRDisengagingIdler;
|
||||
error = ErrorCode::FINDA_DIDNT_SWITCH_ON;
|
||||
mi::idler.Disengage();
|
||||
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::Color::green, ml::Mode::off);
|
||||
|
|
@ -74,18 +74,18 @@ bool LoadFilament::StepInner() {
|
|||
break;
|
||||
case ProgressCode::OK:
|
||||
return true;
|
||||
case ProgressCode::ERR1DisengagingIdler: // couldn't unload to FINDA
|
||||
case ProgressCode::ERRDisengagingIdler: // couldn't unload to FINDA
|
||||
if (!mi::idler.Engaged()) {
|
||||
state = ProgressCode::ERR1WaitingForUser;
|
||||
state = ProgressCode::ERRWaitingForUser;
|
||||
mu::userInput.Clear(); // remove all buffered events if any just before we wait for some input
|
||||
}
|
||||
return false;
|
||||
case ProgressCode::ERR1WaitingForUser: {
|
||||
case ProgressCode::ERRWaitingForUser: {
|
||||
// waiting for user buttons and/or a command from the printer
|
||||
mu::Event ev = mu::userInput.ConsumeEvent();
|
||||
switch (ev) {
|
||||
case mu::Event::Left: // try to manually load just a tiny bit - help the filament with the pulley
|
||||
state = ProgressCode::ERR1EngagingIdler;
|
||||
state = ProgressCode::ERREngagingIdler;
|
||||
mi::idler.Engage(mg::globals.ActiveSlot());
|
||||
break;
|
||||
case mu::Event::Middle: // try again the whole sequence
|
||||
|
|
@ -102,20 +102,20 @@ bool LoadFilament::StepInner() {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
case ProgressCode::ERR1EngagingIdler:
|
||||
case ProgressCode::ERREngagingIdler:
|
||||
if (mi::idler.Engaged()) {
|
||||
state = ProgressCode::ERR1HelpingFilament;
|
||||
state = ProgressCode::ERRHelpingFilament;
|
||||
mm::motion.PlanMove(mm::Pulley, 450, 5000); //@@TODO constants
|
||||
}
|
||||
return false;
|
||||
case ProgressCode::ERR1HelpingFilament:
|
||||
case ProgressCode::ERRHelpingFilament:
|
||||
if (mf::finda.Pressed()) {
|
||||
// the help was enough to press the FINDA, we are ok, continue normally
|
||||
state = ProgressCode::FeedingToBondtech;
|
||||
error = ErrorCode::OK;
|
||||
} else if (mm::motion.QueueEmpty()) {
|
||||
// helped a bit, but FINDA didn't trigger, return to the main error state
|
||||
state = ProgressCode::ERR1DisengagingIdler;
|
||||
state = ProgressCode::ERRDisengagingIdler;
|
||||
}
|
||||
return false;
|
||||
default: // we got into an unhandled state, better report it
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ enum class ProgressCode : uint_fast8_t {
|
|||
AvoidingGrind,
|
||||
FinishingMoves,
|
||||
|
||||
ERR1DisengagingIdler,
|
||||
ERR1EngagingIdler,
|
||||
ERR1WaitingForUser,
|
||||
ERRDisengagingIdler,
|
||||
ERREngagingIdler,
|
||||
ERRWaitingForUser,
|
||||
ERRInternal,
|
||||
ERR1HelpingFilament,
|
||||
ERR1TMCInitFailed,
|
||||
ERRHelpingFilament,
|
||||
ERRTMCFailed,
|
||||
|
||||
UnloadingFilament,
|
||||
LoadingFilament,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ bool UnloadFilament::StepInner() {
|
|||
if (unl.Step()) {
|
||||
if (unl.State() == UnloadToFinda::Failed) {
|
||||
// couldn't unload to FINDA, report error and wait for user to resolve it
|
||||
state = ProgressCode::ERR1DisengagingIdler;
|
||||
state = ProgressCode::ERRDisengagingIdler;
|
||||
error = ErrorCode::FINDA_DIDNT_SWITCH_OFF;
|
||||
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::red, ml::blink0);
|
||||
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::off);
|
||||
|
|
@ -68,18 +68,18 @@ bool UnloadFilament::StepInner() {
|
|||
ml::leds.SetMode(mg::globals.ActiveSlot(), ml::green, ml::on);
|
||||
}
|
||||
return false;
|
||||
case ProgressCode::ERR1DisengagingIdler: // couldn't unload to FINDA
|
||||
case ProgressCode::ERRDisengagingIdler: // couldn't unload to FINDA
|
||||
if (!mi::idler.Engaged()) {
|
||||
state = ProgressCode::ERR1WaitingForUser;
|
||||
state = ProgressCode::ERRWaitingForUser;
|
||||
mu::userInput.Clear(); // remove all buffered events if any just before we wait for some input
|
||||
}
|
||||
return false;
|
||||
case ProgressCode::ERR1WaitingForUser: {
|
||||
case ProgressCode::ERRWaitingForUser: {
|
||||
// waiting for user buttons and/or a command from the printer
|
||||
mu::Event ev = mu::userInput.ConsumeEvent();
|
||||
switch (ev) {
|
||||
case mu::Event::Left: // try to manually unload just a tiny bit - help the filament with the pulley
|
||||
state = ProgressCode::ERR1EngagingIdler;
|
||||
state = ProgressCode::ERREngagingIdler;
|
||||
mi::idler.Engage(mg::globals.ActiveSlot());
|
||||
break;
|
||||
case mu::Event::Middle: // try again the whole sequence
|
||||
|
|
@ -96,20 +96,20 @@ bool UnloadFilament::StepInner() {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
case ProgressCode::ERR1EngagingIdler:
|
||||
case ProgressCode::ERREngagingIdler:
|
||||
if (mi::idler.Engaged()) {
|
||||
state = ProgressCode::ERR1HelpingFilament;
|
||||
state = ProgressCode::ERRHelpingFilament;
|
||||
mm::motion.PlanMove(mm::Pulley, 450, 5000);
|
||||
}
|
||||
return false;
|
||||
case ProgressCode::ERR1HelpingFilament:
|
||||
case ProgressCode::ERRHelpingFilament:
|
||||
if (!mf::finda.Pressed()) {
|
||||
// the help was enough to depress the FINDA, we are ok, continue normally
|
||||
state = ProgressCode::DisengagingIdler;
|
||||
error = ErrorCode::OK;
|
||||
} else if (mm::motion.QueueEmpty()) {
|
||||
// helped a bit, but FINDA didn't trigger, return to the main error state
|
||||
state = ProgressCode::ERR1DisengagingIdler;
|
||||
state = ProgressCode::ERRDisengagingIdler;
|
||||
}
|
||||
return false;
|
||||
case ProgressCode::OK:
|
||||
|
|
|
|||
|
|
@ -207,18 +207,18 @@ void ReportVersion(const mp::RequestMsg &rq) {
|
|||
|
||||
void ReportRunningCommand() {
|
||||
mp::ResponseMsgParamCodes commandStatus;
|
||||
uint8_t value = 0;
|
||||
uint16_t value = 0;
|
||||
switch (currentCommand->Error()) {
|
||||
case ErrorCode::RUNNING:
|
||||
commandStatus = mp::ResponseMsgParamCodes::Processing;
|
||||
value = (uint8_t)currentCommand->State();
|
||||
value = (uint16_t)currentCommand->State();
|
||||
break;
|
||||
case ErrorCode::OK:
|
||||
commandStatus = mp::ResponseMsgParamCodes::Finished;
|
||||
break;
|
||||
default:
|
||||
commandStatus = mp::ResponseMsgParamCodes::Error;
|
||||
value = (uint8_t)currentCommand->Error();
|
||||
value = (uint16_t)currentCommand->Error();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ target_sources(
|
|||
idler.cpp
|
||||
leds.cpp
|
||||
motion.cpp
|
||||
movable_base.cpp
|
||||
permanent_storage.cpp
|
||||
selector.cpp
|
||||
timebase.cpp
|
||||
|
|
|
|||
|
|
@ -11,57 +11,34 @@ Idler idler;
|
|||
|
||||
namespace mm = modules::motion;
|
||||
|
||||
Idler::EngageDisengage Idler::Disengage() {
|
||||
if (state == Moving)
|
||||
return EngageDisengage::Refused;
|
||||
void Idler::PrepareMoveToPlannedSlot() {
|
||||
mm::motion.PlanMoveTo<mm::Idler>(SlotPosition(plannedSlot), 1000._I_deg_s); // @@TODO
|
||||
}
|
||||
|
||||
Idler::OperationResult Idler::Disengage() {
|
||||
if (state == Moving)
|
||||
return OperationResult::Refused;
|
||||
|
||||
plannedSlot = IdleSlotIndex();
|
||||
plannedEngage = false;
|
||||
|
||||
if (!Engaged())
|
||||
return true;
|
||||
return OperationResult::Accepted;
|
||||
|
||||
mm::motion.InitAxis(mm::Idler);
|
||||
// plan move to idle position
|
||||
mm::motion.PlanMoveTo<mm::Idler>(SlotPosition(IdleSlotIndex()), 1000._I_deg_s); // @@TODO
|
||||
state = Moving;
|
||||
return true;
|
||||
// return EngageDisengage::Accepted;
|
||||
//
|
||||
// if (!mm::motion.InitAxis(mm::Idler)) {
|
||||
// state = Failed;
|
||||
// return EngageDisengage::Failed;
|
||||
// } else {
|
||||
// // plan move to idle position
|
||||
// mm::motion.PlanMove(mm::Idler, config::idlerSlotPositions[IdleSlotIndex()] - mm::motion.Position(mm::Idler), 1000); // @@TODO
|
||||
// state = Moving;
|
||||
// return EngageDisengage::Accepted;
|
||||
// }
|
||||
return InitMovement(mm::Idler);
|
||||
}
|
||||
|
||||
Idler::EngageDisengage Idler::Engage(uint8_t slot) {
|
||||
Idler::OperationResult Idler::Engage(uint8_t slot) {
|
||||
if (state == Moving)
|
||||
return EngageDisengage::Refused;
|
||||
return OperationResult::Refused;
|
||||
|
||||
plannedSlot = slot;
|
||||
plannedEngage = true;
|
||||
|
||||
if (Engaged())
|
||||
return true;
|
||||
return OperationResult::Accepted;
|
||||
|
||||
mm::motion.InitAxis(mm::Idler);
|
||||
mm::motion.PlanMoveTo<mm::Idler>(SlotPosition(slot), 1000._I_deg_s); // @@TODO
|
||||
state = Moving;
|
||||
return true;
|
||||
// return EngageDisengage::Accepted;
|
||||
//
|
||||
// if (!mm::motion.InitAxis(mm::Idler)) {
|
||||
// state = Failed;
|
||||
// return EngageDisengage::Failed;
|
||||
// } else {
|
||||
// mm::motion.PlanMove(mm::Idler, config::idlerSlotPositions[slot] - mm::motion.Position(mm::Idler), 1000); // @@TODO
|
||||
// state = Moving;
|
||||
// return EngageDisengage::Accepted;
|
||||
// }
|
||||
return InitMovement(mm::Idler);
|
||||
}
|
||||
|
||||
bool Idler::Home() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include "../config/config.h"
|
||||
#include "../modules/axisunit.h"
|
||||
#include "axisunit.h"
|
||||
#include "movable_base.h"
|
||||
|
||||
namespace modules {
|
||||
|
||||
|
|
@ -10,37 +11,21 @@ namespace idler {
|
|||
namespace mm = modules::motion;
|
||||
|
||||
/// The Idler model handles asynchronnous Engaging / Disengaging operations and keeps track of idler's current state.
|
||||
class Idler {
|
||||
class Idler : public motion::MovableBase {
|
||||
public:
|
||||
/// Internal states of idler's state machine
|
||||
enum {
|
||||
Ready = 0, // intentionally set as zero in order to allow zeroing the Idler structure upon startup -> avoid explicit initialization code
|
||||
Moving,
|
||||
Failed
|
||||
};
|
||||
|
||||
inline constexpr Idler()
|
||||
: state(Ready)
|
||||
: MovableBase()
|
||||
, plannedEngage(false)
|
||||
, plannedSlot(0)
|
||||
, currentSlot(0)
|
||||
, currentlyEngaged(false) {}
|
||||
|
||||
/// Engage/Disengage return values
|
||||
enum class EngageDisengage : uint8_t {
|
||||
Accepted, ///< the operation has been successfully started
|
||||
Refused, ///< another operation is currently underway, cannot start a new one
|
||||
Failed ///< the operation could not been started due to HW issues
|
||||
};
|
||||
|
||||
/// Plan engaging of the idler to a specific filament slot
|
||||
/// @param slot index to be activated
|
||||
/// @returns #EngageDisengage
|
||||
EngageDisengage Engage(uint8_t slot);
|
||||
OperationResult Engage(uint8_t slot);
|
||||
|
||||
/// Plan disengaging of the idler, i.e. parking the idler
|
||||
/// @returns #EngageDisengage
|
||||
EngageDisengage Disengage();
|
||||
OperationResult Disengage();
|
||||
|
||||
/// Plan homing of the idler axis
|
||||
/// @returns false in case an operation is already underway
|
||||
|
|
@ -55,9 +40,6 @@ public:
|
|||
/// state machines to use this call as a waiting condition for the desired state of the idler
|
||||
inline bool Engaged() const { return currentlyEngaged; }
|
||||
|
||||
/// @returns currently active slot
|
||||
inline uint8_t Slot() const { return currentSlot; }
|
||||
|
||||
/// @returns predefined positions of individual slots
|
||||
static constexpr mm::I_pos_t SlotPosition(uint8_t slot) {
|
||||
return mm::unitToAxisUnit<mm::I_pos_t>(config::idlerSlotPositions[slot]);
|
||||
|
|
@ -66,19 +48,14 @@ public:
|
|||
/// @returns the index of idle position of the idler, usually 5 in case of 0-4 valid indices of filament slots
|
||||
inline static constexpr uint8_t IdleSlotIndex() { return config::toolCount; }
|
||||
|
||||
/// @returns internal state of the Idler
|
||||
inline uint8_t State() const { return state; }
|
||||
protected:
|
||||
virtual void PrepareMoveToPlannedSlot() override;
|
||||
|
||||
private:
|
||||
/// internal state of the automaton
|
||||
uint8_t state;
|
||||
|
||||
/// direction of travel - engage/disengage
|
||||
bool plannedEngage;
|
||||
uint8_t plannedSlot;
|
||||
|
||||
/// current state
|
||||
uint8_t currentSlot;
|
||||
bool currentlyEngaged;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
#include "movable_base.h"
|
||||
#include "motion.h"
|
||||
|
||||
namespace modules {
|
||||
namespace motion {
|
||||
|
||||
MovableBase::OperationResult MovableBase::InitMovement(config::Axis axis) {
|
||||
if (motion.InitAxis(axis)) {
|
||||
PrepareMoveToPlannedSlot();
|
||||
state = Moving;
|
||||
return OperationResult::Accepted;
|
||||
} else {
|
||||
state = Failed;
|
||||
return OperationResult::Failed;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace motion
|
||||
} // namespace modules
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "../config/axis.h"
|
||||
|
||||
namespace modules {
|
||||
namespace motion {
|
||||
|
||||
/// Base class for movable modules - #Idler and #Selector contains the common code
|
||||
class MovableBase {
|
||||
public:
|
||||
/// Internal states of the state machine
|
||||
enum {
|
||||
Ready = 0, // intentionally set as zero in order to allow zeroing the Idler structure upon startup -> avoid explicit initialization code
|
||||
Moving,
|
||||
Failed
|
||||
};
|
||||
|
||||
/// Operation (Engage/Disengage/MoveToSlot) return values
|
||||
enum class OperationResult : uint8_t {
|
||||
Accepted, ///< the operation has been successfully started
|
||||
Refused, ///< another operation is currently underway, cannot start a new one
|
||||
Failed ///< the operation could not been started due to HW issues
|
||||
};
|
||||
|
||||
inline constexpr MovableBase()
|
||||
: state(Ready)
|
||||
, plannedSlot(0)
|
||||
, currentSlot(0) {}
|
||||
|
||||
/// virtual ~MovableBase(); intentionally disabled, see description in logic::CommandBase
|
||||
|
||||
/// @returns currently active slot
|
||||
/// this state is updated only when a planned move is successfully finished, so it is safe for higher-level
|
||||
/// state machines to use this call as a waiting condition for the desired state of the derive class (idler/selector)
|
||||
inline uint8_t Slot() const { return currentSlot; }
|
||||
|
||||
/// @returns internal state of the state machine
|
||||
inline uint8_t State() const { return state; }
|
||||
|
||||
protected:
|
||||
/// internal state of the automaton
|
||||
uint8_t state;
|
||||
|
||||
/// planned slot - where to move to
|
||||
uint8_t plannedSlot;
|
||||
|
||||
/// current slot
|
||||
uint8_t currentSlot;
|
||||
|
||||
virtual void PrepareMoveToPlannedSlot() = 0;
|
||||
|
||||
OperationResult InitMovement(config::Axis axis);
|
||||
};
|
||||
|
||||
} // namespace motion
|
||||
} // namespace modules
|
||||
|
|
@ -197,7 +197,7 @@ uint8_t Protocol::EncodeResponseVersion(const RequestMsg &msg, uint8_t value, ui
|
|||
return dst - txbuff + 1;
|
||||
}
|
||||
|
||||
uint8_t Protocol::EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint8_t value, uint8_t *txbuff) {
|
||||
uint8_t Protocol::EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint16_t value, uint8_t *txbuff) {
|
||||
txbuff[0] = (uint8_t)msg.code;
|
||||
txbuff[1] = msg.value + '0';
|
||||
txbuff[2] = ' ';
|
||||
|
|
@ -209,10 +209,21 @@ uint8_t Protocol::EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMs
|
|||
} else if (value < 100) {
|
||||
*dst++ = value / 10 + '0';
|
||||
*dst++ = value % 10 + '0';
|
||||
} else {
|
||||
} else if (value < 1000) {
|
||||
*dst++ = value / 100 + '0';
|
||||
*dst++ = (value / 10) % 10 + '0';
|
||||
*dst++ = value % 10 + '0';
|
||||
} else if (value < 10000) {
|
||||
*dst++ = value / 1000 + '0';
|
||||
*dst++ = (value / 100) % 100 + '0';
|
||||
*dst++ = (value / 10) % 10 + '0';
|
||||
*dst++ = value % 10 + '0';
|
||||
} else {
|
||||
*dst++ = value / 10000 + '0';
|
||||
*dst++ = (value / 1000) % 1000 + '0';
|
||||
*dst++ = (value / 100) % 100 + '0';
|
||||
*dst++ = (value / 10) % 10 + '0';
|
||||
*dst++ = value % 10 + '0';
|
||||
}
|
||||
}
|
||||
*dst = '\n';
|
||||
|
|
|
|||
|
|
@ -52,12 +52,12 @@ struct RequestMsg {
|
|||
struct ResponseMsg {
|
||||
RequestMsg request; ///< response is always preceeded by the request message
|
||||
ResponseMsgParamCodes paramCode; ///< code of the parameter
|
||||
uint8_t paramValue; ///< value of the parameter
|
||||
uint16_t paramValue; ///< value of the parameter
|
||||
|
||||
/// @param request the source request message this response is a reply to
|
||||
/// @param paramCode code of the parameter
|
||||
/// @param paramValue value of the parameter
|
||||
inline ResponseMsg(RequestMsg request, ResponseMsgParamCodes paramCode, uint8_t paramValue)
|
||||
inline ResponseMsg(RequestMsg request, ResponseMsgParamCodes paramCode, uint16_t paramValue)
|
||||
: request(request)
|
||||
, paramCode(paramCode)
|
||||
, paramValue(paramValue) {}
|
||||
|
|
@ -123,7 +123,7 @@ public:
|
|||
/// @param value related to status of operation(e.g. error code or progress)
|
||||
/// @param txbuff where to format the message
|
||||
/// @returns number of bytes written into txbuff
|
||||
static uint8_t EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint8_t value, uint8_t *txbuff);
|
||||
static uint8_t EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint16_t value, uint8_t *txbuff);
|
||||
|
||||
/// @returns the most recently lexed request message
|
||||
inline const RequestMsg GetRequestMsg() const { return requestMsg; }
|
||||
|
|
|
|||
|
|
@ -11,19 +11,20 @@ Selector selector;
|
|||
|
||||
namespace mm = modules::motion;
|
||||
|
||||
bool Selector::MoveToSlot(uint8_t slot) {
|
||||
void Selector::PrepareMoveToPlannedSlot() {
|
||||
mm::motion.PlanMoveTo<mm::Selector>(SlotPosition(plannedSlot), 1000.0_S_mm_s); // @@TODO
|
||||
}
|
||||
|
||||
Selector::OperationResult Selector::MoveToSlot(uint8_t slot) {
|
||||
if (state == Moving)
|
||||
return false;
|
||||
return OperationResult::Refused;
|
||||
|
||||
plannedSlot = slot;
|
||||
|
||||
if (currentSlot == slot)
|
||||
return true;
|
||||
return OperationResult::Accepted;
|
||||
|
||||
mm::motion.InitAxis(mm::Selector);
|
||||
mm::motion.PlanMoveTo<mm::Selector>(SlotPosition(slot), 1000.0_S_mm_s); // @@TODO
|
||||
state = Moving;
|
||||
return true;
|
||||
return InitMovement(mm::Selector);
|
||||
}
|
||||
|
||||
bool Selector::Home() {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include "../config/config.h"
|
||||
#include "../modules/axisunit.h"
|
||||
#include "axisunit.h"
|
||||
#include "movable_base.h"
|
||||
|
||||
namespace modules {
|
||||
|
||||
|
|
@ -10,24 +11,15 @@ namespace selector {
|
|||
namespace mm = modules::motion;
|
||||
|
||||
/// The selector model - handles asynchronnous move operations between filament individual slots and keeps track of selector's current state.
|
||||
class Selector {
|
||||
class Selector : public mm::MovableBase {
|
||||
public:
|
||||
/// Internal states of selector's state machine
|
||||
enum {
|
||||
Ready = 0,
|
||||
Moving,
|
||||
Failed
|
||||
};
|
||||
|
||||
inline constexpr Selector()
|
||||
: state(Ready)
|
||||
, plannedSlot(0)
|
||||
, currentSlot(0) {}
|
||||
: MovableBase() {}
|
||||
|
||||
/// Plan move of the selector to a specific filament slot
|
||||
/// @param slot index to move to
|
||||
/// @returns false in case an operation is already underway
|
||||
bool MoveToSlot(uint8_t slot);
|
||||
OperationResult MoveToSlot(uint8_t slot);
|
||||
|
||||
/// Plan homing of the selector's axis
|
||||
/// @returns false in case an operation is already underway
|
||||
|
|
@ -37,11 +29,6 @@ public:
|
|||
/// @returns true if the selector is ready to accept new commands (i.e. it has finished the last operation)
|
||||
bool Step();
|
||||
|
||||
/// @returns the current slot of selector
|
||||
/// this state is updated only when a planned move is successfully finished, so it is safe for higher-level
|
||||
/// state machines to use this call as a waiting condition for the desired state of the selector
|
||||
inline uint8_t Slot() const { return currentSlot; }
|
||||
|
||||
/// @returns predefined positions of individual slots
|
||||
static constexpr mm::S_pos_t SlotPosition(uint8_t slot) {
|
||||
return mm::unitToAxisUnit<mm::S_pos_t>(config::selectorSlotPositions[slot]);
|
||||
|
|
@ -50,13 +37,10 @@ public:
|
|||
/// @returns the index of idle position of the selector, usually 5 in case of 0-4 valid indices of filament slots
|
||||
inline static constexpr uint8_t IdleSlotIndex() { return config::toolCount; }
|
||||
|
||||
private:
|
||||
/// internal state of the automaton
|
||||
uint8_t state;
|
||||
uint8_t plannedSlot;
|
||||
protected:
|
||||
virtual void PrepareMoveToPlannedSlot() override;
|
||||
|
||||
/// current state
|
||||
uint8_t currentSlot;
|
||||
private:
|
||||
};
|
||||
|
||||
/// The one and only instance of Selector in the FW
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ add_executable(
|
|||
${CMAKE_SOURCE_DIR}/src/modules/globals.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/idler.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/leds.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/selector.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ add_executable(
|
|||
${CMAKE_SOURCE_DIR}/src/modules/globals.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/idler.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/leds.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/selector.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ add_executable(
|
|||
${CMAKE_SOURCE_DIR}/src/modules/globals.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/idler.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/leds.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/selector.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ add_executable(
|
|||
${CMAKE_SOURCE_DIR}/src/modules/globals.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/idler.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/leds.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/selector.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ add_executable(
|
|||
${CMAKE_SOURCE_DIR}/src/modules/globals.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/idler.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/leds.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/selector.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp
|
||||
|
|
|
|||
|
|
@ -96,11 +96,11 @@ void FailedLoadToFinda(uint8_t slot, logic::LoadFilament &lf) {
|
|||
// Stage 2 - feeding to finda
|
||||
// we'll assume the finda is defective here and does not trigger
|
||||
REQUIRE(WhileTopState(lf, ProgressCode::FeedingToFinda, 5000));
|
||||
REQUIRE(VerifyState(lf, false, slot, slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_ON, ProgressCode::ERR1DisengagingIdler));
|
||||
REQUIRE(VerifyState(lf, false, slot, slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_ON, ProgressCode::ERRDisengagingIdler));
|
||||
|
||||
// Stage 3 - disengaging idler in error mode
|
||||
REQUIRE(WhileTopState(lf, ProgressCode::ERR1DisengagingIdler, 5000));
|
||||
REQUIRE(VerifyState(lf, false, mi::Idler::IdleSlotIndex(), slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_ON, ProgressCode::ERR1WaitingForUser));
|
||||
REQUIRE(WhileTopState(lf, ProgressCode::ERRDisengagingIdler, 5000));
|
||||
REQUIRE(VerifyState(lf, false, mi::Idler::IdleSlotIndex(), slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_ON, ProgressCode::ERRWaitingForUser));
|
||||
}
|
||||
|
||||
void FailedLoadToFindaResolveHelp(uint8_t slot, logic::LoadFilament &lf) {
|
||||
|
|
@ -119,12 +119,12 @@ void FailedLoadToFindaResolveHelp(uint8_t slot, logic::LoadFilament &lf) {
|
|||
lf.Step();
|
||||
}
|
||||
|
||||
REQUIRE(VerifyState(lf, false, mi::Idler::IdleSlotIndex(), slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_ON, ProgressCode::ERR1EngagingIdler));
|
||||
REQUIRE(VerifyState(lf, false, mi::Idler::IdleSlotIndex(), slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_ON, ProgressCode::ERREngagingIdler));
|
||||
|
||||
// Stage 4 - engage the idler
|
||||
REQUIRE(WhileTopState(lf, ProgressCode::ERR1EngagingIdler, 5000));
|
||||
REQUIRE(WhileTopState(lf, ProgressCode::ERREngagingIdler, 5000));
|
||||
|
||||
REQUIRE(VerifyState(lf, false, slot, slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_ON, ProgressCode::ERR1HelpingFilament));
|
||||
REQUIRE(VerifyState(lf, false, slot, slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_ON, ProgressCode::ERRHelpingFilament));
|
||||
}
|
||||
|
||||
void FailedLoadToFindaResolveHelpFindaTriggered(uint8_t slot, logic::LoadFilament &lf) {
|
||||
|
|
@ -135,7 +135,7 @@ void FailedLoadToFindaResolveHelpFindaTriggered(uint8_t slot, logic::LoadFilamen
|
|||
if(step == 100){ // on 100th step make FINDA trigger
|
||||
hal::adc::SetADC(config::findaADCIndex, 1023);
|
||||
}
|
||||
return lf.TopLevelState() == ProgressCode::ERR1HelpingFilament; },
|
||||
return lf.TopLevelState() == ProgressCode::ERRHelpingFilament; },
|
||||
5000));
|
||||
|
||||
REQUIRE(VerifyState(lf, false, slot, slot, true, ml::off, ml::blink0, ErrorCode::OK, ProgressCode::FeedingToBondtech));
|
||||
|
|
@ -143,9 +143,9 @@ void FailedLoadToFindaResolveHelpFindaTriggered(uint8_t slot, logic::LoadFilamen
|
|||
|
||||
void FailedLoadToFindaResolveHelpFindaDidntTrigger(uint8_t slot, logic::LoadFilament &lf) {
|
||||
// Stage 5 - move the pulley a bit - no FINDA change
|
||||
REQUIRE(WhileTopState(lf, ProgressCode::ERR1HelpingFilament, 5000));
|
||||
REQUIRE(WhileTopState(lf, ProgressCode::ERRHelpingFilament, 5000));
|
||||
|
||||
REQUIRE(VerifyState(lf, false, slot, slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_ON, ProgressCode::ERR1DisengagingIdler));
|
||||
REQUIRE(VerifyState(lf, false, slot, slot, false, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_ON, ProgressCode::ERRDisengagingIdler));
|
||||
}
|
||||
|
||||
TEST_CASE("load_filament::failed_load_to_finda_0-4_resolve_help_second_ok", "[load_filament]") {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ add_executable(
|
|||
${CMAKE_SOURCE_DIR}/src/modules/globals.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/idler.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/leds.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/selector.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ add_executable(
|
|||
${CMAKE_SOURCE_DIR}/src/modules/globals.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/idler.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/leds.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/selector.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp
|
||||
|
|
|
|||
|
|
@ -158,10 +158,10 @@ void FindaDidntTriggerCommonSetup(uint8_t slot, logic::UnloadFilament &uf) {
|
|||
// no change in selector's position
|
||||
// FINDA still on
|
||||
// red LED should blink, green LED should be off
|
||||
REQUIRE(VerifyState(uf, true, slot, slot, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERR1DisengagingIdler));
|
||||
REQUIRE(VerifyState(uf, true, slot, slot, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERRDisengagingIdler));
|
||||
|
||||
// Stage 2 - idler should get disengaged
|
||||
REQUIRE(WhileTopState(uf, ProgressCode::ERR1DisengagingIdler, 5000));
|
||||
REQUIRE(WhileTopState(uf, ProgressCode::ERRDisengagingIdler, 5000));
|
||||
|
||||
// we still think we have filament loaded at this stage
|
||||
// idler should have been disengaged
|
||||
|
|
@ -169,7 +169,7 @@ void FindaDidntTriggerCommonSetup(uint8_t slot, logic::UnloadFilament &uf) {
|
|||
// FINDA still on
|
||||
// red LED should blink
|
||||
// green LED should be off
|
||||
REQUIRE(VerifyState(uf, true, mi::Idler::IdleSlotIndex(), slot, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERR1WaitingForUser));
|
||||
REQUIRE(VerifyState(uf, true, mi::Idler::IdleSlotIndex(), slot, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERRWaitingForUser));
|
||||
}
|
||||
|
||||
void FindaDidntTriggerResolveHelp(uint8_t slot, logic::UnloadFilament &uf) {
|
||||
|
|
@ -194,17 +194,17 @@ void FindaDidntTriggerResolveHelp(uint8_t slot, logic::UnloadFilament &uf) {
|
|||
// no change in selector's position
|
||||
// FINDA still on
|
||||
// red LED should blink, green LED should be off
|
||||
REQUIRE(VerifyState(uf, true, mi::Idler::IdleSlotIndex(), slot, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERR1EngagingIdler));
|
||||
REQUIRE(VerifyState(uf, true, mi::Idler::IdleSlotIndex(), slot, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERREngagingIdler));
|
||||
|
||||
// Stage 4 - engage the idler
|
||||
REQUIRE(WhileTopState(uf, ProgressCode::ERR1EngagingIdler, 5000));
|
||||
REQUIRE(WhileTopState(uf, ProgressCode::ERREngagingIdler, 5000));
|
||||
|
||||
// we still think we have filament loaded at this stage
|
||||
// idler should be engaged
|
||||
// no change in selector's position
|
||||
// FINDA still on
|
||||
// red LED should blink, green LED should be off
|
||||
REQUIRE(VerifyState(uf, true, slot, slot, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERR1HelpingFilament));
|
||||
REQUIRE(VerifyState(uf, true, slot, slot, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERRHelpingFilament));
|
||||
}
|
||||
|
||||
void FindaDidntTriggerResolveHelpFindaTriggered(uint8_t slot, logic::UnloadFilament &uf) {
|
||||
|
|
@ -215,7 +215,7 @@ void FindaDidntTriggerResolveHelpFindaTriggered(uint8_t slot, logic::UnloadFilam
|
|||
if(step == 100){ // on 100th step make FINDA trigger
|
||||
hal::adc::SetADC(config::findaADCIndex, 0);
|
||||
}
|
||||
return uf.TopLevelState() == ProgressCode::ERR1HelpingFilament; },
|
||||
return uf.TopLevelState() == ProgressCode::ERRHelpingFilament; },
|
||||
5000));
|
||||
|
||||
// we still think we have filament loaded at this stage
|
||||
|
|
@ -228,14 +228,14 @@ void FindaDidntTriggerResolveHelpFindaTriggered(uint8_t slot, logic::UnloadFilam
|
|||
|
||||
void FindaDidntTriggerResolveHelpFindaDidntTrigger(uint8_t slot, logic::UnloadFilament &uf) {
|
||||
// Stage 5 - move the pulley a bit - no FINDA change
|
||||
REQUIRE(WhileTopState(uf, ProgressCode::ERR1HelpingFilament, 5000));
|
||||
REQUIRE(WhileTopState(uf, ProgressCode::ERRHelpingFilament, 5000));
|
||||
|
||||
// we still think we have filament loaded at this stage
|
||||
// idler should be engaged
|
||||
// no change in selector's position
|
||||
// FINDA still pressed
|
||||
// red LED should blink, green LED should be off
|
||||
REQUIRE(VerifyState(uf, true, slot, slot, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERR1DisengagingIdler));
|
||||
REQUIRE(VerifyState(uf, true, slot, slot, true, ml::off, ml::blink0, ErrorCode::FINDA_DIDNT_SWITCH_OFF, ProgressCode::ERRDisengagingIdler));
|
||||
}
|
||||
|
||||
TEST_CASE("unload_filament::finda_didnt_trigger_resolve_help_second_ok", "[unload_filament]") {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ add_executable(
|
|||
${CMAKE_SOURCE_DIR}/src/modules/globals.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/idler.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/leds.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/movable_base.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/permanent_storage.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/selector.cpp
|
||||
${CMAKE_SOURCE_DIR}/src/modules/user_input.cpp
|
||||
|
|
|
|||
Loading…
Reference in New Issue