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