STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
BoardDiscovery.hpp
Go to the documentation of this file.
1#ifndef DAQ_BOARD_DISCOVERY_HPP
2#define DAQ_BOARD_DISCOVERY_HPP
3
4#include <atomic>
5#include <chrono>
6#include <cstdint>
7#include <cstring>
8#include <functional>
9#include <map>
10#include <mutex>
11#include <optional>
12#include <string>
13#include <vector>
14
15namespace fsw {
16namespace config {
17
18/**
19 * @brief Board signature/identifier structure
20 *
21 * Each board has a unique signature used for identification and IP assignment
22 */
24 uint32_t board_id = 0; // Unique board ID (MAC address hash or serial number)
25 uint8_t board_type = 0; // Board type (PT, TC, RTD, LC, etc.)
26 uint8_t hardware_version = 0; // Hardware revision
27 uint8_t firmware_version = 0; // Firmware version
28 uint16_t serial_number = 0; // Board serial number
29
30 // Comparison operators for map/set usage
31 bool operator<(const BoardSignature& other) const {
32 if (board_id != other.board_id)
33 return board_id < other.board_id;
34 if (board_type != other.board_type)
35 return board_type < other.board_type;
36 return serial_number < other.serial_number;
37 }
38
39 bool operator==(const BoardSignature& other) const {
40 return board_id == other.board_id && board_type == other.board_type &&
43 }
44
45 // Convert to string for logging
46 std::string to_string() const {
47 return "Board{id=0x" + std::to_string(board_id) + ", type=" + std::to_string(board_type) +
48 ", hw=" + std::to_string(hardware_version) +
49 ", fw=" + std::to_string(firmware_version) +
50 ", sn=" + std::to_string(serial_number) + "}";
51 }
52};
53
54/**
55 * @brief Detected sensor information from board
56 */
57struct SensorInfo {
58 uint8_t sensor_type = 0; // Sensor type (PT, TC, RTD, LC)
59 uint8_t channel_id = 0; // Channel ID on board
60 uint8_t sensor_count = 0; // Number of sensors of this type
61 bool is_active = false; // Whether sensor is currently active
62 uint8_t quality = 0; // Data quality (0-255)
63 std::string location; // Physical location (if known)
64};
65
66/**
67 * @brief Discovered board information
68 */
71 std::string current_ip; // Current IP address (if assigned)
72 std::string mac_address; // MAC address
73 std::vector<SensorInfo> sensors; // Detected sensors
74 std::chrono::steady_clock::time_point last_seen;
75 bool is_configured = false; // Whether board has been configured
76 uint16_t port = 0; // Communication port
77
78 // Board capabilities
79 uint8_t max_sensors = 0; // Maximum sensors board supports
80 uint8_t active_sensors = 0; // Currently active sensors
81 bool supports_dynamic_config = false; // Can board accept config updates?
82};
83
84/**
85 * @brief Board Discovery and Configuration Manager
86 *
87 * Discovers boards on the network, detects sensors, and assigns IP addresses
88 * based on board signatures. Automatically updates configuration based on
89 * discovered hardware.
90 */
92public:
93 // Board types (matching sensor types)
94 enum class BoardType : uint8_t {
95 PT_BOARD = 0x01,
96 TC_BOARD = 0x02,
97 RTD_BOARD = 0x03,
98 LC_BOARD = 0x04,
99 MIXED_BOARD = 0x05, // Board with multiple sensor types
100 UNKNOWN = 0xFF
101 };
102
103 // Discovery modes
104 enum class DiscoveryMode {
105 PASSIVE, // Listen for board announcements
106 ACTIVE, // Actively scan network
107 HYBRID // Both passive and active
108 };
109
111 ~BoardDiscovery() = default;
112
113 /**
114 * @brief Initialize discovery system
115 * @param network_interface Network interface to use (e.g., "eth0", "wlan0")
116 * @param base_ip Base IP address for assignment (e.g., "192.168.1.0")
117 * @param ip_range_start Starting IP in range (e.g., 100)
118 * @param ip_range_end Ending IP in range (e.g., 200)
119 */
120 bool initialize(const std::string& network_interface, const std::string& base_ip,
121 uint8_t ip_range_start = 100, uint8_t ip_range_end = 200);
122
123 /**
124 * @brief Set static IP for board_id (from config). Overrides hash-based assignment.
125 * E.g. set_static_ip_for_board(21, "192.168.2.21") so pt_board uses canonical IP.
126 */
127 void set_static_ip_for_board(uint8_t board_id, const std::string& ip);
128
129 /**
130 * @brief Start discovery process
131 * @param mode Discovery mode to use
132 */
134
135 /**
136 * @brief Stop discovery process
137 */
138 void stop_discovery();
139
140 /**
141 * @brief Process incoming board announcement packet
142 * @param data Packet data
143 * @param size Packet size
144 * @param source_ip Source IP address
145 */
146 void process_board_announcement(const uint8_t* data, size_t size, const std::string& source_ip);
147
148 /**
149 * @brief Process sensor data packet to detect sensors
150 * @param data Packet data
151 * @param size Packet size
152 * @param source_ip Source IP address
153 */
154 void process_sensor_data(const uint8_t* data, size_t size, const std::string& source_ip);
155
156 /**
157 * @brief Get all discovered boards
158 */
159 std::vector<DiscoveredBoard> get_discovered_boards();
160
161 /**
162 * @brief Get board by signature
163 */
164 std::optional<DiscoveredBoard> get_board(const BoardSignature& signature);
165
166 /**
167 * @brief Get board by IP address
168 */
169 std::optional<DiscoveredBoard> get_board_by_ip(const std::string& ip);
170
171 /**
172 * @brief Assign IP address to board based on signature
173 * @param signature Board signature
174 * @return Assigned IP address, or empty if assignment failed
175 */
176 std::optional<std::string> assign_ip(const BoardSignature& signature);
177
178 /**
179 * @brief Generate configuration from discovered boards
180 * @return Configuration map ready to be written to TOML
181 */
182 std::map<std::string, std::map<std::string, std::string>> generate_config();
183
184 /**
185 * @brief Update configuration file with discovered boards
186 * @param config_path Path to config file
187 * @return true if update successful
188 */
189 bool update_config_file(const std::string& config_path) const;
190
191 /**
192 * @brief Register callback for board discovery events
193 */
194 void register_discovery_callback(std::function<void(const DiscoveredBoard&)> callback);
195
196 /**
197 * @brief Get statistics
198 */
204 std::chrono::steady_clock::time_point last_discovery;
205 };
206
208 return stats_;
209 }
210
211private:
212 // IP assignment based on board signature
213 std::string calculate_ip_from_signature(const BoardSignature& signature) const;
214 bool is_ip_available(const std::string& ip) const;
215
216 // Sensor detection from packet data
217 std::vector<SensorInfo> detect_sensors_from_packet(const uint8_t* data, size_t size) const;
218 BoardType detect_board_type(const std::vector<SensorInfo>& sensors) const;
219
220 // Board management
222 void remove_stale_boards(std::chrono::seconds timeout = std::chrono::seconds(30));
223
224 // Configuration generation
225 std::map<std::string, std::string> generate_board_config(const DiscoveredBoard& board) const;
226 std::map<std::string, std::string> generate_sensor_config(
227 const std::vector<SensorInfo>& sensors) const;
228
229 // Network discovery
230 void scan_network();
232
233 // State
234 std::map<BoardSignature, DiscoveredBoard> discovered_boards_;
235 std::map<std::string, BoardSignature> ip_to_signature_; // IP -> signature mapping
236 std::map<BoardSignature, std::string> signature_to_ip_; // signature -> IP mapping
237
239 std::string base_ip_;
242 std::map<uint8_t, std::string> static_ip_overrides_; // board_id → config IP
243
244 std::atomic<bool> discovery_active_;
246
247 std::vector<std::function<void(const DiscoveredBoard&)>> discovery_callbacks_;
248
250 std::mutex boards_mutex_;
251};
252
253/**
254 * @brief Dynamic Configuration Manager
255 *
256 * Manages configuration that updates based on discovered hardware
257 */
259public:
262
263 /**
264 * @brief Load base configuration
265 */
266 bool load_base_config(const std::string& config_path);
267
268 /**
269 * @brief Update configuration with discovered boards
270 */
271 bool update_with_boards(const std::vector<DiscoveredBoard>& boards);
272
273 /**
274 * @brief Get current configuration
275 */
276 std::map<std::string, std::map<std::string, std::string>> get_config() const {
277 return config_;
278 }
279
280private:
281 std::map<std::string, std::map<std::string, std::string>> config_;
282 std::string base_config_path_;
283};
284
285} // namespace config
286} // namespace fsw
287
288#endif // DAQ_BOARD_DISCOVERY_HPP
void start_discovery(DiscoveryMode mode=DiscoveryMode::HYBRID)
Start discovery process.
std::atomic< bool > discovery_active_
std::vector< SensorInfo > detect_sensors_from_packet(const uint8_t *data, size_t size) const
void remove_stale_boards(std::chrono::seconds timeout=std::chrono::seconds(30))
std::map< std::string, BoardSignature > ip_to_signature_
std::map< BoardSignature, std::string > signature_to_ip_
BoardType detect_board_type(const std::vector< SensorInfo > &sensors) const
void add_or_update_board(const DiscoveredBoard &board)
void set_static_ip_for_board(uint8_t board_id, const std::string &ip)
Set static IP for board_id (from config).
std::optional< std::string > assign_ip(const BoardSignature &signature)
Assign IP address to board based on signature.
std::map< BoardSignature, DiscoveredBoard > discovered_boards_
DiscoveryStats get_stats() const
void process_board_announcement(const uint8_t *data, size_t size, const std::string &source_ip)
Process incoming board announcement packet.
std::map< std::string, std::map< std::string, std::string > > generate_config()
Generate configuration from discovered boards.
void register_discovery_callback(std::function< void(const DiscoveredBoard &)> callback)
Register callback for board discovery events.
std::string calculate_ip_from_signature(const BoardSignature &signature) const
void stop_discovery()
Stop discovery process.
std::map< std::string, std::string > generate_board_config(const DiscoveredBoard &board) const
void process_sensor_data(const uint8_t *data, size_t size, const std::string &source_ip)
Process sensor data packet to detect sensors.
bool update_config_file(const std::string &config_path) const
Update configuration file with discovered boards.
std::optional< DiscoveredBoard > get_board_by_ip(const std::string &ip)
Get board by IP address.
bool initialize(const std::string &network_interface, const std::string &base_ip, uint8_t ip_range_start=100, uint8_t ip_range_end=200)
Initialize discovery system.
std::map< uint8_t, std::string > static_ip_overrides_
std::map< std::string, std::string > generate_sensor_config(const std::vector< SensorInfo > &sensors) const
std::vector< std::function< void(const DiscoveredBoard &)> > discovery_callbacks_
std::optional< DiscoveredBoard > get_board(const BoardSignature &signature)
Get board by signature.
bool is_ip_available(const std::string &ip) const
std::vector< DiscoveredBoard > get_discovered_boards()
Get all discovered boards.
std::map< std::string, std::map< std::string, std::string > > config_
bool load_base_config(const std::string &config_path)
Load base configuration.
std::map< std::string, std::map< std::string, std::string > > get_config() const
Get current configuration.
bool update_with_boards(const std::vector< DiscoveredBoard > &boards)
Update configuration with discovered boards.
fsw::config::ActiveBoardKind BoardType
static uint8_t board_id
Definition main.cpp:30
Motorized ball valve position: raw ADC counts -> % open.
std::chrono::steady_clock::time_point last_discovery
Board signature/identifier structure.
std::string to_string() const
bool operator<(const BoardSignature &other) const
bool operator==(const BoardSignature &other) const
Discovered board information.
std::chrono::steady_clock::time_point last_seen
std::vector< SensorInfo > sensors
Detected sensor information from board.
std::string board(const std::string &name, const std::string &id, bool enabled=true)