1 #include "config-validator.hpp"
2
3 #include "grouplayout.hpp"
4 #include "ledlayout.hpp"
5
6 #include <phosphor-logging/lg2.hpp>
7 #include <sdbusplus/bus.hpp>
8
9 using namespace phosphor::led;
10
11 namespace phosphor
12 {
13 namespace led
14 {
15
16 // Priority for a particular LED needs to stay SAME across all groups
17 using PriorityMap =
18 std::unordered_map<std::string,
19 std::optional<phosphor::led::Layout::Action>>;
20
isUsingGroupPriority(const phosphor::led::GroupMap & ledMap)21 static bool isUsingGroupPriority(const phosphor::led::GroupMap& ledMap)
22 {
23 for (const auto& [_, group] : ledMap)
24 {
25 if (group.priority != 0)
26 {
27 return true;
28 }
29 }
30 return false;
31 }
32
priorityToString(const std::optional<phosphor::led::Layout::Action> & priority)33 static std::string priorityToString(
34 const std::optional<phosphor::led::Layout::Action>& priority)
35 {
36 if (!priority.has_value())
37 {
38 return "none";
39 }
40 switch (priority.value())
41 {
42 case phosphor::led::Layout::Action::Off:
43 return "Off";
44 case phosphor::led::Layout::Action::On:
45 return "On";
46 case phosphor::led::Layout::Action::Blink:
47 return "Blink";
48 }
49 return "?";
50 }
51
52 /** @brief Validate the Priority of an LED is same across ALL groups
53 *
54 * @param[in] name - led name member of each group
55 * @param[in] priority - member priority of each group
56 * @param[out] priorityMap - std::unordered_map, key:name, value:priority
57 *
58 * @return
59 */
validatePriority(const std::string & name,const std::optional<phosphor::led::Layout::Action> & priority,PriorityMap & priorityMap)60 void validatePriority(
61 const std::string& name,
62 const std::optional<phosphor::led::Layout::Action>& priority,
63 PriorityMap& priorityMap)
64 {
65 auto iter = priorityMap.find(name);
66 if (iter == priorityMap.end())
67 {
68 priorityMap.emplace(name, priority);
69 return;
70 }
71
72 if (iter->second != priority)
73 {
74 throw ConfigValidationException(
75 error::LedPriorityMismatch, "?", name,
76 "Priority of the LED is not same across groups. Old Priority = " +
77 priorityToString(iter->second) +
78 ", New Priority = " + priorityToString(priority));
79 }
80 }
81
validateConfigV1GroupForLedPriority(const std::string groupName,const phosphor::led::Layout::GroupLayout & group,PriorityMap & priorityMap)82 static void validateConfigV1GroupForLedPriority(
83 const std::string groupName,
84 const phosphor::led::Layout::GroupLayout& group, PriorityMap& priorityMap)
85 {
86 if (group.priority != 0)
87 {
88 throw ConfigValidationException(
89 error::MixedLedAndGroupPriority, groupName,
90 "Cannot mix group priority and led priority");
91 }
92
93 for (const auto& ledAction : group.actionSet)
94 {
95 if (ledAction.priority == std::nullopt)
96 {
97 throw ConfigValidationException(error::MissingLedPriority,
98 groupName, ledAction.name,
99 "Need valid led priority");
100 }
101
102 // Same LEDs can be part of multiple groups. However, their
103 // priorities across groups need to match.
104 validatePriority(ledAction.name, ledAction.priority, priorityMap);
105 }
106 }
107
108 static void
validateConfigV1ForLedPriority(const phosphor::led::GroupMap & ledMap)109 validateConfigV1ForLedPriority(const phosphor::led::GroupMap& ledMap)
110 {
111 PriorityMap priorityMap{};
112 for (const auto& [groupName, group] : ledMap)
113 {
114 validateConfigV1GroupForLedPriority(groupName, group, priorityMap);
115 }
116 }
117
validateConfigV1GroupForGroupPriority(const std::string groupName,const phosphor::led::Layout::GroupLayout & group)118 static void validateConfigV1GroupForGroupPriority(
119 const std::string groupName,
120 const phosphor::led::Layout::GroupLayout& group)
121 {
122 for (const auto& led : group.actionSet)
123 {
124 if (led.priority != std::nullopt)
125 {
126 throw ConfigValidationException(
127 error::MixedLedAndGroupPriority, groupName, led.name,
128 "Cannot mix group priority and led priority for LED");
129 }
130 }
131
132 if (group.priority == 0)
133 {
134 // group priority 0 is for internal use
135 throw ConfigValidationException(error::InvalidGroupPriority, groupName,
136 "Group Priority cannot be 0");
137 }
138 }
139
140 static void
validateConfigV1ForGroupPriority(const phosphor::led::GroupMap & ledMap)141 validateConfigV1ForGroupPriority(const phosphor::led::GroupMap& ledMap)
142 {
143 std::set<int> groupPriorities;
144 for (const auto& [_, group] : ledMap)
145 {
146 groupPriorities.insert(group.priority);
147 }
148
149 if (groupPriorities.size() != ledMap.size())
150 {
151 throw ConfigValidationException(
152 error::DuplicateGroupPriority,
153 "When using Group Priority, no 2 Groups may have the same priority");
154 }
155
156 for (const auto& [groupName, group] : ledMap)
157 {
158 validateConfigV1GroupForGroupPriority(groupName, group);
159 }
160 }
161
validateConfigV1(const GroupMap & ledMap)162 void validateConfigV1(const GroupMap& ledMap)
163 {
164 const bool useGroupPriority = isUsingGroupPriority(ledMap);
165
166 if (useGroupPriority)
167 {
168 validateConfigV1ForGroupPriority(ledMap);
169 }
170 else
171 {
172 validateConfigV1ForLedPriority(ledMap);
173 }
174 }
175
176 } // namespace led
177 } // namespace phosphor
178