Skip to content

Commit 52a0a78

Browse files
committed
Load: Comms integration & ported related nacelle changes
1 parent 3d1f871 commit 52a0a78

4 files changed

Lines changed: 233 additions & 131 deletions

File tree

include/LoadContainer.hpp

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,29 +40,75 @@ class LoadContainer {
4040
etl::array<TaskInfo *, NUM_OPTIONAL_TASKS> optionalTaskDescriptions = {
4141
&tTelnet, &tOTA};
4242

43-
LoadContainer(MCP23008T &loadDevice) : loadDevice(loadDevice) {}
43+
LoadContainer(MCP23008T &loadDevice, LoadComms &loadComms)
44+
: loadDevice(loadDevice), loadComms(loadComms) {}
4445
~LoadContainer() = default;
4546

46-
inline bool getSafetyFlag() const { return safetyFlag; }
47+
inline bool getSafetyFlag() const { return (safetyFlag); }
4748
inline bool isPowerPositive() const { return (INA260::current_mA > 0); }
48-
inline bool isSteadyRPM() const { return false; } // todo - steady power is actually more important
49+
inline bool isSteadyRPM() const {
50+
return false;
51+
} // todo - steady power is actually more important
4952
inline bool isTargetRPMExceeded() const { return false; } // todo
5053

5154
inline void updateSafetyFlag(bool safetyFlag) {
52-
this->safetyFlag = (digitalRead(UM_PROS3::ESTOP_PIN) ==
53-
LOW) /*|| getPPCCurrent() < threshold*/; // todo
55+
this->safetyFlag =
56+
(digitalRead(UM_PROS3::ESTOP_PIN) == LOW) || (!isPowerPositive());
5457
}
5558
// inline void updatePowerPositive(bool powerPositive) {
5659
// this->powerPositive = powerPositive;
5760
// }
5861
inline void setLoadGPIO(uint_fast8_t value) {
5962
loadDevice.setGPIO((uint32_t)value);
6063
}
64+
inline void setRPM(int_fast16_t rpm) { this->currentRPM = rpm; }
6165

6266
private:
6367
MCP23008T &loadDevice;
64-
6568
bool safetyFlag = false; // todo
69+
LoadComms &loadComms;
6670
// bool powerPositive = false;
6771
int_fast16_t currentRPM = 0; // todo
72+
73+
/**
74+
* @brief Check for C++17 support, which allows us to verify if std::atomic
75+
* is a acceptable (lock free) solution for shared variables
76+
* @see https://stackoverflow.com/a/49915536
77+
*/
78+
static_assert(
79+
(__cplusplus >= 201703L),
80+
"C++17 or higher is required for std::atomic is_always_lock_free");
81+
82+
/**
83+
* @brief Do some basic checks regarding std::atomic and data types
84+
* From C++14.2.0 atomic.h:
85+
* Check Lock-free property.
86+
*
87+
* 0 indicates that the types are never lock-free.
88+
* 1 indicates that the types are sometimes lock-free.
89+
* 2 indicates that the types are always lock-free.
90+
*/
91+
static_assert(sizeof(int) == sizeof(int_fast16_t),
92+
"Atomic Lock-free check issue");
93+
#if (ATOMIC_INT_LOCK_FREE == 0)
94+
# error "Atomic operations on int are not lock-free on this platform."
95+
#elif (ATOMIC_INT_LOCK_FREE == 1)
96+
# warning \
97+
"Atomic operations on int are only sometimes lock-free on this platform."
98+
#endif
99+
100+
/**
101+
* @brief Check if std::atomic<int_fast16_t> is an acceptable (lock free)
102+
* solution for shared variables
103+
* @see https://www.reddit.com/r/embedded/comments/zn23of/comment/j0fav6o/
104+
* @see
105+
* https://stackoverflow.com/questions/63471387/should-volatile-still-be-used-for-sharing-data-with-isrs-in-modern-c
106+
* @see https://en.cppreference.com/w/c/language/atomic.html
107+
* @see https://en.cppreference.com/w/cpp/atomic/atomic.html
108+
* @see https://stackoverflow.com/a/16783513
109+
*/
110+
// static_assert(std::atomic<int_fast16_t>::is_always_lock_free,
111+
// "Atomic operations on int_fast16_t are not lock-free on "
112+
// "this platform.");
113+
// std::atomic<int_fast16_t> currentRPM = 0;
68114
};

lib/LoadComms/LoadComms.cpp

Lines changed: 69 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@
66
* Sends state, E-stop, and actuator position data while receiving RPM data.
77
*/
88

9-
#include "LoadComms.h"
9+
#include "LoadComms.hpp"
10+
#include <esp_log.h>
11+
12+
// Initialization of static members
13+
QueueHandle_t LoadComms::priorityDataQueue = nullptr;
1014

1115
/**
1216
* @brief MAC address of the nacelle controller.
1317
*/
1418
const uint8_t NACELLE_MAC[] = {0x30, 0xED, 0xA0, 0xE0, 0x6B, 0x78};
1519

16-
static constexpr char* TAG = "LoadboxComms";
17-
constexpr uint8_t wiFiChannel = 6;
18-
1920
/**
2021
* @brief Pointer to instance for static callbacks.
2122
*/
@@ -24,8 +25,9 @@ static LoadComms *s_instance = nullptr;
2425
LoadComms::LoadComms()
2526
: lastSendTime_(0),
2627
lastRxTime_(0),
27-
linkAlive_(false),
28-
nacelleRPM_(0.0f) {
28+
linkAlive_(false) //,
29+
// nacelleRPM_(0.0f)
30+
{
2931
s_instance = this;
3032
}
3133

@@ -51,41 +53,59 @@ bool LoadComms::begin() {
5153
}
5254

5355
if (esp_now_init() != ESP_OK) {
54-
Serial.println("ESP-NOW init failed");
56+
ESP_LOGE(TAG, "ESP-NOW init failed");
57+
return false;
58+
}
59+
60+
if(esp_now_register_send_cb(onDataSent_) != ESP_OK) {
61+
ESP_LOGE(TAG, "Failed to register tx cb");
5562
return false;
5663
}
5764

58-
esp_now_register_send_cb(onDataSent_);
59-
esp_now_register_recv_cb(onDataRecv_);
65+
if(esp_now_register_recv_cb(onDataRecv_) != ESP_OK) {
66+
ESP_LOGE(TAG, "Failed to register rx cb");
67+
return false;
68+
}
6069

61-
setupPeer_();
70+
if( setupPeer_() != ESP_OK) {
71+
// Logging already handled
72+
return false;
73+
}
6274

6375
Serial.println("Loadbox ready");
6476
return true;
6577
}
6678

67-
void LoadComms::setupPeer_() {
79+
esp_err_t LoadComms::setupPeer_() {
6880
esp_now_peer_info_t peerInfo = {};
6981
memcpy(peerInfo.peer_addr, NACELLE_MAC, 6);
7082
peerInfo.channel = 0;
7183
peerInfo.encrypt = false;
7284

73-
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
74-
Serial.println("Failed to add peer");
75-
return;
85+
esp_err_t result = esp_now_add_peer(&peerInfo);
86+
if (result != ESP_OK) {
87+
ESP_LOGE(TAG, "Failed to add peer: %d at %02x:%02x:%02x:%02x:%02x:%02x", result,
88+
NACELLE_MAC[0], NACELLE_MAC[1], NACELLE_MAC[2],
89+
NACELLE_MAC[3], NACELLE_MAC[4], NACELLE_MAC[5]);
90+
} else{
91+
ESP_LOGI(TAG, "Peer added: %02X:%02X:%02X:%02X:%02X:%02X",
92+
NACELLE_MAC[0], NACELLE_MAC[1], NACELLE_MAC[2],
93+
NACELLE_MAC[3], NACELLE_MAC[4], NACELLE_MAC[5]);
7694
}
7795

78-
Serial.println("Peer added");
96+
return result;
7997
}
8098

8199
void LoadComms::onDataSent_(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) {
82-
(void)tx_info;
83-
Serial.print("Send status: ");
84-
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
100+
// (void)tx_info;
101+
// Serial.print("Send status: ");
102+
// Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
103+
// This is check elsewhere
85104
}
86105

87106
void LoadComms::onDataRecv_(const esp_now_recv_info_t *recv_info, const uint8_t *data, int len) {
88107
if (s_instance == nullptr) {
108+
ESP_LOGE(TAG, "Rx CB: Invalid instance");
89109
return;
90110
}
91111

@@ -95,47 +115,53 @@ void LoadComms::onDataRecv_(const esp_now_recv_info_t *recv_info, const uint8_t
95115
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
96116

97117
if (len == sizeof(NacellePacket)) {
98-
memcpy(&s_instance->incomingPacket_, data, sizeof(NacellePacket));
118+
// memcpy(&s_instance->incomingPacket_, data, sizeof(NacellePacket));
99119

100120
s_instance->lastRxTime_ = millis();
101121
s_instance->linkAlive_ = true;
102122

103-
s_instance->nacelleRPM_ = s_instance->incomingPacket_.rpm;
123+
// s_instance->nacelleRPM_ = s_instance->incomingPacket_.rpm;
104124

105-
Serial.println("Received NacellePacket:");
106-
printNacellePacket(s_instance->incomingPacket_, Serial);
125+
// Serial.println("Received NacellePacket:");
126+
// printNacellePacket(s_instance->incomingPacket_, Serial);
127+
128+
(void)xQueueOverwrite(priorityDataQueue, data); // Allegedly cannot fail
107129
} else {
108-
Serial.print("Unexpected packet length: ");
109-
Serial.println(len);
130+
ESP_LOGE(TAG, "Rx invalid len: %d", len);
110131
}
111132
}
112133

113-
void LoadComms::sendLoadboxData(int8_t state, int8_t estop, int16_t actuatorPos) {
114-
unsigned long now = millis();
115-
116-
if (now - lastSendTime_ >= LOAD_COMMS_SEND_PERIOD_MS) {
117-
lastSendTime_ = now;
118-
makeLoadboxPacket(outgoingPacket_, state, estop, actuatorPos);
119-
esp_now_send(NACELLE_MAC, (uint8_t *)&outgoingPacket_, sizeof(outgoingPacket_));
120-
}
121-
122-
if (now - lastRxTime_ > LOAD_COMMS_TIMEOUT_MS) {
134+
bool LoadComms::sendLoadboxData(uint8_t estop) {
135+
// if (now - lastSendTime_ >= LOAD_COMMS_SEND_PERIOD_MS) {
136+
makeLoadboxPacket(outgoingPacket_, estop);
137+
esp_err_t result = esp_now_send(NACELLE_MAC, (uint8_t *)&outgoingPacket_, sizeof(outgoingPacket_));
138+
if(result == ESP_OK) {
139+
lastSendTime_ = millis();
140+
linkAlive_ = true;
141+
} else {
123142
linkAlive_ = false;
143+
ESP_LOGE(TAG, "Tx failed");
124144
}
125145

126-
if (!linkAlive_) {
127-
Serial.println("WARNING: nacelle comms timeout");
128-
}
129-
}
146+
// }
147+
// if (now - lastRxTime_ > LOAD_COMMS_TIMEOUT_MS) {
148+
// linkAlive_ = false;
149+
// }
130150

131-
void LoadComms::process() {
132-
// This method can be used for future expansion (e.g., periodic checks)
151+
// if (!linkAlive_) {
152+
// Serial.println("WARNING: nacelle comms timeout");
153+
// }
154+
return linkAlive_;
133155
}
134156

157+
// void LoadComms::process() {
158+
// // This method can be used for future expansion (e.g., periodic checks)
159+
// }
160+
135161
bool LoadComms::isLinkAlive() const {
136162
return linkAlive_;
137163
}
138164

139-
float LoadComms::getNacelleRPM() const {
140-
return nacelleRPM_;
141-
}
165+
// float LoadComms::getNacelleRPM() const {
166+
// return nacelleRPM_;
167+
// }
Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
* Sends state, E-stop, and actuator position data while receiving RPM data.
1414
*/
1515

16-
#ifndef LOAD_COMMS_H
17-
#define LOAD_COMMS_H
16+
#ifndef LOAD_COMMS_HPP
17+
#define LOAD_COMMS_HPP
1818

1919
#include <Arduino.h>
2020
#include <WiFi.h>
2121
#include <esp_now.h>
22-
#include <TurbinePacket.h>
22+
#include <2026Core/TurbinePacket/TurbinePacket.hpp>
2323

2424
/**
2525
* @brief MAC address of the nacelle controller.
@@ -29,19 +29,24 @@ extern const uint8_t NACELLE_MAC[];
2929
/**
3030
* @brief Communication timeout threshold in milliseconds.
3131
*/
32-
const unsigned long LOAD_COMMS_TIMEOUT_MS = 1500;
32+
// const unsigned long LOAD_COMMS_TIMEOUT_MS = 1500;
3333

3434
/**
3535
* @brief Transmission period in milliseconds.
3636
*/
37-
const unsigned long LOAD_COMMS_SEND_PERIOD_MS = 100;
37+
// const unsigned long LOAD_COMMS_SEND_PERIOD_MS = 100;
3838

3939
/**
4040
* @class LoadComms
4141
* @brief ESP-NOW communication handler for load box controller.
4242
*/
4343
class LoadComms {
4444
public:
45+
static constexpr char* TAG = "LCO";
46+
static constexpr uint8_t wiFiChannel = 6;
47+
48+
static QueueHandle_t priorityDataQueue;
49+
4550
/**
4651
* @brief Construct a new LoadComms object.
4752
*/
@@ -55,17 +60,16 @@ class LoadComms {
5560

5661
/**
5762
* @brief Send load box data to nacelle.
58-
* @param state State value to send.
59-
* @param estop E-stop value to send.
60-
* @param actuatorPos Actuator position to send.
63+
* @param safety Safety value to send.
6164
*/
62-
void sendLoadboxData(int8_t state, int8_t estop, int16_t actuatorPos);
65+
bool sendLoadboxData(uint8_t safety);
6366

6467
/**
6568
* @brief Process communication - call in main loop.
6669
* Handles periodic sending and link health monitoring.
70+
* @deprecated WIll call sendLoadboxData directly from main
6771
*/
68-
void process();
72+
// void process();
6973

7074
/**
7175
* @brief Check if communication link is active.
@@ -76,21 +80,23 @@ class LoadComms {
7680
/**
7781
* @brief Get the latest received RPM from nacelle.
7882
* @return Current RPM value.
83+
* @deprecated Giving deferred processing in main a try
7984
*/
80-
float getNacelleRPM() const;
85+
// float getNacelleRPM() const;
8186

8287
private:
8388
NacellePacket incomingPacket_; ///< Received packet from nacelle.
8489
LoadboxPacket outgoingPacket_; ///< Outgoing packet to send.
8590
unsigned long lastSendTime_; ///< Timestamp of last transmission.
8691
unsigned long lastRxTime_; ///< Timestamp of last received packet.
8792
bool linkAlive_; ///< Link health status.
88-
float nacelleRPM_; ///< Cached RPM value.
93+
// float nacelleRPM_; ///< Cached RPM value.
8994

9095
/**
9196
* @brief Configure ESP-NOW peer.
97+
* @returns ESP_OK if peer setup successful, error code otherwise.
9298
*/
93-
void setupPeer_();
99+
esp_err_t setupPeer_();
94100

95101
/**
96102
* @brief Callback executed after data is sent.
@@ -108,4 +114,4 @@ class LoadComms {
108114
static void onDataRecv_(const esp_now_recv_info_t *recv_info, const uint8_t *data, int len);
109115
};
110116

111-
#endif // LOAD_COMMS_H
117+
#endif // LOAD_COMMS_HPP

0 commit comments

Comments
 (0)