1 #pragma once
2 
3 #include "libpldmresponder/pdr_utils.hpp"
4 
5 #include <libpldm/platform.h>
6 
7 #include <phosphor-logging/lg2.hpp>
8 
9 PHOSPHOR_LOG2_USING;
10 
11 namespace pldm
12 {
13 namespace responder
14 {
15 namespace pdr_state_sensor
16 {
17 using Json = nlohmann::json;
18 
19 static const Json empty{};
20 
21 /** @brief Parse PDR JSON file and generate state sensor PDR structure
22  *
23  *  @param[in] json - the JSON Object with the state sensor PDR
24  *  @param[out] handler - the Parser of PLDM command handler
25  *  @param[out] repo - pdr::RepoInterface
26  *
27  */
28 template <class DBusInterface, class Handler>
29 void generateStateSensorPDR(const DBusInterface& dBusIntf, const Json& json,
30                             Handler& handler, pdr_utils::RepoInterface& repo)
31 {
32     static const std::vector<Json> emptyList{};
33     auto entries = json.value("entries", emptyList);
34     for (const auto& e : entries)
35     {
36         size_t pdrSize = 0;
37         auto sensors = e.value("sensors", emptyList);
38         for (const auto& sensor : sensors)
39         {
40             auto set = sensor.value("set", empty);
41             auto statesSize = set.value("size", 0);
42             if (!statesSize)
43             {
44                 error(
45                     "Malformed PDR JSON return pdrEntry; no state set info for state sensor pdr '{STATE_SENSOR_PDR}'",
46                     "STATE_SENSOR_PDR", PLDM_STATE_SENSOR_PDR);
47                 throw InternalFailure();
48             }
49             pdrSize += sizeof(state_sensor_possible_states) -
50                        sizeof(bitfield8_t) + (sizeof(bitfield8_t) * statesSize);
51         }
52         pdrSize += sizeof(pldm_state_sensor_pdr) - sizeof(uint8_t);
53 
54         std::vector<uint8_t> entry{};
55         entry.resize(pdrSize);
56 
57         pldm_state_sensor_pdr* pdr =
58             reinterpret_cast<pldm_state_sensor_pdr*>(entry.data());
59         if (!pdr)
60         {
61             error("Failed to get state sensor PDR.");
62             continue;
63         }
64         pdr->hdr.record_handle = 0;
65         pdr->hdr.version = 1;
66         pdr->hdr.type = PLDM_STATE_SENSOR_PDR;
67         pdr->hdr.record_change_num = 0;
68         pdr->hdr.length = pdrSize - sizeof(pldm_pdr_hdr);
69 
70         HTOLE32(pdr->hdr.record_handle);
71         HTOLE16(pdr->hdr.record_change_num);
72         HTOLE16(pdr->hdr.length);
73 
74         pdr->terminus_handle = TERMINUS_HANDLE;
75 
76         try
77         {
78             std::string entity_path = e.value("entity_path", "");
79             auto& associatedEntityMap = handler.getAssociateEntityMap();
80             if (entity_path != "" && associatedEntityMap.contains(entity_path))
81             {
82                 pdr->entity_type =
83                     associatedEntityMap.at(entity_path).entity_type;
84                 pdr->entity_instance =
85                     associatedEntityMap.at(entity_path).entity_instance_num;
86                 pdr->container_id =
87                     associatedEntityMap.at(entity_path).entity_container_id;
88             }
89             else
90             {
91                 pdr->entity_type = e.value("type", 0);
92                 pdr->entity_instance = e.value("instance", 0);
93                 pdr->container_id = e.value("container", 0);
94 
95                 // do not create the PDR when the FRU or the entity path is not
96                 // present
97                 if (!pdr->entity_type)
98                 {
99                     continue;
100                 }
101             }
102         }
103         catch (const std::exception&)
104         {
105             pdr->entity_type = e.value("type", 0);
106             pdr->entity_instance = e.value("instance", 0);
107             pdr->container_id = e.value("container", 0);
108         }
109 
110         pdr->sensor_init = PLDM_NO_INIT;
111         pdr->sensor_auxiliary_names_pdr = false;
112         if (sensors.size() > 8)
113         {
114             throw std::runtime_error("sensor size must be less than 8");
115         }
116         pdr->composite_sensor_count = sensors.size();
117 
118         HTOLE16(pdr->terminus_handle);
119         HTOLE16(pdr->entity_type);
120         HTOLE16(pdr->entity_instance);
121         HTOLE16(pdr->container_id);
122 
123         pldm::responder::pdr_utils::DbusMappings dbusMappings{};
124         pldm::responder::pdr_utils::DbusValMaps dbusValMaps{};
125         uint8_t* start =
126             entry.data() + sizeof(pldm_state_sensor_pdr) - sizeof(uint8_t);
127         for (const auto& sensor : sensors)
128         {
129             auto set = sensor.value("set", empty);
130             state_sensor_possible_states* possibleStates =
131                 reinterpret_cast<state_sensor_possible_states*>(start);
132             possibleStates->state_set_id = set.value("id", 0);
133             HTOLE16(possibleStates->state_set_id);
134             possibleStates->possible_states_size = set.value("size", 0);
135 
136             start += sizeof(possibleStates->state_set_id) +
137                      sizeof(possibleStates->possible_states_size);
138             static const std::vector<uint8_t> emptyStates{};
139             pldm::responder::pdr_utils::PossibleValues stateValues;
140             auto states = set.value("states", emptyStates);
141             for (const auto& state : states)
142             {
143                 auto index = state / 8;
144                 auto bit = state - (index * 8);
145                 bitfield8_t* bf = reinterpret_cast<bitfield8_t*>(start + index);
146                 bf->byte |= 1 << bit;
147                 stateValues.emplace_back(state);
148             }
149             start += possibleStates->possible_states_size;
150             auto dbusEntry = sensor.value("dbus", empty);
151             auto objectPath = dbusEntry.value("path", "");
152             auto interface = dbusEntry.value("interface", "");
153             auto propertyName = dbusEntry.value("property_name", "");
154             auto propertyType = dbusEntry.value("property_type", "");
155 
156             pldm::responder::pdr_utils::StatestoDbusVal dbusIdToValMap{};
157             pldm::utils::DBusMapping dbusMapping{};
158             try
159             {
160                 auto service =
161                     dBusIntf.getService(objectPath.c_str(), interface.c_str());
162 
163                 dbusMapping = pldm::utils::DBusMapping{
164                     objectPath, interface, propertyName, propertyType};
165                 dbusIdToValMap = pldm::responder::pdr_utils::populateMapping(
166                     propertyType, dbusEntry["property_values"], stateValues);
167             }
168             catch (const std::exception& e)
169             {
170                 error(
171                     "Failed to create sensor PDR, D-Bus object '{PATH}' returned error - {ERROR}",
172                     "PATH", objectPath, "ERROR", e);
173                 break;
174             }
175             dbusMappings.emplace_back(std::move(dbusMapping));
176             dbusValMaps.emplace_back(std::move(dbusIdToValMap));
177         }
178 
179         if (!(dbusMappings.empty() && dbusValMaps.empty()))
180         {
181             pdr->sensor_id = handler.getNextSensorId();
182             HTOLE16(pdr->sensor_id);
183             handler.addDbusObjMaps(
184                 pdr->sensor_id,
185                 std::make_tuple(std::move(dbusMappings),
186                                 std::move(dbusValMaps)),
187                 pldm::responder::pdr_utils::TypeId::PLDM_SENSOR_ID);
188             pldm::responder::pdr_utils::PdrEntry pdrEntry{};
189             pdrEntry.data = entry.data();
190             pdrEntry.size = pdrSize;
191             repo.addRecord(pdrEntry);
192         }
193     }
194 }
195 
196 } // namespace pdr_state_sensor
197 } // namespace responder
198 } // namespace pldm
199