107 const unsigned long now =
millis();
177 daq::BoardHeartbeatPacket hb;
178 memset(hb.firmware_hash, 0,
sizeof(hb.firmware_hash));
198 daq::PacketHeader& header_out) {
199 if (buffer_size <
sizeof(daq::PacketHeader))
201 memcpy(&header_out, buffer,
sizeof(daq::PacketHeader));
220 daq::PacketHeader hdr;
224 switch (hdr.packet_type) {
226 daq::PacketHeader dummy;
227 daq::ServerHeartbeatPacket data;
250 daq::PacketHeader cmd_header;
251 std::vector<daq::ActuatorCommand>
commands;
270 const std::vector<daq::ActuatorCommand>&
commands) {
277 uint8_t new_state = (cmd.actuator_state != 0) ? 1 : 0;
278 uint8_t idx = cmd.actuator_id - 1;
297 float voltage = (
static_cast<float>(adcValue) / 4095.0f) * 3.3f;
298 uint32_t voltage_bits;
299 memcpy(&voltage_bits, &voltage,
sizeof(
float));
300 chunk.add_datapoint(i, voltage_bits);
306 std::vector<daq::SensorDataChunkCollection>
chunks;
328 unsigned long now =
millis();
434 Serial.println(
"Initializing actuators...");
438 Serial.print(
"Warning: Invalid actuator ID ");
445 Serial.print(
"Actuator ");
449 Serial.println(
") set to OFF");
451 Serial.println(
"All actuators initialized to OFF state");
455 Serial.println(
"Initializing current sense pins...");
460 Serial.print(
"Current sense sensor ");
464 Serial.println(
") initialized");
474 Serial.println(
"Actuator Controller (actuator_c) starting...");
476 bool spiffs_ok =
false;
479 if (SPIFFS.begin(
false)) {
481 if (f && f.available() >= 1) {
483 if (f.read(&
b, 1) == 1) {
487 Serial.print(
"Board ID and IP from SPIFFS: ");
489 Serial.print(
" / 192.168.2.");
490 Serial.println(
static_cast<unsigned>(
b));
499 "SPIFFS read skipped or failed, using default board ID 1 / "
510 ESP_ERROR_CHECK(esp_read_mac(
mac, ESP_MAC_ETH));
511 Serial.print(
"Generated unique MAC address: ");
512 for (
int i = 0; i < 6; i++) {
521 Serial.println(
"Initializing Ethernet...");
531 Serial.print(
"Ethernet initialized. IP: ");
533 Serial.print(
"Link Status: ");
534 if (
Ethernet.linkStatus() == LinkON) {
535 Serial.println(
"Connected");
536 }
else if (
Ethernet.linkStatus() == LinkOFF) {
537 Serial.println(
"Disconnected");
539 Serial.println(
"Unknown");
541 Serial.print(
"Listening for actuator commands on UDP port: ");
548 Serial.println(
"Setup complete. State: WaitingForServer");
556 int packetSize =
udp.parsePacket();
557 if (packetSize > 0) {
590 unsigned long now =
millis();
void digitalWrite(int, int)
#define NO_CONNECTION_ABORT_DONE_MS
#define ETHERNET_INIT_DELAY_MS
#define CONNECTION_LOSS_GRACE_MS
#define SPIFFS_BOARD_VALUE_PATH
#define ETHERNET_BEGIN_DELAY_MS
#define HEARTBEAT_TIMEOUT_MS
#define ADC_READ_INTERVAL_MS
#define BOARD_HEARTBEAT_INTERVAL_MS
#define ETHERNET_SPI_DELAY_MS
static EthernetClass Ethernet
static void readCurrentSensePinsAndSend()
static StoredConfig stored_config
static void run_WaitingForServer()
static void run_AbortFinished()
static void initializeCurrentSensePins()
static bool heartbeatTimedOut()
static void run_NoConnectionAbort()
static void applyPacketTransition(IncomingPacketKind kind)
static void updateLedNonBlocking()
IPAddress dns(192, 168, 2, 1)
static uint8_t getStateNumber(ActuatorControllerState s)
IPAddress subnet(255, 255, 255, 0)
IPAddress staticIP(192, 168, 2, BOARD_ID_DEFAULT)
static void initializeActuators()
static bool readPacketHeader(const uint8_t *buffer, size_t buffer_size, daq::PacketHeader &header_out)
IPAddress serverIP(192, 168, 2, 20)
static IncomingPacketKind processIncomingPacket(const uint8_t *buffer, size_t len)
static void run_ConnectionLossDetected()
static void sendBoardHeartbeat()
static void processActuatorCommands(const std::vector< daq::ActuatorCommand > &commands)
IPAddress gateway(0, 0, 0, 0)
static void run_StandardAbort()
static void streamSensorDataIfDue()
static daq::BoardState getBoardStateForHeartbeat()
std::vector< daq::SensorDataChunkCollection > chunks
static unsigned long lastHeartbeatMillis
static unsigned long last_adc_read_ms
static unsigned long led_cycle_start_ms
static unsigned long last_server_heartbeat_ms
static unsigned long led_phase_start_ms
static uint8_t led_blink_index
IPAddress dns(192, 168, 2, 1)
IPAddress subnet(255, 255, 255, 0)
IPAddress staticIP(192, 168, 2, BOARD_ID_DEFAULT)
IPAddress serverIP(192, 168, 2, 20)
static uint8_t actuator_states[NUM_ACTUATORS]
static ActuatorControllerState last_led_state
IPAddress gateway(0, 0, 0, 0)
static ActuatorControllerState state
static unsigned long state_enter_ms
static LedPhase led_phase
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]
static osMessageQueueId_t commands
*brief create JSON pointer *sa reference_tokens const string_t const string_t & b
int getActuatorPin(uint8_t actuator_id)
constexpr int NUM_ACTUATORS
int getCurrentSensePin(uint8_t actuator_id)
constexpr Layout Actuator_Board
size_t create_sensor_data_packet(const std::vector< SensorDataChunkCollection > &chunks, const uint8_t num_sensors, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a complete Sensor Data packet in the provided buffer.
bool parse_server_heartbeat_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, ServerHeartbeatPacket &data_out)
Parses a Server Heartbeat packet from buffer.
size_t create_board_heartbeat_packet(const BoardHeartbeatPacket &data, uint32_t timestamp_ms, uint8_t *buffer, size_t buffer_size)
Creates a complete Board Heartbeat packet in the provided buffer.
BoardState
Defines the operational state of a board.
@ CONNECTION_LOSS_DETECTED
bool parse_actuator_command_packet(const uint8_t *buffer, size_t buffer_size, PacketHeader &header_out, std::vector< ActuatorCommand > &commands_out)
Parses an Actuator Command packet from buffer.
Represents a single data chunk with timestamp and sensor datapoints.