HardFOC Vortex V1 HAL
Unified HAL API for the HardFOC Vortex motor-control platform (ESP32-C6, TMC9660)
Loading...
Searching...
No Matches
EncoderManager.h
Go to the documentation of this file.
1
14#pragma once
15
16#include <array>
17#include <atomic>
18#include <optional>
19#include "RtosMutex.h"
20#include "handlers/as5047u/As5047uHandler.h"
21
22// Forward declarations
24class GpioManager;
25class BaseSpi;
26enum class SpiDeviceId : uint8_t;
27enum class AS5047U_Error : uint16_t;
28
48
51
57constexpr const char* EncoderErrorToString(EncoderError error) noexcept {
58 switch (error) {
59 case EncoderError::SUCCESS: return "Success";
60 case EncoderError::NOT_INITIALIZED: return "Not initialized";
61 case EncoderError::INITIALIZATION_FAILED: return "Initialization failed";
62 case EncoderError::INVALID_PARAMETER: return "Invalid parameter";
63 case EncoderError::SPI_COMMUNICATION_FAILED: return "SPI communication failed";
64 case EncoderError::CRC_ERROR: return "CRC error";
65 case EncoderError::FRAMING_ERROR: return "Framing error";
66 case EncoderError::SENSOR_ERROR: return "Sensor error";
67 case EncoderError::TIMEOUT: return "Timeout";
68 case EncoderError::MUTEX_LOCK_FAILED: return "Mutex lock failed";
69 default: return "Unknown error";
70 }
71}
72
78constexpr const char* As5047uErrorToString(As5047uError error) noexcept {
79 return EncoderErrorToString(error);
80}
81
82//==============================================================================
83// ENCODER DIAGNOSTICS
84//==============================================================================
85
88 uint8_t agc{0};
89 uint16_t magnitude{0};
90};
91
112
145public:
146 static constexpr uint8_t MAX_ENCODER_DEVICES = 4;
147
148 // Slot indices — all user-provisioned, no onboard encoder.
149 static constexpr uint8_t ENCODER_SLOT_0 = 0;
150 static constexpr uint8_t ENCODER_SLOT_1 = 1;
151 static constexpr uint8_t ENCODER_SLOT_2 = 2;
152 static constexpr uint8_t ENCODER_SLOT_3 = 3;
153
155 static constexpr uint8_t ONBOARD_ENCODER_INDEX = ENCODER_SLOT_0;
156
157public:
162 static EncoderManager& GetInstance() noexcept;
163
164 //**************************************************************************//
165 //** DEVICE MANAGEMENT METHODS **//
166 //**************************************************************************//
167
173 bool EnsureInitialized() noexcept;
174
179 bool IsInitialized() const noexcept;
180
185 [[nodiscard]] EncoderError GetLastError() const noexcept { return last_error_.load(std::memory_order_acquire); }
186
192 [[nodiscard]] EncoderError GetSystemDiagnostics(EncoderSystemDiagnostics& diagnostics) const noexcept;
193
198 bool Deinitialize() noexcept;
199
200 //**************************************************************************//
201 //** HANDLER AND DRIVER MANAGEMENT **//
202 //**************************************************************************//
203
209 As5047uHandler* GetAs5047uHandler(uint8_t deviceIndex = ENCODER_SLOT_0) noexcept;
210
220 template <typename Fn>
221 bool VisitDriver(uint8_t deviceIndex, Fn&& fn) noexcept {
222 MutexLockGuard lock(manager_mutex_);
223 As5047uHandler* handler = ReadyHandlerLocked(deviceIndex);
224 if (handler == nullptr) {
225 return false;
226 }
227 bool ran = false;
228 handler->visitDriver([&](as5047u::AS5047U<As5047uSpiAdapter>& driver) {
229 ran = true;
230 fn(driver);
231 });
232 return ran;
233 }
234
235 //**************************************************************************//
236 //** DEVICES MANAGEMENT METHODS **//
237 //**************************************************************************//
238
246 bool CreateAs5047uDevice(uint8_t deviceIndex,
247 SpiDeviceId spiDeviceId,
248 const As5047uConfig& config = As5047uHandler::GetDefaultConfig()) noexcept;
249
257 bool CreateAs5047uDevice(uint8_t deviceIndex,
258 BaseSpi& spi_interface,
259 const As5047uConfig& config = As5047uHandler::GetDefaultConfig()) noexcept;
260
262 bool CreateExternalAs5047uDevice(uint8_t deviceIndex,
263 SpiDeviceId spiDeviceId,
264 const As5047uConfig& config = As5047uHandler::GetDefaultConfig()) noexcept {
265 return CreateAs5047uDevice(deviceIndex, spiDeviceId, config);
266 }
268 bool CreateExternalAs5047uDevice(uint8_t deviceIndex,
269 BaseSpi& spi_interface,
270 const As5047uConfig& config = As5047uHandler::GetDefaultConfig()) noexcept {
271 return CreateAs5047uDevice(deviceIndex, spi_interface, config);
272 }
273
279 bool DeleteDevice(uint8_t deviceIndex) noexcept;
280
282 bool DeleteExternalDevice(uint8_t deviceIndex) noexcept { return DeleteDevice(deviceIndex); }
283
288 uint8_t GetDeviceCount() const noexcept;
289
295 bool IsDeviceValid(uint8_t deviceIndex) const noexcept;
296
302 bool IsExternalSlotAvailable(uint8_t deviceIndex) const noexcept;
303
309 void GetActiveDeviceIndices(std::array<uint8_t, MAX_ENCODER_DEVICES>& out, size_t& count) const noexcept;
310
316 size_t InitializeAllDevices(std::array<bool, MAX_ENCODER_DEVICES>& results) noexcept;
317
322 void GetInitializationStatus(std::array<bool, MAX_ENCODER_DEVICES>& status) const noexcept;
323
324 //**************************************************************************//
325 //** DEVICE INFORMATION METHODS **//
326 //**************************************************************************//
327
333 void GetAvailableDevices(std::array<const char*, MAX_ENCODER_DEVICES>& out, size_t& count) const noexcept;
334
340 [[nodiscard]] const char* GetDeviceType(uint8_t deviceIndex) const noexcept;
341
342 //**************************************************************************//
343 //** HIGH-LEVEL ENCODER OPERATIONS **//
344 //**************************************************************************//
345
352 EncoderError ReadAngle(uint8_t deviceIndex, uint16_t& angle) noexcept;
353
360 EncoderError ReadAngleDegrees(uint8_t deviceIndex, double& angle_degrees) noexcept;
361
368 EncoderError ReadVelocityRPM(uint8_t deviceIndex, double& velocity_rpm) noexcept;
369
378 EncoderError ReadDiagnostics(uint8_t deviceIndex, As5047uDiagnostics& diagnostics) noexcept;
379
386 EncoderError ReadFieldStrength(uint8_t deviceIndex, EncoderFieldStrength& field) noexcept;
387
394 EncoderError SetZeroPosition(uint8_t deviceIndex, uint16_t zero_position) noexcept;
395
403 void ReadAllAngles(std::array<uint16_t, MAX_ENCODER_DEVICES>& angles,
404 std::array<uint8_t, MAX_ENCODER_DEVICES>& device_indices,
405 std::array<EncoderError, MAX_ENCODER_DEVICES>& errors,
406 size_t& count) noexcept;
407
415 void ReadAllVelocities(std::array<double, MAX_ENCODER_DEVICES>& velocities_rpm,
416 std::array<uint8_t, MAX_ENCODER_DEVICES>& device_indices,
417 std::array<EncoderError, MAX_ENCODER_DEVICES>& errors,
418 size_t& count) noexcept;
419
424 bool CheckAllDevicesHealth() noexcept;
425
426 //**************************************************************************//
427 //** SENSOR MONITORING METHODS **//
428 //**************************************************************************//
429
435 uint32_t GetMeasurementCount(uint8_t deviceIndex) const noexcept;
436
442 uint32_t GetCommunicationErrorCount(uint8_t deviceIndex) const noexcept;
443
448 void DumpStatistics() const noexcept;
449
450 // Delete copy/move constructors and assignment operators
452 EncoderManager& operator=(const EncoderManager&) = delete;
454 EncoderManager& operator=(EncoderManager&&) = delete;
455
456private:
460 EncoderManager() noexcept;
461
465 ~EncoderManager() noexcept;
466
471 bool Initialize() noexcept;
472
476 static bool IsValidDeviceIndex(uint8_t deviceIndex) noexcept {
477 return deviceIndex < MAX_ENCODER_DEVICES;
478 }
479
485 static EncoderError mapDriverError(AS5047U_Error sticky_flags) noexcept;
486
488 As5047uHandler* ReadyHandlerLocked(uint8_t deviceIndex) noexcept;
489
491 EncoderError FinishRead(uint8_t deviceIndex, AS5047U_Error sticky, bool count_measurement) noexcept;
492
493 // ===============================
494 // SYSTEM STATE
495 // ===============================
496
500 std::atomic<bool> initialized_{false};
501
505 std::atomic<EncoderError> last_error_{EncoderError::SUCCESS};
506
511 mutable RtosMutex manager_mutex_;
512
513 // ===============================
514 // DEVICE STORAGE
515 // ===============================
516
521 std::array<std::optional<As5047uHandler>, MAX_ENCODER_DEVICES> as5047u_handlers_;
522
527 std::array<bool, MAX_ENCODER_DEVICES> device_initialized_;
528
533 std::array<bool, MAX_ENCODER_DEVICES> device_active_;
534
535 // (no onboard device — all encoder slots are user-provisioned)
536
537 // ===============================
538 // DEPENDENCIES
539 // ===============================
540
546
552
553 // ===============================
554 // SENSOR MONITORING
555 // ===============================
556
560 std::array<std::atomic<uint32_t>, MAX_ENCODER_DEVICES> measurement_counts_{0};
561 std::array<std::atomic<uint32_t>, MAX_ENCODER_DEVICES> communication_error_counts_{0};
562};
563
564//==============================================================================
565// CONVENIENCE
566//==============================================================================
567
572[[nodiscard]] inline EncoderManager& GetEncoderManager() noexcept {
574}
SpiDeviceId
SPI device identifiers for the Vortex V1 board.
Definition CommChannelsManager.h:113
constexpr const char * EncoderErrorToString(EncoderError error) noexcept
Convert EncoderError to a human-readable string.
Definition EncoderManager.h:57
EncoderError
Generic encoder manager error codes.
Definition EncoderManager.h:36
@ NOT_INITIALIZED
Manager not yet initialised.
@ TIMEOUT
Operation timed out.
@ MUTEX_LOCK_FAILED
RTOS mutex acquire timed out.
@ SENSOR_ERROR
Encoder sensor self-test failure.
@ FRAMING_ERROR
Malformed SPI frame received.
@ SUCCESS
Operation completed successfully.
@ SPI_COMMUNICATION_FAILED
SPI bus transfer failed.
@ INITIALIZATION_FAILED
Device initialisation failed.
@ CRC_ERROR
CRC mismatch on SPI frame.
@ INVALID_PARAMETER
Null pointer or out-of-range argument.
EncoderManager & GetEncoderManager() noexcept
Convenience accessor — equivalent to EncoderManager::GetInstance().
Definition EncoderManager.h:572
constexpr const char * As5047uErrorToString(As5047uError error) noexcept
Backward-compatible helper — calls EncoderErrorToString().
Definition EncoderManager.h:78
Singleton managing all board communication channels for Vortex V1.
Definition CommChannelsManager.h:149
Singleton for managing multiple AS5047U encoder devices with indexed access.
Definition EncoderManager.h:144
RtosMutex manager_mutex_
Main system mutex for thread-safe operations. Uses RtosMutex for embedded RTOS compatibility.
Definition EncoderManager.h:511
EncoderError ReadVelocityRPM(uint8_t deviceIndex, double &velocity_rpm) noexcept
Read velocity from specific encoder device.
Definition EncoderManager.cpp:450
bool Initialize() noexcept
Initialize the encoder manager system (no devices auto-created).
Definition EncoderManager.cpp:612
std::atomic< bool > initialized_
System initialization state (atomic for thread safety).
Definition EncoderManager.h:500
std::atomic< EncoderError > last_error_
Most recent error code for system-level tracking.
Definition EncoderManager.h:505
As5047uHandler * GetAs5047uHandler(uint8_t deviceIndex=ENCODER_SLOT_0) noexcept
Get access to AS5047U encoder handler by device index.
Definition EncoderManager.cpp:106
EncoderError GetLastError() const noexcept
Get the most recent error code.
Definition EncoderManager.h:185
EncoderError ReadAngleDegrees(uint8_t deviceIndex, double &angle_degrees) noexcept
Read angle in degrees from specific encoder device.
Definition EncoderManager.cpp:431
std::array< std::optional< As5047uHandler >, MAX_ENCODER_DEVICES > as5047u_handlers_
AS5047U encoder handlers (one per device slot), in place (no heap): emplaced on create,...
Definition EncoderManager.h:521
void ReadAllVelocities(std::array< double, MAX_ENCODER_DEVICES > &velocities_rpm, std::array< uint8_t, MAX_ENCODER_DEVICES > &device_indices, std::array< EncoderError, MAX_ENCODER_DEVICES > &errors, size_t &count) noexcept
Read velocities from all active encoder devices.
Definition EncoderManager.cpp:570
std::array< bool, MAX_ENCODER_DEVICES > device_initialized_
Device initialization status tracking. Tracks which devices have been successfully initialized.
Definition EncoderManager.h:527
bool CheckAllDevicesHealth() noexcept
Check health status of all active encoder devices.
Definition EncoderManager.cpp:591
void GetAvailableDevices(std::array< const char *, MAX_ENCODER_DEVICES > &out, size_t &count) const noexcept
Get human-readable names of all available devices.
Definition EncoderManager.cpp:308
bool IsDeviceValid(uint8_t deviceIndex) const noexcept
Check if a device index is valid and has an active device.
Definition EncoderManager.cpp:246
static constexpr uint8_t MAX_ENCODER_DEVICES
Maximum supported AS5047U devices.
Definition EncoderManager.h:146
EncoderError ReadDiagnostics(uint8_t deviceIndex, As5047uDiagnostics &diagnostics) noexcept
Read diagnostics from specific encoder device.
Definition EncoderManager.cpp:469
void ReadAllAngles(std::array< uint16_t, MAX_ENCODER_DEVICES > &angles, std::array< uint8_t, MAX_ENCODER_DEVICES > &device_indices, std::array< EncoderError, MAX_ENCODER_DEVICES > &errors, size_t &count) noexcept
Read angles from all active encoder devices.
Definition EncoderManager.cpp:549
bool VisitDriver(uint8_t deviceIndex, Fn &&fn) noexcept
Run fn on the AS5047U driver of one initialised slot, under both locks.
Definition EncoderManager.h:221
bool Deinitialize() noexcept
Deinitialize all encoders and release resources.
Definition EncoderManager.cpp:68
static constexpr uint8_t ENCODER_SLOT_2
Definition EncoderManager.h:151
static EncoderManager & GetInstance() noexcept
Get the singleton instance of EncoderManager.
Definition EncoderManager.cpp:33
std::array< std::atomic< uint32_t >, MAX_ENCODER_DEVICES > measurement_counts_
Measurement and error tracking for all devices.
Definition EncoderManager.h:560
void DumpStatistics() const noexcept
Dump comprehensive system statistics to log as INFO level. Logs all device statistics,...
Definition EncoderManager.cpp:702
uint32_t GetCommunicationErrorCount(uint8_t deviceIndex) const noexcept
Get communication error count for specific device.
Definition EncoderManager.cpp:660
const char * GetDeviceType(uint8_t deviceIndex) const noexcept
Get device type by index.
Definition EncoderManager.cpp:325
std::array< std::atomic< uint32_t >, MAX_ENCODER_DEVICES > communication_error_counts_
Communication error counts per device.
Definition EncoderManager.h:561
size_t InitializeAllDevices(std::array< bool, MAX_ENCODER_DEVICES > &results) noexcept
Initialize all active encoder devices.
Definition EncoderManager.cpp:272
As5047uHandler * ReadyHandlerLocked(uint8_t deviceIndex) noexcept
Handler of an active, initialised slot, or nullptr. Caller holds manager_mutex_.
Definition EncoderManager.cpp:385
bool CreateAs5047uDevice(uint8_t deviceIndex, SpiDeviceId spiDeviceId, const As5047uConfig &config=As5047uHandler::GetDefaultConfig()) noexcept
Create an AS5047U encoder device on a given SPI device slot.
Definition EncoderManager.cpp:120
GpioManager * gpio_manager_
Reference to GPIO manager for interrupt pin access. Used for configuring interrupt pins for encoder d...
Definition EncoderManager.h:551
bool IsExternalSlotAvailable(uint8_t deviceIndex) const noexcept
Check if an external device slot is available for creation.
Definition EncoderManager.cpp:251
bool EnsureInitialized() noexcept
Ensure the encoder manager system is initialized.
Definition EncoderManager.cpp:49
static constexpr uint8_t ENCODER_SLOT_3
Definition EncoderManager.h:152
void GetInitializationStatus(std::array< bool, MAX_ENCODER_DEVICES > &status) const noexcept
Get initialization status of all device slots.
Definition EncoderManager.cpp:296
static bool IsValidDeviceIndex(uint8_t deviceIndex) noexcept
Validate that deviceIndex is within [0, MAX_ENCODER_DEVICES).
Definition EncoderManager.h:476
EncoderError ReadAngle(uint8_t deviceIndex, uint16_t &angle) noexcept
Read angle from specific encoder device.
Definition EncoderManager.cpp:412
EncoderError FinishRead(uint8_t deviceIndex, AS5047U_Error sticky, bool count_measurement) noexcept
Count a read and map its sticky flags to an error. Caller holds manager_mutex_.
Definition EncoderManager.cpp:393
static constexpr uint8_t ENCODER_SLOT_0
Definition EncoderManager.h:149
uint8_t GetDeviceCount() const noexcept
Get the number of active encoder devices.
Definition EncoderManager.cpp:234
void GetActiveDeviceIndices(std::array< uint8_t, MAX_ENCODER_DEVICES > &out, size_t &count) const noexcept
Get indices of all active encoder devices.
Definition EncoderManager.cpp:261
EncoderError ReadFieldStrength(uint8_t deviceIndex, EncoderFieldStrength &field) noexcept
Read the AGC value and the CORDIC magnitude (magnet field strength) of one encoder.
Definition EncoderManager.cpp:503
bool CreateExternalAs5047uDevice(uint8_t deviceIndex, SpiDeviceId spiDeviceId, const As5047uConfig &config=As5047uHandler::GetDefaultConfig()) noexcept
Definition EncoderManager.h:262
EncoderError GetSystemDiagnostics(EncoderSystemDiagnostics &diagnostics) const noexcept
Fill a diagnostics snapshot with current system state.
Definition EncoderManager.cpp:676
static constexpr uint8_t ENCODER_SLOT_1
Definition EncoderManager.h:150
bool DeleteDevice(uint8_t deviceIndex) noexcept
Delete an encoder device and free its slot.
Definition EncoderManager.cpp:209
std::array< bool, MAX_ENCODER_DEVICES > device_active_
Device active status tracking. Tracks which device slots have active devices.
Definition EncoderManager.h:533
uint32_t GetMeasurementCount(uint8_t deviceIndex) const noexcept
Get measurement statistics for monitoring specific device.
Definition EncoderManager.cpp:653
static EncoderError mapDriverError(AS5047U_Error sticky_flags) noexcept
Map AS5047U driver sticky error flags to generic EncoderError.
Definition EncoderManager.cpp:339
bool DeleteExternalDevice(uint8_t deviceIndex) noexcept
Definition EncoderManager.h:282
static constexpr uint8_t ONBOARD_ENCODER_INDEX
Definition EncoderManager.h:155
CommChannelsManager * comm_manager_
Reference to communication manager for SPI access. Used for creating encoder devices with proper tran...
Definition EncoderManager.h:545
bool IsInitialized() const noexcept
Check if the encoder manager is initialized.
Definition EncoderManager.cpp:64
EncoderError SetZeroPosition(uint8_t deviceIndex, uint16_t zero_position) noexcept
Set zero position for specific encoder device.
Definition EncoderManager.cpp:523
bool CreateExternalAs5047uDevice(uint8_t deviceIndex, BaseSpi &spi_interface, const As5047uConfig &config=As5047uHandler::GetDefaultConfig()) noexcept
Definition EncoderManager.h:268
Singleton managing GPIO pins across ESP32, PCAL95555 I/O expander, and TMC9660 controllers.
Definition GpioManager.h:110
Magnet field readings of one AS5047U (see EncoderManager::ReadFieldStrength()).
Definition EncoderManager.h:87
uint16_t magnitude
CORDIC magnitude (0–16383)
Definition EncoderManager.h:89
uint8_t agc
Automatic gain control value (0–255); near either end means a weak or strong magnet.
Definition EncoderManager.h:88
Per-device health snapshot.
Definition EncoderManager.h:103
uint32_t communication_error_count
Cumulative SPI errors.
Definition EncoderManager.h:107
bool initialized
Device initialised successfully.
Definition EncoderManager.h:105
bool active
Slot has a device.
Definition EncoderManager.h:104
uint32_t measurement_count
Cumulative successful readings.
Definition EncoderManager.h:106
System-level diagnostics snapshot for encoder health monitoring.
Definition EncoderManager.h:95
uint8_t active_device_count
Number of active device slots.
Definition EncoderManager.h:98
uint8_t initialized_device_count
Number of successfully initialised devices.
Definition EncoderManager.h:99
static constexpr uint8_t kMaxDevices
Definition EncoderManager.h:109
DeviceSnapshot devices[kMaxDevices]
Per-slot snapshots (0–kMaxDevices-1)
Definition EncoderManager.h:110
EncoderError last_error
Most recent error code.
Definition EncoderManager.h:100
bool system_initialized
EncoderManager::IsInitialized()
Definition EncoderManager.h:97
bool system_healthy
True when all active devices are healthy.
Definition EncoderManager.h:96