-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample_module.h
More file actions
135 lines (116 loc) · 5.3 KB
/
example_module.h
File metadata and controls
135 lines (116 loc) · 5.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/**
* @file
* @brief Demonstrates the implementation of an AXMC-compatible hardware module class.
*
* This file demonstrates the process of writing custom hardware module classes that use the AXMC library to integrate
* with the communication interface running on the host-computer (PC). This implementation showcases one of the many
* possible module design patterns. The main advantage of the AXMC library is that it is designed to work with any
* class design and layout, as long as it subclasses the base Module class and overloads the three pure virtual
* methods: SetCustomParameters, RunActiveCommand and SetupModule.
*
* @note For the best learning experience, it is recommended to review this code side-by-side with the implementation
* of the companion TestModuleInterface class defined in the ataraxis-communication-interface library.
*/
#ifndef AXMC_EXAMPLE_MODULE_H
#define AXMC_EXAMPLE_MODULE_H
#include <Arduino.h>
#include "module.h"
/**
* @brief Sends square digital pulses and echoes parameter values to the PC in response to commands received from the
* communication interface.
*
* @tparam kPin The digital pin managed by this module instance.
*/
template <const uint8_t kPin = 5>
class TestModule final : public Module
{
public:
/// Stores the instance's PC-addressable runtime parameters.
struct CustomRuntimeParameters
{
uint32_t on_duration = 2000000; ///< The time, in microseconds, to keep the pin HIGH when pulsing.
uint32_t off_duration = 2000000; ///< The time, in microseconds, to keep the pin LOW when pulsing.
uint16_t echo_value = 666; ///< The value sent to the PC as part of the Echo() command's runtime.
} PACKED_STRUCT parameters;
/// Defines the state codes used by the class when communicating with the PC. Each code must be unique within
/// the module class and use values between 51 and 250 to avoid clashing with system-reserved codes.
enum class kStates : uint8_t
{
kHigh = 52, ///< The managed digital pin is currently set to output a HIGH signal.
kLow = 53, ///< The managed digital pin is currently set to output a LOW signal.
kEcho = 54, ///< Communicates the 'echo_value' to the PC.
};
/// Defines the codes for the commands that can be executed by the module.
enum class kCommands : uint8_t
{
kPulse = 1, ///< Sends a square digital pulse using the managed digital pin.
kEcho = 2, ///< Sends the 'echo_value' parameter to the PC.
};
/// Initializes the base Module class with the provided type, id, and communication instance.
TestModule(const uint8_t module_type, const uint8_t module_id, Communication& communication) :
Module(module_type, module_id, communication)
{}
/// Overwrites the module's runtime parameters structure with the data received from the PC.
bool SetCustomParameters() override
{
return ExtractParameters(parameters);
}
/// Resolves and executes the currently active command.
bool RunActiveCommand() override
{
switch (static_cast<kCommands>(get_active_command()))
{
case kCommands::kPulse: Pulse(); return true;
case kCommands::kEcho: Echo(); return true;
default: return false;
}
}
/// Sets up the instance's hardware and software assets to default values.
bool SetupModule() override
{
pinMode(kPin, OUTPUT);
digitalWrite(kPin, LOW);
parameters.on_duration = 2000000;
parameters.off_duration = 2000000;
parameters.echo_value = 123;
return true;
}
/// Destroys the instance during cleanup.
~TestModule() override = default;
private:
/// Emits a square digital pulse using the managed pin.
void Pulse()
{
switch (get_command_stage())
{
// Stage 1: Activates the pin.
case 1:
digitalWrite(kPin, HIGH);
SendData(static_cast<uint8_t>(kStates::kHigh));
AdvanceCommandStage();
break;
// Stage 2: Waits for the specified on_duration.
case 2:
if (WaitForMicros(parameters.on_duration)) AdvanceCommandStage();
break;
// Stage 3: Disables the pin.
case 3:
digitalWrite(kPin, LOW);
SendData(static_cast<uint8_t>(kStates::kLow));
AdvanceCommandStage();
break;
// Stage 4: Ensures the pin is kept off for at least the specified off_duration.
case 4:
if (WaitForMicros(parameters.off_duration)) CompleteCommand();
break;
default: AbortCommand(); break;
}
}
/// Sends the current value of the 'echo_value' parameter to the PC.
void Echo()
{
SendData(static_cast<uint8_t>(kStates::kEcho), parameters.echo_value);
CompleteCommand();
}
};
#endif //AXMC_EXAMPLE_MODULE_H