Introduce Doxyfile + fix modules documentation

pull/37/head
D.R.racer 2021-06-25 11:39:37 +02:00 committed by DRracer
parent f6e5d4ae76
commit c15b1d59c4
15 changed files with 2734 additions and 140 deletions

2494
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
///
/// Which state machines are high-level? Those which are being initiated either by a command over the serial line or from a button
/// - they report their progress to the printer
/// - they can be composed of other sub automatons
/// - they can be composed of other sub automata
namespace logic {

View File

@ -3,12 +3,12 @@
#include <stdint.h>
#include "debouncer.h"
/// Buttons are built on top of the raw ADC API
/// This layer should contain debouncing of buttons and their logical interpretation
namespace modules {
/// The buttons namespace provides all necessary facilities related to the logical model of the physical buttons device the MMU unit.
namespace buttons {
/// A model of a single button, performs automatic debouncing on top of the raw ADC API
struct Button : public debounce::Debouncer {
inline constexpr Button()
: debounce::Debouncer(debounce) {}
@ -18,12 +18,14 @@ private:
constexpr static const uint16_t debounce = 100;
};
/// Enum of buttons - used also as indices in an array of buttons to keep the code size tight.
enum {
Left = 0,
Middle,
Right
};
/// A model of the 3 buttons on the MMU unit
class Buttons {
constexpr static const uint8_t N = 3; ///< number of buttons currently supported
constexpr static const uint8_t adc = 1; ///< ADC index - will be some define or other constant later on
@ -31,11 +33,11 @@ class Buttons {
public:
inline constexpr Buttons() = default;
/// State machine step - reads the ADC, processes debouncing, updates states of individual buttons
/// Performs one step of the state machine - reads the ADC, processes debouncing, updates states of individual buttons
void Step();
/// @returns true if button at index is pressed
/// @@TODO add range checking if necessary
/// @param index of the button to check
inline bool ButtonPressed(uint8_t index) const { return buttons[index].Pressed(); }
/// @returns true if any of the button is pressed
@ -55,6 +57,7 @@ private:
static int8_t DecodeADC(uint16_t rawADC);
};
/// The one and only instance of Buttons in the FW
extern Buttons buttons;
} // namespace buttons

View File

@ -1,15 +1,17 @@
/// A generic debouncing algorithm
#pragma once
#include <stdint.h>
namespace modules {
/// The debounce namespace provides a generic debouncing algorithm.
namespace debounce {
/// Implements debouncing on 2-state logic variables (true/false, high/low, on/off, pressed/unpressed)
/// Intentionally not modelled as a template to avoid code bloat
class Debouncer {
public:
/// @param debounceTimeout initial debounce timeout in milliseconds @@TODO
/// - after what time of having a pressed level the debouncer considers the level stable enough to report the Pressed state.
inline constexpr Debouncer(uint8_t debounceTimeout)
: timeLastChange(0)
, debounceTimeout(debounceTimeout) {}

View File

@ -3,8 +3,11 @@
#include "debouncer.h"
namespace modules {
/// The finda namespace provides all necessary facilities related to the logical model of the FINDA device the MMU unit.
namespace finda {
/// A model of the FINDA - basically acts as a button with pre-set debouncing
class FINDA : protected debounce::Debouncer {
public:
/// time interval for debouncing @@TODO specify units
@ -14,10 +17,14 @@ public:
inline constexpr FINDA()
: debounce::Debouncer(debounce) {};
/// Performs one step of the state machine - reads the ADC, processes debouncing, updates states of FINDA
void Step();
using debounce::Debouncer::Pressed;
};
/// The one and only instance of FINDA in the FW
extern FINDA finda;
} // namespace finda

View File

@ -2,21 +2,25 @@
#include <stdint.h>
#include "debouncer.h"
/// External module - model of printer's fsensor
namespace modules {
/// The fsensor namespace provides all necessary facilities related to the logical model of the printer's filamens sensor device.
namespace fsensor {
/// the debouncer is probably not necessary, but it has all the necessary functionality for modelling of the fsensor
/// External module - model of printer's filament sensor
/// The debouncer is probably not necessary, but it has all the necessary functionality for modelling of the filament sensor
class FSensor : protected debounce::Debouncer {
public:
inline constexpr FSensor()
: debounce::Debouncer(debounce)
, reportedFSensorState(false) {};
/// Performs one step of the state machine - processes a change-of-state message if any arrived
void Step();
using debounce::Debouncer::Pressed;
/// Records a change of state of filament sensor when arrived via communication
void ProcessMessage(bool on);
private:
@ -25,7 +29,8 @@ private:
bool reportedFSensorState; ///< reported state that came from the printer via a communication message
};
/// The one and only instance of printer's filament sensor in the FW
extern FSensor fsensor;
} // namespace finda
} // namespace fsensor
} // namespace modules

View File

@ -2,16 +2,35 @@
#include <stdint.h>
namespace modules {
/// The globals namespace provides all necessary facilities related to keeping track of global state of the firmware.
namespace globals {
/// Globals keep track of global state variables in the firmware.
/// So far only Active slot and Filament loaded variables are used.
class Globals {
public:
/// Initializes the global storage hive - basically looks into EEPROM to gather information.
void Init();
/// @returns active filament slot on the MMU unit
/// Slots are numbered 0-4
uint8_t ActiveSlot() const;
/// Sets the active slot, usually after some command/operation.
/// Also updates the EEPROM records accordingly
/// @param newActiveSlot the new slot index to set
void SetActiveSlot(uint8_t newActiveSlot);
/// @returns true if filament is considered as loaded
/// @@TODO this may change meaning slightly as the MMU is primarily concerned
/// about whether a piece of filament is stock up of a PTFE tube.
/// If that's true, we cannot move the selector.
bool FilamentLoaded() const;
/// Sets the filament loaded flag value, usually after some command/operation.
/// Also updates the EEPROM records accordingly
/// @param newFilamentLoaded new state
void SetFilamentLoaded(bool newFilamentLoaded);
private:
@ -19,6 +38,7 @@ private:
bool filamentLoaded;
};
/// The one and only instance of global state variables
extern Globals globals;
} // namespace globals

View File

@ -1,15 +1,15 @@
#pragma once
#include <stdint.h>
/// Idler model
/// Handles asynchronnous Engaging / Disengaging operations
/// Keeps track of idler's current state
namespace modules {
/// The idler namespace provides all necessary facilities related to the logical model of the idler device of the MMU unit.
namespace idler {
/// The Idler model handles asynchronnous Engaging / Disengaging operations and keeps track of idler's current state.
class Idler {
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,
@ -23,15 +23,20 @@ public:
, currentSlot(0)
, currentlyEngaged(false) {}
// public operations on the idler
/// @retuns false in case an operation is already underway
/// Plan engaging of the idler to a specific filament slot
/// @param slot index to be activated
/// @returns false in case an operation is already underway
bool Engage(uint8_t slot);
/// @retuns false in case an operation is already underway
/// Plan disengaging of the idler, i.e. parking the idler
/// @returns false in case an operation is already underway
bool Disengage();
/// @retuns false in case an operation is already underway
/// Plan homing of the idler axis
/// @returns false in case an operation is already underway
bool Home();
/// Performs one step of the state machine according to currently planned operation
/// @returns true if the idler is ready to accept new commands (i.e. it has finished the last operation)
bool Step();
@ -62,6 +67,7 @@ private:
bool currentlyEngaged;
};
/// The one and only instance of Idler in the FW
extern Idler idler;
} // namespace idler

View File

@ -2,18 +2,22 @@
#include <stdint.h>
/// We have 5 pairs of LEDs
/// In each pair there is a green and a red LED
namespace modules {
/// @brief The leds namespace provides all necessary facilities related to the logical model of the sets of LEDs on the MMU unit.
///
/// We have 5 pairs of LEDs. In each pair there is a green and a red LED.
///
/// A typical scenario in the past was visualization of error states.
/// The combination of colors with blinking frequency had a specific meaning.
///
/// The physical connection is not important on this level (i.e. how and what shall be sent into the shift registers)
namespace modules {
/// The physical connection is not important on this level (i.e. how and what shall be sent into the shift registers).
///
/// LEDS are physically connected to a pair of shift registers along with some other signals.
/// The physical write operations are handled by hal::shr16.
namespace leds {
/// Mode of LED
/// Enum of LED modes
/// blink0 and blink1 allow for interlaced blinking of LEDs (one is on and the other off)
enum Mode {
off,
@ -22,20 +26,29 @@ enum Mode {
blink1 ///< start blinking at odd periods
};
/// Enum of LEDs color - green or red
enum Color {
green = 0,
red = 1
};
/// a single LED
/// A single LED
class LED {
public:
constexpr inline LED() = default;
/// Sets the mode of the LED
/// @param mode to set
void SetMode(leds::Mode mode);
/// @returns the currently active mode of the LED
inline leds::Mode Mode() const { return (leds::Mode)state.mode; }
/// @returns true if the LED shines
/// @param oddPeriod LEDs class operates this parameter based on blinking period based on elapsed real time
bool Step(bool oddPeriod);
/// @returns true if the LED shines
inline bool On() const { return state.on; }
private:
@ -50,7 +63,7 @@ private:
State state;
};
/// main LED API
/// The main LEDs API takes care of the whole set of LEDs
class LEDs {
public:
constexpr inline LEDs() = default;
@ -58,25 +71,46 @@ public:
/// step LED automaton
void Step();
/// @returns the number of LED pairs
inline constexpr uint8_t LedPairsCount() const { return ledPairs; }
/// Sets the mode of a LED in a pair
/// @param slot index of filament slot (index of the LED pair)
/// @param color green or red LED
/// @param mode to set
inline void SetMode(uint8_t slot, Color color, Mode mode) {
SetMode(slot * 2 + color, mode);
}
/// Sets the mode of a LED in a pair
/// @param index - raw index of the LED in the internal leds array
/// @param mode to set
inline void SetMode(uint8_t index, Mode mode) {
leds[index].SetMode(mode);
}
/// @returns the currently active mode of a LED in a pair
/// @param slot index of filament slot (index of the LED pair)
/// @param color green or red LED
inline leds::Mode Mode(uint8_t slot, Color color) {
return Mode(slot * 2 + color);
}
/// @returns the currently active mode of a LED
/// @param index - raw index of the LED in the internal leds array
inline leds::Mode Mode(uint8_t index) {
return leds[index].Mode();
}
/// @returns true if a LED is shining
/// @param index - raw index of the LED in the internal leds array
inline bool LedOn(uint8_t index) const {
return leds[index].On();
}
/// @returns true if a LED is shining
/// @param slot index of filament slot (index of the LED pair)
/// @param color green or red LED
inline bool LedOn(uint8_t slot, Color color) const {
return leds[slot * 2 + color].On();
}
@ -97,6 +131,7 @@ private:
LED leds[ledPairs * 2];
};
/// The one and only instance of FINDA in the FW
extern LEDs leds;
} // namespace LEDs

View File

@ -1,4 +1,3 @@
/// @author Marek Bel
#include "permanent_storage.h"
#include "../hal/eeprom.h"
#include "globals.h"
@ -57,7 +56,6 @@ void Init() {
}
}
/// @brief Erase the whole EEPROM
void EraseAll() {
for (uint16_t i = 0; i < ee::EEPROM::End(); i++) {
ee::EEPROM::UpdateByte(i, static_cast<uint8_t>(eepromEmpty));

View File

@ -1,23 +1,26 @@
/// Permanent storage implementation
/// This is the logic/wear levelling/data structure on top of the raw EEPROM API
/// @author Marek Bel
/// Extracted and refactored from MM-control-01
#pragma once
#include "../hal/eeprom.h"
namespace modules {
/// @brief The permanent_storage namespace provides all necessary facilities related to permanently storing data (into EEPROM) on the MMU unit.
///
/// It uses some clever logic/wear levelling/data structure on top of the raw EEPROM API.
/// The code was originally written by Marek Bel for the previous MMU firmware.
namespace permanent_storage {
void Init();
void EraseAll();
/// Initialization of the permanent storage hive
void Init();
/// @brief Read manipulate and store bowden length
///
/// Value is stored independently for each filament.
/// Active filament is deduced from active_extruder global variable.
class BowdenLength {
public:
/// Erase the whole EEPROM
void EraseAll();
/// @brief Read manipulate and store bowden length
///
/// Value is stored independently for each filament.
/// Active filament is deduced from active_extruder global variable.
class BowdenLength {
public:
static uint16_t get();
static const uint8_t stepSize = 10u; ///< increase()/decrease() bowden length step size
BowdenLength();
@ -25,45 +28,45 @@ namespace permanent_storage {
bool decrease();
~BowdenLength();
private:
private:
uint8_t filament; ///< Selected filament
uint16_t length; ///< Selected filament bowden length
};
};
/// @brief Read and store last filament loaded to nozzle
///
/// 800(data) + 3(status) EEPROM cells are used to store 4 bit value frequently
/// to spread wear between more cells to increase durability.
///
/// Expected worst case durability scenario:
/// @n Print has 240mm height, layer height is 0.1mm, print takes 10 hours,
/// filament is changed 5 times each layer, EEPROM endures 100 000 cycles
/// @n Cell written per print: 240/0.1*5/800 = 15
/// @n Cell written per hour : 15/10 = 1.5
/// @n Fist cell failure expected: 100 000 / 1.5 = 66 666 hours = 7.6 years
///
/// Algorithm can handle one cell failure in status and one cell in data.
/// Status use 2 of 3 majority vote.
/// If bad data cell is detected, status is switched to next key.
/// Key alternates between begin to end and end to begin write order.
/// Two keys are needed for each start point and direction.
/// If two data cells fails, area between them is unavailable to write.
/// If this is first and last cell, whole storage is disabled.
/// This vulnerability can be avoided by adding additional keys
/// and start point in the middle of the EEPROM.
///
/// It would be possible to implement twice as efficient algorithm, if
/// separate EEPROM erase and EEPROM write commands would be available and
/// if write command would allow to be invoked twice between erases to update
/// just one nibble. Such commands are not available in AVR Libc, and possibility
/// to use write command twice is not documented in atmega32U4 datasheet.
///
class FilamentLoaded {
public:
/// @brief Read and store last filament loaded to nozzle
///
/// 800(data) + 3(status) EEPROM cells are used to store 4 bit value frequently
/// to spread wear between more cells to increase durability.
///
/// Expected worst case durability scenario:
/// @n Print has 240mm height, layer height is 0.1mm, print takes 10 hours,
/// filament is changed 5 times each layer, EEPROM endures 100 000 cycles
/// @n Cell written per print: 240/0.1*5/800 = 15
/// @n Cell written per hour : 15/10 = 1.5
/// @n Fist cell failure expected: 100 000 / 1.5 = 66 666 hours = 7.6 years
///
/// Algorithm can handle one cell failure in status and one cell in data.
/// Status use 2 of 3 majority vote.
/// If bad data cell is detected, status is switched to next key.
/// Key alternates between begin to end and end to begin write order.
/// Two keys are needed for each start point and direction.
/// If two data cells fails, area between them is unavailable to write.
/// If this is first and last cell, whole storage is disabled.
/// This vulnerability can be avoided by adding additional keys
/// and start point in the middle of the EEPROM.
///
/// It would be possible to implement twice as efficient algorithm, if
/// separate EEPROM erase and EEPROM write commands would be available and
/// if write command would allow to be invoked twice between erases to update
/// just one nibble. Such commands are not available in AVR Libc, and possibility
/// to use write command twice is not documented in atmega32U4 datasheet.
///
class FilamentLoaded {
public:
static bool get(uint8_t &filament);
static bool set(uint8_t filament);
private:
private:
enum Key {
KeyFront1,
KeyReverse1,
@ -77,22 +80,22 @@ namespace permanent_storage {
static int16_t getIndex();
static void getNext(uint8_t &status, int16_t &index);
static void getNext(uint8_t &status);
};
};
/// @brief Read and increment drive errors
///
/// (Motor power rail voltage loss)
class DriveError {
public:
/// @brief Read and increment drive errors
///
/// (Motor power rail voltage loss)
class DriveError {
public:
static uint16_t get();
static void increment();
private:
private:
static uint8_t getL();
static void setL(uint8_t lowByte);
static uint8_t getH();
static void setH(uint8_t highByte);
};
};
} // namespace permanent_storage
} // namespace modules

View File

@ -1,14 +1,15 @@
#pragma once
#include <stdint.h>
/// MMU protocol implementation
namespace modules {
/// @brief The MMU communication protocol implementation and related stuff.
///
/// See description of the new protocol in the MMU 2021 doc
/// @@TODO possibly add some checksum to verify the correctness of messages
namespace modules {
namespace protocol {
/// Definition of request message codes
enum class RequestMsgCodes : uint8_t {
unknown = 0,
Query = 'Q',
@ -25,6 +26,7 @@ enum class RequestMsgCodes : uint8_t {
Cut = 'K'
};
/// Definition of response message parameter codes
enum class ResponseMsgParamCodes : uint8_t {
unknown = 0,
Processing = 'P',
@ -34,30 +36,34 @@ enum class ResponseMsgParamCodes : uint8_t {
Rejected = 'R'
};
/// A request message
/// Requests are being sent by the printer into the MMU
/// It is the same structure as the generic Msg
/// A request message - requests are being sent by the printer into the MMU.
struct RequestMsg {
RequestMsgCodes code;
uint8_t value;
RequestMsgCodes code; ///< code of the request message
uint8_t value; ///< value of the request message
/// @param code of the request message
/// @param value of the request message
inline RequestMsg(RequestMsgCodes code, uint8_t value)
: code(code)
, value(value) {}
};
/// A response message
/// Responses are being sent from the MMU into the printer as a response to a request message
/// A response message - responses are being sent from the MMU into the printer as a response to a request message.
struct ResponseMsg {
RequestMsg request; ///< response is always preceeded by the request message
ResponseMsgParamCodes paramCode; ///< parameters of reply
uint8_t paramValue; ///< parameters of reply
ResponseMsgParamCodes paramCode; ///< code of the parameter
uint8_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)
: request(request)
, paramCode(paramCode)
, paramValue(paramValue) {}
};
/// Message decoding return value
/// Message decoding return values
enum class DecodeStatus : uint_fast8_t {
MessageCompleted, ///< message completed and successfully lexed
NeedMoreData, ///< message incomplete yet, waiting for another byte to come
@ -65,8 +71,9 @@ enum class DecodeStatus : uint_fast8_t {
};
/// Protocol class is responsible for creating/decoding messages in Rx/Tx buffer
///
/// Beware - in the decoding more, it is meant to be a statefull instance which works through public methods
/// processing one input byte per call
/// processing one input byte per call.
class Protocol {
public:
inline Protocol()
@ -91,18 +98,22 @@ public:
/// Encode generic response Command Accepted or Rejected
/// @param msg source request message for this response
/// @param ar code of response parameter
/// @param txbuff where to format the message
/// @returns number of bytes written into txbuff
static uint8_t EncodeResponseCmdAR(const RequestMsg &msg, ResponseMsgParamCodes ar, uint8_t *txbuff);
/// Encode response to Read FINDA query
/// @param msg source request message for this response
/// @param findaValue 1/0 (on/off) status of FINDA
/// @param txbuff where to format the message
/// @returns number of bytes written into txbuff
static uint8_t EncodeResponseReadFINDA(const RequestMsg &msg, uint8_t findaValue, uint8_t *txbuff);
/// Encode response to Version query
/// @param msg source request message for this response
/// @param value version number (0-255)
/// @param txbuff where to format the message
/// @returns number of bytes written into txbuff
static uint8_t EncodeResponseVersion(const RequestMsg &msg, uint8_t value, uint8_t *txbuff);
@ -110,6 +121,7 @@ public:
/// @param msg source request message for this response
/// @param code status of operation (Processing, Error, Finished)
/// @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);

View File

@ -1,15 +1,15 @@
#pragma once
#include <stdint.h>
/// Selector model
/// Handles asynchronnous move operations between filament individual slots
/// Keeps track of selector's current state
namespace modules {
/// The selector namespace provides all necessary facilities related to the logical model of the selector device of the MMU unit.
namespace selector {
/// The selector model - handles asynchronnous move operations between filament individual slots and keeps track of selector's current state.
class Selector {
public:
/// Internal states of selector's state machine
enum {
Ready = 0,
Moving,
@ -21,13 +21,16 @@ public:
, plannedSlot(0)
, currentSlot(0) {}
// public operations on the selector
/// @retuns false in case an operation is already underway
/// 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);
/// @retuns false in case an operation is already underway
/// Plan homing of the selector's axis
/// @returns false in case an operation is already underway
bool Home();
/// Performs one step of the state machine according to currently planned operation.
/// @returns true if the selector is ready to accept new commands (i.e. it has finished the last operation)
bool Step();
@ -51,6 +54,7 @@ private:
uint8_t currentSlot;
};
/// The one and only instance of Selector in the FW
extern Selector selector;
} // namespace selector

View File

@ -2,6 +2,8 @@
#include <stdint.h>
namespace modules {
/// The time namespace provides all necessary facilities related to measuring real elapsed time for the whole firmware.
namespace time {
/// A basic time tracking class
@ -11,6 +13,8 @@ class Timebase {
public:
constexpr inline Timebase()
: ms(0) {}
/// Initializes the Timebase class - sets the timers and prepares the internal variables.
void Init();
/// @returns current milliseconds elapsed from the initialization of this class
@ -22,6 +26,7 @@ private:
static void ISR();
};
/// The one and only instance of Selector in the FW
extern Timebase timebase;
} // namespace time

View File

@ -107,7 +107,7 @@ TEST_CASE("unload_to_finda::unload_without_FINDA_trigger", "[unload_to_finda]")
REQUIRE(ff.State() == logic::UnloadToFinda::WaitingForFINDA);
// no changes to FINDA during unload - we'll pretend it never triggers
REQUIRE(!WhileCondition(
REQUIRE_FALSE(WhileCondition(
ff,
[&](int) { return mf::finda.Pressed(); },
50000));