STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
PWMTargets.hpp
Go to the documentation of this file.
1#pragma once
2
3/**
4 * @file PWMTargets.hpp
5 * @brief Resolve which hardware the controller PWMs, from config alone.
6 *
7 * An [actuator_roles] entry whose optional 4th element is "pwm_fuel" or "pwm_ox" is assigned to
8 * controller_service. That entry carries (channel, board_id), and [boards.*] maps board_id to an
9 * IP. This is the *only* statement of what the controller drives — the process has no independent
10 * notion of a "fuel board" — and it is the same fact ActuatorCommander reads to stop commanding
11 * those actuators during a burn, so the two cannot disagree about who owns a valve.
12 *
13 * Every step here used to have a fallback in controller_main.cpp: a missing role became CH3/CH8 on
14 * board 12, an undeclared board became "192.168.2.<board_id>", an empty board table became a
15 * synthesized 11-14, and two roles on two boards silently shared the first one's IP. All of them
16 * were this process asserting a rig layout only config knows, and all of them failed
17 * silent-wrong — PWM onto whatever hardware happened to sit on the guessed channel, behind a
18 * warning nobody reads. There are deliberately no fallbacks here: an unresolved target is
19 * reported, and the caller disables the fire gate.
20 *
21 * Split out of controller_main.cpp so it can be tested without standing up a service.
22 */
23
24#include <map>
25#include <string>
26#include <vector>
27
28#include "config/Config.hpp"
30
31namespace fsw {
32namespace control {
33
37 /** One human-readable line per problem. Empty means both targets are usable. */
38 std::vector<std::string> issues;
39
40 bool ok() const {
41 return issues.empty();
42 }
43};
44
45/** board_id → IP from [boards.*] (non-empty ip, first wins). No synthesized entries: a board this
46 * map does not hold is a board config did not declare. */
47inline std::map<int, std::string> boardIpMap(const fsw::config::Config& cfg) {
48 std::map<int, std::string> out;
49 for (const auto& b : cfg.boards)
50 if (!b.ip.empty() && b.board_id > 0 && !out.count(b.board_id))
51 out[b.board_id] = b.ip;
52 return out;
53}
54
56 const std::map<int, std::string> ips = boardIpMap(cfg);
58
59 auto resolve = [&](const char* assignment) -> ControllerService::PWMTarget {
61
62 // Collect every actuator claiming this assignment. More than one is a config error worth
63 // naming: silently taking the first would put PWM on a valve the operator did not intend,
64 // which is the same class of failure as the old name-matching fallbacks.
65 std::vector<std::string> claimants;
66 for (const auto& [name, role] : cfg.actuator_roles)
67 if (role.controller_role == assignment)
68 claimants.push_back(name);
69
70 if (claimants.empty()) {
71 res.issues.push_back(std::string("no [actuator_roles] entry is assigned \"") +
72 assignment + "\" — no actuator serves this PWM output");
73 return target;
74 }
75 if (claimants.size() > 1) {
76 std::string joined;
77 for (size_t i = 0; i < claimants.size(); ++i)
78 joined += (i ? ", " : "") + ("\"" + claimants[i] + "\"");
79 res.issues.push_back(
80 std::string("more than one [actuator_roles] entry is assigned \"") + assignment +
81 "\": " + joined);
82 return target;
83 }
84
85 const auto& name = claimants.front();
86 const auto& role = cfg.actuator_roles.at(name);
87 if (role.channel < 1) {
88 res.issues.push_back("\"" + name + "\" is assigned \"" + assignment +
89 "\" but declares no valid channel");
90 return target;
91 }
92 const auto ip_it = ips.find(role.board_id);
93 if (ip_it == ips.end()) {
94 res.issues.push_back("\"" + name + "\" is assigned \"" + assignment +
95 "\" but is on board_id " + std::to_string(role.board_id) +
96 ", which no [boards.*] section declares an ip for");
97 return target;
98 }
99 target.channel = static_cast<uint8_t>(role.channel);
100 target.board_ip = ip_it->second;
101 target.actuator_name = name;
102 return target;
103 };
104
105 res.fuel = resolve("pwm_fuel");
106 res.ox = resolve("pwm_ox");
107 return res;
108}
109
110} // namespace control
111} // namespace fsw
long target
Definition main.cpp:38
*brief create JSON pointer *sa reference_tokens const string_t const string_t & b
Definition json.hpp:13878
json_pointer res
Definition json.hpp:13957
std::map< int, std::string > boardIpMap(const fsw::config::Config &cfg)
board_id → IP from [boards.
PWMResolution resolvePWMTargets(const fsw::config::Config &cfg)
Motorized ball valve position: raw ADC counts -> % open.
The whole parsed config.toml, restricted to what C++ consumes.
Definition Config.hpp:264
Where one propellant's PWM commands go.
std::vector< std::string > issues
One human-readable line per problem.
ControllerService::PWMTarget ox
ControllerService::PWMTarget fuel