blob: 97b0c3612c510fff587465147aca1f3b96116fe9 [file] [log] [blame]
Gilbert Chen6c7fed42022-02-22 15:40:17 +00001#include "terminus.hpp"
2
Dung Caob6d39432024-06-05 03:46:47 +00003#include "dbus_impl_fru.hpp"
Gilbert Chen6c7fed42022-02-22 15:40:17 +00004#include "terminus_manager.hpp"
5
Manojkiran Edafe252792025-03-13 19:24:19 +05306#include <libpldm/platform.h>
7
Thu Nguyenb8cf46b2024-06-15 02:44:35 +00008#include <common/utils.hpp>
9
Gilbert Chende2a1322022-05-24 15:35:21 +010010#include <ranges>
11
Gilbert Chen6c7fed42022-02-22 15:40:17 +000012namespace pldm
13{
14namespace platform_mc
15{
16
Chaul Lyfdf61cc2025-01-22 07:55:45 +000017Terminus::Terminus(pldm_tid_t tid, uint64_t supportedTypes,
18 sdeventplus::Event& event) :
Gilbert Chen77e6fe72024-08-06 09:23:30 +000019 initialized(false), maxBufferSize(PLDM_PLATFORM_EVENT_MSG_MAX_BUFFER_SIZE),
Dung Caof48015b2023-11-21 04:38:29 +000020 synchronyConfigurationSupported(0), pollEvent(false), tid(tid),
Chaul Lyfdf61cc2025-01-22 07:55:45 +000021 supportedTypes(supportedTypes), event(event)
Gilbert Chen6c7fed42022-02-22 15:40:17 +000022{}
23
24bool Terminus::doesSupportType(uint8_t type)
25{
26 return supportedTypes.test(type);
27}
28
29bool Terminus::doesSupportCommand(uint8_t type, uint8_t command)
30{
31 if (!doesSupportType(type))
32 {
33 return false;
34 }
35
36 try
37 {
38 const size_t idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + (command / 8);
39 if (idx >= supportedCmds.size())
40 {
41 return false;
42 }
43
44 if (supportedCmds[idx] & (1 << (command % 8)))
45 {
46 lg2::info(
47 "PLDM type {TYPE} command {CMD} is supported by terminus {TID}",
48 "TYPE", type, "CMD", command, "TID", getTid());
49 return true;
50 }
51 }
52 catch (const std::exception& e)
53 {
54 return false;
55 }
56
57 return false;
58}
59
Thu Nguyenb8cf46b2024-06-15 02:44:35 +000060std::optional<std::string_view> Terminus::findTerminusName()
61{
62 auto it = std::find_if(
63 entityAuxiliaryNamesTbl.begin(), entityAuxiliaryNamesTbl.end(),
64 [](const std::shared_ptr<EntityAuxiliaryNames>& entityAuxiliaryNames) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -040065 const auto& [key, entityNames] = *entityAuxiliaryNames;
66 /**
Manojkiran Eda04ac9972024-09-06 10:57:12 +053067 * There is only one Overall system container entity in one
68 * terminus. The entity auxiliary name PDR of that terminus with the
69 * that type of containerID will include terminus name.
70 */
Patrick Williams16c2a0a2024-08-16 15:20:59 -040071 return (
72 entityAuxiliaryNames &&
Thu Nguyenb8cf46b2024-06-15 02:44:35 +000073 key.containerId == PLDM_PLATFORM_ENTITY_SYSTEM_CONTAINER_ID &&
74 entityNames.size());
Patrick Williams16c2a0a2024-08-16 15:20:59 -040075 });
Thu Nguyenb8cf46b2024-06-15 02:44:35 +000076
77 if (it != entityAuxiliaryNamesTbl.end())
78 {
79 const auto& [key, entityNames] = **it;
80 if (!entityNames.size())
81 {
82 return std::nullopt;
83 }
84 return entityNames[0].second;
85 }
86
87 return std::nullopt;
88}
89
Thu Nguyen3c5486d2024-08-01 08:03:08 +000090bool Terminus::createInventoryPath(std::string tName)
91{
92 if (tName.empty())
93 {
94 return false;
95 }
96
Dung Caob6d39432024-06-05 03:46:47 +000097 /* inventory object is created */
98 if (inventoryItemBoardInft)
99 {
100 return false;
101 }
102
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000103 inventoryPath = "/xyz/openbmc_project/inventory/system/board/" + tName;
104 try
105 {
Dung Caob6d39432024-06-05 03:46:47 +0000106 inventoryItemBoardInft =
107 std::make_unique<pldm::dbus_api::PldmEntityReq>(
108 utils::DBusHandler::getBus(), inventoryPath.c_str());
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000109 return true;
110 }
111 catch (const sdbusplus::exception_t& e)
112 {
113 lg2::error(
114 "Failed to create Inventory Board interface for device {PATH}",
115 "PATH", inventoryPath);
116 }
117
118 return false;
119}
120
Gilbert Chende2a1322022-05-24 15:35:21 +0100121void Terminus::parseTerminusPDRs()
122{
Gilbert Chende2a1322022-05-24 15:35:21 +0100123 for (auto& pdr : pdrs)
124 {
Pavithra Barithaya36b36932025-01-30 10:33:05 +0530125 auto pdrHdr = new (pdr.data()) pldm_pdr_hdr;
Gilbert Chende2a1322022-05-24 15:35:21 +0100126 switch (pdrHdr->type)
127 {
128 case PLDM_SENSOR_AUXILIARY_NAMES_PDR:
129 {
130 auto sensorAuxNames = parseSensorAuxiliaryNamesPDR(pdr);
131 if (!sensorAuxNames)
132 {
133 lg2::error(
134 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
135 "TYPE", pdrHdr->type, "HANDLE",
136 static_cast<uint32_t>(pdrHdr->record_handle));
137 continue;
138 }
139 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
140 break;
141 }
142 case PLDM_NUMERIC_SENSOR_PDR:
143 {
144 auto parsedPdr = parseNumericSensorPDR(pdr);
145 if (!parsedPdr)
146 {
147 lg2::error(
148 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
149 "TYPE", pdrHdr->type, "HANDLE",
150 static_cast<uint32_t>(pdrHdr->record_handle));
151 continue;
152 }
153 numericSensorPdrs.emplace_back(std::move(parsedPdr));
154 break;
155 }
156 case PLDM_COMPACT_NUMERIC_SENSOR_PDR:
157 {
158 auto parsedPdr = parseCompactNumericSensorPDR(pdr);
159 if (!parsedPdr)
160 {
161 lg2::error(
162 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
163 "TYPE", pdrHdr->type, "HANDLE",
164 static_cast<uint32_t>(pdrHdr->record_handle));
165 continue;
166 }
167 auto sensorAuxNames = parseCompactNumericSensorNames(pdr);
168 if (!sensorAuxNames)
169 {
170 lg2::error(
171 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
172 "TYPE", pdrHdr->type, "HANDLE",
173 static_cast<uint32_t>(pdrHdr->record_handle));
174 continue;
175 }
176 compactNumericSensorPdrs.emplace_back(std::move(parsedPdr));
177 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
178 break;
179 }
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000180 case PLDM_ENTITY_AUXILIARY_NAMES_PDR:
181 {
182 auto entityNames = parseEntityAuxiliaryNamesPDR(pdr);
183 if (!entityNames)
184 {
185 lg2::error(
186 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
187 "TYPE", pdrHdr->type, "HANDLE",
188 static_cast<uint32_t>(pdrHdr->record_handle));
189 continue;
190 }
191 entityAuxiliaryNamesTbl.emplace_back(std::move(entityNames));
192 break;
193 }
Gilbert Chende2a1322022-05-24 15:35:21 +0100194 default:
195 {
196 lg2::error("Unsupported PDR with type {TYPE} handle {HANDLE}",
197 "TYPE", pdrHdr->type, "HANDLE",
198 static_cast<uint32_t>(pdrHdr->record_handle));
199 break;
200 }
201 }
202 }
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000203
204 auto tName = findTerminusName();
205 if (tName && !tName.value().empty())
206 {
207 lg2::info("Terminus {TID} has Auxiliary Name {NAME}.", "TID", tid,
208 "NAME", tName.value());
209 terminusName = static_cast<std::string>(tName.value());
210 }
Aditya Kurdunkar8eedaa62025-08-18 21:21:08 +0530211 else
212 {
213 terminusName = std::format("Terminus_{}", tid);
214 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000215
216 if (terminusName.empty() &&
217 (numericSensorPdrs.size() || compactNumericSensorPdrs.size()))
218 {
219 lg2::error(
220 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
221 "TID", tid);
222 return;
223 }
224
225 if (createInventoryPath(terminusName))
226 {
Konstantin Aladyshev12daa102025-08-04 17:42:06 +0300227 lg2::info("Terminus ID {TID}: Created Inventory path {PATH}.", "TID",
228 tid, "PATH", inventoryPath);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000229 }
230
Chaul Lyfdf61cc2025-01-22 07:55:45 +0000231 addNextSensorFromPDRs();
232}
233
234void Terminus::addNextSensorFromPDRs()
235{
236 sensorCreationEvent.reset();
237
238 if (terminusName.empty())
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000239 {
Chaul Lyfdf61cc2025-01-22 07:55:45 +0000240 lg2::error(
241 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
242 "TID", tid);
243 return;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000244 }
245
Chaul Lyfdf61cc2025-01-22 07:55:45 +0000246 auto pdrIt = sensorPdrIt;
247
248 if (pdrIt < numericSensorPdrs.size())
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000249 {
Chaul Lyfdf61cc2025-01-22 07:55:45 +0000250 const auto& pdr = numericSensorPdrs[pdrIt];
251 // Defer adding the next Numeric Sensor
252 sensorCreationEvent = std::make_unique<sdeventplus::source::Defer>(
253 event,
254 std::bind(std::mem_fn(&Terminus::addNumericSensor), this, pdr));
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000255 }
Chaul Lyfdf61cc2025-01-22 07:55:45 +0000256 else if (pdrIt < numericSensorPdrs.size() + compactNumericSensorPdrs.size())
257 {
258 pdrIt -= numericSensorPdrs.size();
259 const auto& pdr = compactNumericSensorPdrs[pdrIt];
260 // Defer adding the next Compact Numeric Sensor
261 sensorCreationEvent = std::make_unique<sdeventplus::source::Defer>(
262 event, std::bind(std::mem_fn(&Terminus::addCompactNumericSensor),
263 this, pdr));
264 }
265 else
266 {
267 sensorPdrIt = 0;
268 return;
269 }
270
271 // Move the iteration to the next sensor PDR
272 sensorPdrIt++;
Gilbert Chende2a1322022-05-24 15:35:21 +0100273}
274
Patrick Williams366507c2025-02-03 14:28:01 -0500275std::shared_ptr<SensorAuxiliaryNames> Terminus::getSensorAuxiliaryNames(
Chau Ly3419e182025-07-29 07:11:32 +0000276 SensorID id)
Gilbert Chende2a1322022-05-24 15:35:21 +0100277{
278 auto it = std::find_if(
279 sensorAuxiliaryNamesTbl.begin(), sensorAuxiliaryNamesTbl.end(),
280 [id](
281 const std::shared_ptr<SensorAuxiliaryNames>& sensorAuxiliaryNames) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400282 const auto& [sensorId, sensorCnt, sensorNames] =
283 *sensorAuxiliaryNames;
284 return sensorId == id;
285 });
Gilbert Chende2a1322022-05-24 15:35:21 +0100286
287 if (it != sensorAuxiliaryNamesTbl.end())
288 {
289 return *it;
290 }
291 return nullptr;
292};
293
Patrick Williams366507c2025-02-03 14:28:01 -0500294std::shared_ptr<SensorAuxiliaryNames> Terminus::parseSensorAuxiliaryNamesPDR(
295 const std::vector<uint8_t>& pdrData)
Gilbert Chende2a1322022-05-24 15:35:21 +0100296{
297 constexpr uint8_t nullTerminator = 0;
298 auto pdr = reinterpret_cast<const struct pldm_sensor_auxiliary_names_pdr*>(
299 pdrData.data());
300 const uint8_t* ptr = pdr->names;
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000301 std::vector<AuxiliaryNames> sensorAuxNames{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100302 char16_t alignedBuffer[PLDM_STR_UTF_16_MAX_LEN];
303 for ([[maybe_unused]] const auto& sensor :
304 std::views::iota(0, static_cast<int>(pdr->sensor_count)))
305 {
306 const uint8_t nameStringCount = static_cast<uint8_t>(*ptr);
307 ptr += sizeof(uint8_t);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000308 AuxiliaryNames nameStrings{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100309 for ([[maybe_unused]] const auto& count :
310 std::views::iota(0, static_cast<int>(nameStringCount)))
311 {
312 std::string_view nameLanguageTag(
313 reinterpret_cast<const char*>(ptr));
314 ptr += nameLanguageTag.size() + sizeof(nullTerminator);
315
316 int u16NameStringLen = 0;
317 for (int i = 0; ptr[i] != 0 || ptr[i + 1] != 0; i += 2)
318 {
319 u16NameStringLen++;
320 }
321 /* include terminator */
322 u16NameStringLen++;
323
324 std::fill(std::begin(alignedBuffer), std::end(alignedBuffer), 0);
325 if (u16NameStringLen > PLDM_STR_UTF_16_MAX_LEN)
326 {
Chau Ly38a09d22025-03-05 05:47:43 +0000327 lg2::error("Sensor name too long.");
Gilbert Chende2a1322022-05-24 15:35:21 +0100328 return nullptr;
329 }
330 memcpy(alignedBuffer, ptr, u16NameStringLen * sizeof(uint16_t));
331 std::u16string u16NameString(alignedBuffer, u16NameStringLen);
tal-yacf1e32c12024-08-12 13:12:30 +0300332 ptr += u16NameString.size() * sizeof(uint16_t);
Gilbert Chende2a1322022-05-24 15:35:21 +0100333 std::transform(u16NameString.cbegin(), u16NameString.cend(),
334 u16NameString.begin(),
335 [](uint16_t utf16) { return be16toh(utf16); });
Patrick Williams15d42c52025-07-03 16:46:40 -0400336#pragma GCC diagnostic push
337#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Gilbert Chende2a1322022-05-24 15:35:21 +0100338 std::string nameString =
339 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,
340 char16_t>{}
341 .to_bytes(u16NameString);
Patrick Williams15d42c52025-07-03 16:46:40 -0400342#pragma GCC diagnostic pop
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000343 nameStrings.emplace_back(std::make_pair(
344 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100345 }
346 sensorAuxNames.emplace_back(std::move(nameStrings));
347 }
348 return std::make_shared<SensorAuxiliaryNames>(
349 pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames));
350}
351
Patrick Williams366507c2025-02-03 14:28:01 -0500352std::shared_ptr<EntityAuxiliaryNames> Terminus::parseEntityAuxiliaryNamesPDR(
353 const std::vector<uint8_t>& pdrData)
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000354{
355 auto names_offset = sizeof(struct pldm_pdr_hdr) +
356 PLDM_PDR_ENTITY_AUXILIARY_NAME_PDR_MIN_LENGTH;
357 auto names_size = pdrData.size() - names_offset;
358
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400359 size_t decodedPdrSize =
360 sizeof(struct pldm_entity_auxiliary_names_pdr) + names_size;
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000361 auto vPdr = std::vector<char>(decodedPdrSize);
Pavithra Barithaya36b36932025-01-30 10:33:05 +0530362 auto decodedPdr = new (vPdr.data()) pldm_entity_auxiliary_names_pdr;
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000363
364 auto rc = decode_entity_auxiliary_names_pdr(pdrData.data(), pdrData.size(),
365 decodedPdr, decodedPdrSize);
366
367 if (rc)
368 {
369 lg2::error(
370 "Failed to decode Entity Auxiliary Name PDR data, error {RC}.",
371 "RC", rc);
372 return nullptr;
373 }
374
375 auto vNames =
376 std::vector<pldm_entity_auxiliary_name>(decodedPdr->name_string_count);
377 decodedPdr->names = vNames.data();
378
379 rc = decode_pldm_entity_auxiliary_names_pdr_index(decodedPdr);
380 if (rc)
381 {
382 lg2::error("Failed to decode Entity Auxiliary Name, error {RC}.", "RC",
383 rc);
384 return nullptr;
385 }
386
387 AuxiliaryNames nameStrings{};
388 for (const auto& count :
389 std::views::iota(0, static_cast<int>(decodedPdr->name_string_count)))
390 {
391 std::string_view nameLanguageTag =
392 static_cast<std::string_view>(decodedPdr->names[count].tag);
393 const size_t u16NameStringLen =
394 std::char_traits<char16_t>::length(decodedPdr->names[count].name);
395 std::u16string u16NameString(decodedPdr->names[count].name,
396 u16NameStringLen);
397 std::transform(u16NameString.cbegin(), u16NameString.cend(),
398 u16NameString.begin(),
399 [](uint16_t utf16) { return be16toh(utf16); });
Patrick Williams15d42c52025-07-03 16:46:40 -0400400#pragma GCC diagnostic push
401#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000402 std::string nameString =
403 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
404 .to_bytes(u16NameString);
Patrick Williams15d42c52025-07-03 16:46:40 -0400405#pragma GCC diagnostic pop
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000406 nameStrings.emplace_back(std::make_pair(
407 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
408 }
409
410 EntityKey key{decodedPdr->container.entity_type,
411 decodedPdr->container.entity_instance_num,
412 decodedPdr->container.entity_container_id};
413
414 return std::make_shared<EntityAuxiliaryNames>(key, nameStrings);
415}
416
Patrick Williams366507c2025-02-03 14:28:01 -0500417std::shared_ptr<pldm_numeric_sensor_value_pdr> Terminus::parseNumericSensorPDR(
418 const std::vector<uint8_t>& pdr)
Gilbert Chende2a1322022-05-24 15:35:21 +0100419{
420 const uint8_t* ptr = pdr.data();
421 auto parsedPdr = std::make_shared<pldm_numeric_sensor_value_pdr>();
422 auto rc = decode_numeric_sensor_pdr_data(ptr, pdr.size(), parsedPdr.get());
423 if (rc)
424 {
425 return nullptr;
426 }
427 return parsedPdr;
428}
429
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000430void Terminus::addNumericSensor(
431 const std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr)
432{
Chau Ly38a09d22025-03-05 05:47:43 +0000433 if (!pdr)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000434 {
Chau Ly38a09d22025-03-05 05:47:43 +0000435 lg2::error(
436 "Terminus ID {TID}: Skip adding Numeric Sensor - invalid pointer to PDR.",
437 "TID", tid);
Chaul Lyfdf61cc2025-01-22 07:55:45 +0000438 addNextSensorFromPDRs();
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000439 }
440
Chau Ly38a09d22025-03-05 05:47:43 +0000441 auto sensorId = pdr->sensor_id;
442 auto sensorNames = getSensorNames(sensorId);
443
444 if (sensorNames.empty())
445 {
446 lg2::error(
447 "Terminus ID {TID}: Failed to get name for Numeric Sensor {SID}",
448 "TID", tid, "SID", sensorId);
Chaul Lyfdf61cc2025-01-22 07:55:45 +0000449 addNextSensorFromPDRs();
Chau Ly38a09d22025-03-05 05:47:43 +0000450 }
451
452 std::string sensorName = sensorNames.front();
453
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000454 try
455 {
456 auto sensor = std::make_shared<NumericSensor>(
457 tid, true, pdr, sensorName, inventoryPath);
458 lg2::info("Created NumericSensor {NAME}", "NAME", sensorName);
459 numericSensors.emplace_back(sensor);
460 }
461 catch (const sdbusplus::exception_t& e)
462 {
463 lg2::error(
464 "Failed to create NumericSensor. error - {ERROR} sensorname - {NAME}",
465 "ERROR", e, "NAME", sensorName);
466 }
Chaul Lyfdf61cc2025-01-22 07:55:45 +0000467
468 addNextSensorFromPDRs();
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000469}
470
Patrick Williams366507c2025-02-03 14:28:01 -0500471std::shared_ptr<SensorAuxiliaryNames> Terminus::parseCompactNumericSensorNames(
472 const std::vector<uint8_t>& sPdr)
Gilbert Chende2a1322022-05-24 15:35:21 +0100473{
474 std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
475 sensorAuxNames{};
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000476 AuxiliaryNames nameStrings{};
Pavithra Barithaya36b36932025-01-30 10:33:05 +0530477
Gilbert Chende2a1322022-05-24 15:35:21 +0100478 auto pdr =
479 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
480
481 if (sPdr.size() <
482 (sizeof(pldm_compact_numeric_sensor_pdr) - sizeof(uint8_t)))
483 {
484 return nullptr;
485 }
486
487 if (!pdr->sensor_name_length ||
488 (sPdr.size() < (sizeof(pldm_compact_numeric_sensor_pdr) -
489 sizeof(uint8_t) + pdr->sensor_name_length)))
490 {
491 return nullptr;
492 }
493
494 std::string nameString(reinterpret_cast<const char*>(pdr->sensor_name),
495 pdr->sensor_name_length);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000496 nameStrings.emplace_back(
497 std::make_pair("en", pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100498 sensorAuxNames.emplace_back(std::move(nameStrings));
499
500 return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1,
501 std::move(sensorAuxNames));
502}
503
504std::shared_ptr<pldm_compact_numeric_sensor_pdr>
505 Terminus::parseCompactNumericSensorPDR(const std::vector<uint8_t>& sPdr)
506{
507 auto pdr =
508 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
509 if (sPdr.size() < sizeof(pldm_compact_numeric_sensor_pdr))
510 {
511 // Handle error: input data too small to contain valid pdr
512 return nullptr;
513 }
514 auto parsedPdr = std::make_shared<pldm_compact_numeric_sensor_pdr>();
515
516 parsedPdr->hdr = pdr->hdr;
517 parsedPdr->terminus_handle = pdr->terminus_handle;
518 parsedPdr->sensor_id = pdr->sensor_id;
519 parsedPdr->entity_type = pdr->entity_type;
520 parsedPdr->entity_instance = pdr->entity_instance;
521 parsedPdr->container_id = pdr->container_id;
522 parsedPdr->sensor_name_length = pdr->sensor_name_length;
523 parsedPdr->base_unit = pdr->base_unit;
524 parsedPdr->unit_modifier = pdr->unit_modifier;
525 parsedPdr->occurrence_rate = pdr->occurrence_rate;
526 parsedPdr->range_field_support = pdr->range_field_support;
527 parsedPdr->warning_high = pdr->warning_high;
528 parsedPdr->warning_low = pdr->warning_low;
529 parsedPdr->critical_high = pdr->critical_high;
530 parsedPdr->critical_low = pdr->critical_low;
531 parsedPdr->fatal_high = pdr->fatal_high;
532 parsedPdr->fatal_low = pdr->fatal_low;
533 return parsedPdr;
534}
535
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000536void Terminus::addCompactNumericSensor(
537 const std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr)
538{
Chau Ly38a09d22025-03-05 05:47:43 +0000539 if (!pdr)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000540 {
Chau Ly38a09d22025-03-05 05:47:43 +0000541 lg2::error(
542 "Terminus ID {TID}: Skip adding Compact Numeric Sensor - invalid pointer to PDR.",
543 "TID", tid);
Chaul Lyfdf61cc2025-01-22 07:55:45 +0000544 addNextSensorFromPDRs();
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000545 }
546
Chau Ly38a09d22025-03-05 05:47:43 +0000547 auto sensorId = pdr->sensor_id;
548 auto sensorNames = getSensorNames(sensorId);
549
550 if (sensorNames.empty())
551 {
552 lg2::error(
553 "Terminus ID {TID}: Failed to get name for Compact Numeric Sensor {SID}",
554 "TID", tid, "SID", sensorId);
Chaul Lyfdf61cc2025-01-22 07:55:45 +0000555 addNextSensorFromPDRs();
Chau Ly38a09d22025-03-05 05:47:43 +0000556 }
557
558 std::string sensorName = sensorNames.front();
559
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000560 try
561 {
562 auto sensor = std::make_shared<NumericSensor>(
563 tid, true, pdr, sensorName, inventoryPath);
564 lg2::info("Created Compact NumericSensor {NAME}", "NAME", sensorName);
565 numericSensors.emplace_back(sensor);
566 }
567 catch (const sdbusplus::exception_t& e)
568 {
569 lg2::error(
570 "Failed to create Compact NumericSensor. error - {ERROR} sensorname - {NAME}",
571 "ERROR", e, "NAME", sensorName);
572 }
Chaul Lyfdf61cc2025-01-22 07:55:45 +0000573
574 addNextSensorFromPDRs();
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000575}
576
Chau Ly3419e182025-07-29 07:11:32 +0000577std::shared_ptr<NumericSensor> Terminus::getSensorObject(SensorID id)
Gilbert Chen77e6fe72024-08-06 09:23:30 +0000578{
579 if (terminusName.empty())
580 {
581 lg2::error(
582 "Terminus ID {TID}: DOES NOT have terminus name. No numeric sensor object.",
583 "TID", tid);
584 return nullptr;
585 }
586 if (!numericSensors.size())
587 {
588 lg2::error("Terminus ID {TID} name {NAME}: DOES NOT have sensor.",
589 "TID", tid, "NAME", terminusName);
590 return nullptr;
591 }
592
593 for (auto& sensor : numericSensors)
594 {
595 if (!sensor)
596 {
597 continue;
598 }
599
600 if (sensor->sensorId == id)
601 {
602 return sensor;
603 }
604 }
605
606 return nullptr;
607}
Dung Caob6d39432024-06-05 03:46:47 +0000608
609/** @brief Check if a pointer is go through end of table
610 * @param[in] table - pointer to FRU record table
611 * @param[in] p - pointer to each record of FRU record table
612 * @param[in] tableSize - FRU table size
613 */
614static bool isTableEnd(const uint8_t* table, const uint8_t* p,
615 const size_t tableSize)
616{
617 auto offset = p - table;
618 return (tableSize - offset) < sizeof(struct pldm_fru_record_data_format);
619}
620
621void Terminus::updateInventoryWithFru(const uint8_t* fruData,
622 const size_t fruLen)
623{
624 auto tmp = getTerminusName();
625 if (!tmp || tmp.value().empty())
626 {
627 lg2::error(
628 "Terminus ID {TID}: Failed to update Inventory with Fru Data - error : Terminus name is empty.",
629 "TID", tid);
630 return;
631 }
632
633 if (createInventoryPath(static_cast<std::string>(tmp.value())))
634 {
635 lg2::info("Terminus ID {TID}: Created Inventory path.", "TID", tid);
636 }
637
638 auto ptr = fruData;
639 while (!isTableEnd(fruData, ptr, fruLen))
640 {
641 auto record = reinterpret_cast<const pldm_fru_record_data_format*>(ptr);
642 ptr += sizeof(pldm_fru_record_data_format) -
643 sizeof(pldm_fru_record_tlv);
644
645 if (!record->num_fru_fields)
646 {
647 lg2::error(
648 "Invalid number of fields {NUM} of Record ID Type {TYPE} of terminus {TID}",
649 "NUM", record->num_fru_fields, "TYPE", record->record_type,
650 "TID", tid);
651 return;
652 }
653
654 if (record->record_type != PLDM_FRU_RECORD_TYPE_GENERAL)
655 {
656 lg2::error(
657 "Does not support Fru Record ID Type {TYPE} of terminus {TID}",
658 "TYPE", record->record_type, "TID", tid);
659
660 for ([[maybe_unused]] const auto& idx :
661 std::views::iota(0, static_cast<int>(record->num_fru_fields)))
662 {
663 auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(ptr);
664 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length;
665 }
666 continue;
667 }
668 /* FRU General record type */
669 for ([[maybe_unused]] const auto& idx :
670 std::views::iota(0, static_cast<int>(record->num_fru_fields)))
671 {
672 auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(ptr);
673 std::string fruField{};
674 if (tlv->type != PLDM_FRU_FIELD_TYPE_IANA)
675 {
676 auto strOptional =
677 pldm::utils::fruFieldValuestring(tlv->value, tlv->length);
678 if (!strOptional)
679 {
680 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length;
681 continue;
682 }
683 fruField = strOptional.value();
684
685 if (fruField.empty())
686 {
687 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length;
688 continue;
689 }
690 }
691
692 switch (tlv->type)
693 {
694 case PLDM_FRU_FIELD_TYPE_MODEL:
695 inventoryItemBoardInft->model(fruField);
696 break;
697 case PLDM_FRU_FIELD_TYPE_PN:
698 inventoryItemBoardInft->partNumber(fruField);
699 break;
700 case PLDM_FRU_FIELD_TYPE_SN:
701 inventoryItemBoardInft->serialNumber(fruField);
702 break;
703 case PLDM_FRU_FIELD_TYPE_MANUFAC:
704 inventoryItemBoardInft->manufacturer(fruField);
705 break;
706 case PLDM_FRU_FIELD_TYPE_NAME:
707 inventoryItemBoardInft->names({fruField});
708 break;
709 case PLDM_FRU_FIELD_TYPE_VERSION:
710 inventoryItemBoardInft->version(fruField);
711 break;
712 case PLDM_FRU_FIELD_TYPE_ASSET_TAG:
713 inventoryItemBoardInft->assetTag(fruField);
714 break;
715 case PLDM_FRU_FIELD_TYPE_VENDOR:
716 case PLDM_FRU_FIELD_TYPE_CHASSIS:
717 case PLDM_FRU_FIELD_TYPE_SKU:
718 case PLDM_FRU_FIELD_TYPE_DESC:
719 case PLDM_FRU_FIELD_TYPE_EC_LVL:
720 case PLDM_FRU_FIELD_TYPE_OTHER:
721 break;
722 case PLDM_FRU_FIELD_TYPE_IANA:
723 auto iana =
724 pldm::utils::fruFieldParserU32(tlv->value, tlv->length);
725 if (!iana)
726 {
727 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length;
728 continue;
729 }
730 break;
731 }
732 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length;
733 }
734 }
735}
736
Chau Ly3419e182025-07-29 07:11:32 +0000737std::vector<std::string> Terminus::getSensorNames(const SensorID& sensorId)
Chau Ly38a09d22025-03-05 05:47:43 +0000738{
739 std::vector<std::string> sensorNames;
740 std::string defaultName =
741 std::format("{}_Sensor_{}", terminusName, unsigned(sensorId));
742 // To ensure there's always a default name at offset 0
743 sensorNames.emplace_back(defaultName);
744
745 auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId);
746 if (!sensorAuxiliaryNames)
747 {
748 return sensorNames;
749 }
750
751 const auto& [id, sensorCount, nameMap] = *sensorAuxiliaryNames;
752 for (const unsigned int& i :
753 std::views::iota(0, static_cast<int>(sensorCount)))
754 {
755 auto sensorName = defaultName;
756 if (i > 0)
757 {
758 // Sensor name at offset 0 will be the default name
759 sensorName += "_" + std::to_string(i);
760 }
761
762 for (const auto& [languageTag, name] : nameMap[i])
763 {
764 if (languageTag == "en" && !name.empty())
765 {
766 sensorName = std::format("{}_{}", terminusName, name);
767 }
768 }
769
770 if (i >= sensorNames.size())
771 {
772 sensorNames.emplace_back(sensorName);
773 }
774 else
775 {
776 sensorNames[i] = sensorName;
777 }
778 }
779
780 return sensorNames;
781}
782
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000783} // namespace platform_mc
784} // namespace pldm