STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
FSWConfigManager.cpp
Go to the documentation of this file.
2
3#include <chrono>
4#include <iomanip>
5#include <iostream>
6#include <thread>
7
8#include "DiabloEnums.h"
9#include "DiabloPackets.h"
10
11namespace fsw {
12namespace fsw {
13
16
17bool FSWConfigManager::initialize(const std::string& bind_address, uint16_t bind_port) {
18 bind_address_ = bind_address;
19 config_socket_ = std::make_unique<daq_comms::transport::UDPSocket>(bind_address, bind_port);
20
21 if (!config_socket_->is_valid()) {
22 std::cerr << "[FSWConfig] Failed to create UDP socket: " << config_socket_->last_error()
23 << std::endl;
24 return false;
25 }
26
27 // Load sensor definitions (will be loaded from specific config file)
28 assignment_manager_.load_sensor_definitions("");
29
30 std::cout << "[FSWConfig] Initialized FSW configuration manager" << std::endl;
31 std::cout << "[FSWConfig] System state: "
32 << (current_state_ == config::SystemState::GSE ? "GSE" : "FLIGHT") << std::endl;
33
34 return true;
35}
36
37std::string FSWConfigManager::process_board_heartbeat(const daq::PacketHeader& /* header */,
38 const daq::BoardHeartbeatPacket& body,
39 const std::string& source_ip,
40 const std::string& mac_address) {
41 uint8_t board_id = body.board_id;
42
43 // Infer system state from board ID or IP
44 config::SystemState system_state = infer_system_state(board_id, source_ip);
45
46 // Assign IP address
47 std::string assigned_ip =
48 assignment_manager_.assign_board_ip(board_id, mac_address, system_state, source_ip);
49
50 // Check if board needs sensor assignment
51 auto board_config = assignment_manager_.get_board_config(board_id);
52 if (board_config && board_config->sensors.empty()) {
53 // Auto-assign sensors based on board type and system state
54 std::vector<std::string> sensor_ids;
55
56 if (system_state == config::SystemState::FLIGHT) {
57 // Flight sensors based on board ID
58 switch (board_id) {
59 case 0:
60 sensor_ids = {"PT_HP", "PT_LP"};
61 break;
62 case 1:
63 sensor_ids = {"PT_FUP", "PT_FDP"};
64 break;
65 case 2:
66 sensor_ids = {"PT_OUP", "PT_ODP"};
67 break;
68 default:
69 break;
70 }
71 } else {
72 // GSE sensors based on board ID
73 switch (board_id) {
74 case 10:
75 sensor_ids = {"PT_OF"};
76 break;
77 case 11:
78 sensor_ids = {"PT_FF"};
79 break;
80 case 12:
81 sensor_ids = {"PT_HPF", "PT_MPF", "PT_LPF"};
82 break;
83 default:
84 break;
85 }
86 }
87
88 if (!sensor_ids.empty()) {
89 assignment_manager_.assign_sensors_to_board(board_id, sensor_ids);
90 std::cout << "[FSWConfig] Auto-assigned " << sensor_ids.size() << " sensors to board "
91 << (int)board_id << std::endl;
92 }
93 }
94
95 // Deliberately does NOT send SENSOR_CONFIG. config_broadcast_service owns board
96 // configuration: it is the only writer that reads the rig's real config.toml
97 // ([boards.*] active_connectors, voltage_reference, necessary_for_abort). This manager
98 // builds its packet from assignment_manager_'s auto-assign table, which is keyed on a
99 // board-type enum that matches no board on the stand — so it produced an EMPTY config
100 // (num_sensors=0) and shipped it to every sensor board within a millisecond of boot.
101 // The firmware applies every SENSOR_CONFIG it receives in any state, so that empty
102 // config latched: collect_chunk() early-returns on active_count==0, and the board
103 // heartbeats as ACTIVE forever while sampling nothing. Two writers, and the one with
104 // no knowledge of the rig won the race on every board boot.
105 (void)body;
106
107 return assigned_ip;
108}
109
110bool FSWConfigManager::assign_sensors(uint8_t board_id, const std::vector<std::string>& sensor_ids,
111 uint8_t start_channel) {
112 bool success = assignment_manager_.assign_sensors_to_board(board_id, sensor_ids, start_channel);
113
114 if (success) {
115 // Send updated configuration to board
117 }
118
119 return success;
120}
121
123 auto board_config = assignment_manager_.get_board_config(board_id);
124 if (!board_config) {
125 std::cerr << "[FSWConfig] Board " << (int)board_id << " not found" << std::endl;
126 return false;
127 }
128
129 // Generate configuration packet
130 auto packet = assignment_manager_.generate_board_config_packet(board_id);
131 if (packet.empty()) {
132 std::cerr << "[FSWConfig] Failed to generate config packet for board " << (int)board_id
133 << std::endl;
134 return false;
135 }
136
137 // Dump packet contents for debugging / verification
138 std::cout << "[FSWConfig] SENSOR_CONFIG packet for board " << static_cast<int>(board_id)
139 << " len=" << packet.size() << " bytes: ";
140 std::ios_base::fmtflags f(std::cout.flags());
141 for (size_t i = 0; i < packet.size(); ++i) {
142 std::cout << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
143 << static_cast<int>(packet[i]);
144 if (i + 1 < packet.size()) {
145 std::cout << ' ';
146 }
147 }
148 std::cout.flags(f);
149 std::cout << std::dec << std::setfill(' ') << std::endl;
150
151 // Create UDP socket for sending to board, pinned to the same NIC we listen on so the config
152 // packet cannot leave via the site LAN or the Docker bridge on a multi-homed host.
153 daq_comms::transport::UDPSocket board_socket(board_config->board_ip, board_config->board_port,
154 true, bind_address_);
155
156 // Send packet to board
157 ssize_t sent = board_socket.send(packet.data(), packet.size());
158
159 if (sent != static_cast<ssize_t>(packet.size())) {
160 std::cerr << "[FSWConfig] Failed to send config to board " << (int)board_id << " at "
161 << board_config->board_ip << ":" << board_config->board_port << std::endl;
162 return false;
163 }
164
166 std::cout << "[FSWConfig] Sent configuration to board " << (int)board_id << " ("
167 << board_config->board_ip << ":" << board_config->board_port << ")" << std::endl;
168
169 return true;
170}
171
173 // Get all board IDs from assignment manager
174 // For now, iterate through configured boards
175 for (uint8_t board_id = 0; board_id < 16; ++board_id) {
176 auto config = assignment_manager_.get_board_config(board_id);
177 if (config && !config->sensors.empty()) {
179 }
180 }
181}
182
185 std::cout << "[FSWConfig] System state changed to: "
186 << (state == config::SystemState::GSE ? "GSE" : "FLIGHT") << std::endl;
187}
188
189void FSWConfigManager::set_board_static_ip(uint8_t board_id, const std::string& ip) {
190 if (!ip.empty()) {
191 assignment_manager_.set_static_board_ip(board_id, ip);
192 }
193}
194
196 const std::string& source_ip) const {
197 // Infer from board ID: GSE boards typically use IDs 10-15, Flight uses 0-9
198 if (board_id >= 10) {
200 }
201
202 // Infer from IP address: GSE uses 192.168.2.x, Flight uses 192.168.3.x
203 if (source_ip.find("192.168.2.") == 0) {
205 } else if (source_ip.find("192.168.3.") == 0) {
207 }
208
209 // Default to current system state
210 return current_state_;
211}
212
213} // namespace fsw
214} // namespace fsw
UDP socket implementation.
ssize_t send(const uint8_t *data, size_t size) override
Send data through the socket.
std::string process_board_heartbeat(const daq::PacketHeader &header, const daq::BoardHeartbeatPacket &body, const std::string &source_ip, const std::string &mac_address)
Process board heartbeat and assign IP if needed.
config::SensorAssignmentManager assignment_manager_
void set_board_static_ip(uint8_t board_id, const std::string &ip)
Configure static board IP address loaded from config.toml.
std::map< uint8_t, bool > boards_configured_
bool send_config_to_board(uint8_t board_id)
Send configuration packet to board.
void send_configs_to_all_boards()
Send configuration to all configured boards.
config::SystemState current_state_
config::SystemState infer_system_state(uint8_t board_id, const std::string &source_ip) const
std::string bind_address_
Local address board config packets are sent from — the same NIC this manager listens on.
void set_system_state(config::SystemState state)
Set system state (GSE or FLIGHT).
bool initialize(const std::string &bind_address, uint16_t bind_port)
Initialize FSW config manager.
bool assign_sensors(uint8_t board_id, const std::vector< std::string > &sensor_ids, uint8_t start_channel=0)
Assign sensors to a board.
std::unique_ptr< daq_comms::transport::UDPSocket > config_socket_
static uint8_t board_id
Definition main.cpp:30
static ActuatorControllerState state
Definition main.cpp:57
SystemState
System state (GSE or Flight).
Motorized ball valve position: raw ADC counts -> % open.
bool success