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