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, TYPE={STATE_SENSOR_PDR}",
46                     "STATE_SENSOR_PDR",
47                     static_cast<int>(PLDM_STATE_SENSOR_PDR));
48                 throw InternalFailure();
49             }
50             pdrSize += sizeof(state_sensor_possible_states) -
51                        sizeof(bitfield8_t) + (sizeof(bitfield8_t) * statesSize);
52         }
53         pdrSize += sizeof(pldm_state_sensor_pdr) - sizeof(uint8_t);
54 
55         std::vector<uint8_t> entry{};
56         entry.resize(pdrSize);
57 
58         pldm_state_sensor_pdr* pdr =
59             reinterpret_cast<pldm_state_sensor_pdr*>(entry.data());
60         if (!pdr)
61         {
62             error("Failed to get state sensor PDR.");
63             continue;
64         }
65         pdr->hdr.record_handle = 0;
66         pdr->hdr.version = 1;
67         pdr->hdr.type = PLDM_STATE_SENSOR_PDR;
68         pdr->hdr.record_change_num = 0;
69         pdr->hdr.length = pdrSize - sizeof(pldm_pdr_hdr);
70 
71         HTOLE32(pdr->hdr.record_handle);
72         HTOLE16(pdr->hdr.record_change_num);
73         HTOLE16(pdr->hdr.length);
74 
75         pdr->terminus_handle = TERMINUS_HANDLE;
76         pdr->sensor_id = handler.getNextSensorId();
77 
78         try
79         {
80             std::string entity_path = e.value("entity_path", "");
81             auto& associatedEntityMap = handler.getAssociateEntityMap();
82             if (entity_path != "" && associatedEntityMap.find(entity_path) !=
83                                          associatedEntityMap.end())
84             {
85                 pdr->entity_type =
86                     associatedEntityMap.at(entity_path).entity_type;
87                 pdr->entity_instance =
88                     associatedEntityMap.at(entity_path).entity_instance_num;
89                 pdr->container_id =
90                     associatedEntityMap.at(entity_path).entity_container_id;
91             }
92             else
93             {
94                 pdr->entity_type = e.value("type", 0);
95                 pdr->entity_instance = e.value("instance", 0);
96                 pdr->container_id = e.value("container", 0);
97 
98                 // do not create the PDR when the FRU or the entity path is not
99                 // present
100                 if (!pdr->entity_type)
101                 {
102                     std::cerr << "The entity path for the FRU is not present."
103                               << std::endl;
104                     continue;
105                 }
106             }
107         }
108         catch (const std::exception& ex)
109         {
110             pdr->entity_type = e.value("type", 0);
111             pdr->entity_instance = e.value("instance", 0);
112             pdr->container_id = e.value("container", 0);
113         }
114 
115         pdr->sensor_init = PLDM_NO_INIT;
116         pdr->sensor_auxiliary_names_pdr = false;
117         if (sensors.size() > 8)
118         {
119             throw std::runtime_error("sensor size must be less than 8");
120         }
121         pdr->composite_sensor_count = sensors.size();
122 
123         HTOLE16(pdr->terminus_handle);
124         HTOLE16(pdr->sensor_id);
125         HTOLE16(pdr->entity_type);
126         HTOLE16(pdr->entity_instance);
127         HTOLE16(pdr->container_id);
128 
129         pldm::responder::pdr_utils::DbusMappings dbusMappings{};
130         pldm::responder::pdr_utils::DbusValMaps dbusValMaps{};
131         uint8_t* start = entry.data() + sizeof(pldm_state_sensor_pdr) -
132                          sizeof(uint8_t);
133         for (const auto& sensor : sensors)
134         {
135             auto set = sensor.value("set", empty);
136             state_sensor_possible_states* possibleStates =
137                 reinterpret_cast<state_sensor_possible_states*>(start);
138             possibleStates->state_set_id = set.value("id", 0);
139             HTOLE16(possibleStates->state_set_id);
140             possibleStates->possible_states_size = set.value("size", 0);
141 
142             start += sizeof(possibleStates->state_set_id) +
143                      sizeof(possibleStates->possible_states_size);
144             static const std::vector<uint8_t> emptyStates{};
145             pldm::responder::pdr_utils::PossibleValues stateValues;
146             auto states = set.value("states", emptyStates);
147             for (const auto& state : states)
148             {
149                 auto index = state / 8;
150                 auto bit = state - (index * 8);
151                 bitfield8_t* bf = reinterpret_cast<bitfield8_t*>(start + index);
152                 bf->byte |= 1 << bit;
153                 stateValues.emplace_back(state);
154             }
155             start += possibleStates->possible_states_size;
156             auto dbusEntry = sensor.value("dbus", empty);
157             auto objectPath = dbusEntry.value("path", "");
158             auto interface = dbusEntry.value("interface", "");
159             auto propertyName = dbusEntry.value("property_name", "");
160             auto propertyType = dbusEntry.value("property_type", "");
161 
162             pldm::responder::pdr_utils::StatestoDbusVal dbusIdToValMap{};
163             pldm::utils::DBusMapping dbusMapping{};
164             try
165             {
166                 auto service = dBusIntf.getService(objectPath.c_str(),
167                                                    interface.c_str());
168 
169                 dbusMapping = pldm::utils::DBusMapping{
170                     objectPath, interface, propertyName, propertyType};
171                 dbusIdToValMap = pldm::responder::pdr_utils::populateMapping(
172                     propertyType, dbusEntry["property_values"], stateValues);
173             }
174             catch (const std::exception& e)
175             {
176                 error(
177                     "D-Bus object path does not exist, sensor ID: {SENSOR_ID}",
178                     "SENSOR_ID", static_cast<uint16_t>(pdr->sensor_id));
179             }
180 
181             dbusMappings.emplace_back(std::move(dbusMapping));
182             dbusValMaps.emplace_back(std::move(dbusIdToValMap));
183         }
184 
185         handler.addDbusObjMaps(
186             pdr->sensor_id,
187             std::make_tuple(std::move(dbusMappings), std::move(dbusValMaps)),
188             pldm::responder::pdr_utils::TypeId::PLDM_SENSOR_ID);
189         pldm::responder::pdr_utils::PdrEntry pdrEntry{};
190         pdrEntry.data = entry.data();
191         pdrEntry.size = pdrSize;
192         repo.addRecord(pdrEntry);
193     }
194 }
195 
196 } // namespace pdr_state_sensor
197 } // namespace responder
198 } // namespace pldm
199