blob: ba299be60558bc9aeb47fb5f4afa66586b83f4e1 [file] [log] [blame]
Gilbert Chen6c7fed42022-02-22 15:40:17 +00001#include "terminus.hpp"
2
3#include "libpldm/platform.h"
4
Dung Caob6d39432024-06-05 03:46:47 +00005#include "dbus_impl_fru.hpp"
Gilbert Chen6c7fed42022-02-22 15:40:17 +00006#include "terminus_manager.hpp"
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
17Terminus::Terminus(pldm_tid_t tid, uint64_t supportedTypes) :
Gilbert Chen77e6fe72024-08-06 09:23:30 +000018 initialized(false), maxBufferSize(PLDM_PLATFORM_EVENT_MSG_MAX_BUFFER_SIZE),
Dung Caof48015b2023-11-21 04:38:29 +000019 synchronyConfigurationSupported(0), pollEvent(false), tid(tid),
20 supportedTypes(supportedTypes)
Gilbert Chen6c7fed42022-02-22 15:40:17 +000021{}
22
23bool Terminus::doesSupportType(uint8_t type)
24{
25 return supportedTypes.test(type);
26}
27
28bool Terminus::doesSupportCommand(uint8_t type, uint8_t command)
29{
30 if (!doesSupportType(type))
31 {
32 return false;
33 }
34
35 try
36 {
37 const size_t idx = type * (PLDM_MAX_CMDS_PER_TYPE / 8) + (command / 8);
38 if (idx >= supportedCmds.size())
39 {
40 return false;
41 }
42
43 if (supportedCmds[idx] & (1 << (command % 8)))
44 {
45 lg2::info(
46 "PLDM type {TYPE} command {CMD} is supported by terminus {TID}",
47 "TYPE", type, "CMD", command, "TID", getTid());
48 return true;
49 }
50 }
51 catch (const std::exception& e)
52 {
53 return false;
54 }
55
56 return false;
57}
58
Thu Nguyenb8cf46b2024-06-15 02:44:35 +000059std::optional<std::string_view> Terminus::findTerminusName()
60{
61 auto it = std::find_if(
62 entityAuxiliaryNamesTbl.begin(), entityAuxiliaryNamesTbl.end(),
63 [](const std::shared_ptr<EntityAuxiliaryNames>& entityAuxiliaryNames) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -040064 const auto& [key, entityNames] = *entityAuxiliaryNames;
65 /**
Manojkiran Eda04ac9972024-09-06 10:57:12 +053066 * There is only one Overall system container entity in one
67 * terminus. The entity auxiliary name PDR of that terminus with the
68 * that type of containerID will include terminus name.
69 */
Patrick Williams16c2a0a2024-08-16 15:20:59 -040070 return (
71 entityAuxiliaryNames &&
Thu Nguyenb8cf46b2024-06-15 02:44:35 +000072 key.containerId == PLDM_PLATFORM_ENTITY_SYSTEM_CONTAINER_ID &&
73 entityNames.size());
Patrick Williams16c2a0a2024-08-16 15:20:59 -040074 });
Thu Nguyenb8cf46b2024-06-15 02:44:35 +000075
76 if (it != entityAuxiliaryNamesTbl.end())
77 {
78 const auto& [key, entityNames] = **it;
79 if (!entityNames.size())
80 {
81 return std::nullopt;
82 }
83 return entityNames[0].second;
84 }
85
86 return std::nullopt;
87}
88
Thu Nguyen3c5486d2024-08-01 08:03:08 +000089bool Terminus::createInventoryPath(std::string tName)
90{
91 if (tName.empty())
92 {
93 return false;
94 }
95
Dung Caob6d39432024-06-05 03:46:47 +000096 /* inventory object is created */
97 if (inventoryItemBoardInft)
98 {
99 return false;
100 }
101
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000102 inventoryPath = "/xyz/openbmc_project/inventory/system/board/" + tName;
103 try
104 {
Dung Caob6d39432024-06-05 03:46:47 +0000105 inventoryItemBoardInft =
106 std::make_unique<pldm::dbus_api::PldmEntityReq>(
107 utils::DBusHandler::getBus(), inventoryPath.c_str());
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000108 return true;
109 }
110 catch (const sdbusplus::exception_t& e)
111 {
112 lg2::error(
113 "Failed to create Inventory Board interface for device {PATH}",
114 "PATH", inventoryPath);
115 }
116
117 return false;
118}
119
Gilbert Chende2a1322022-05-24 15:35:21 +0100120void Terminus::parseTerminusPDRs()
121{
122 std::vector<std::shared_ptr<pldm_numeric_sensor_value_pdr>>
123 numericSensorPdrs{};
124 std::vector<std::shared_ptr<pldm_compact_numeric_sensor_pdr>>
125 compactNumericSensorPdrs{};
126
127 for (auto& pdr : pdrs)
128 {
Pavithra Barithaya36b36932025-01-30 10:33:05 +0530129 auto pdrHdr = new (pdr.data()) pldm_pdr_hdr;
Gilbert Chende2a1322022-05-24 15:35:21 +0100130 switch (pdrHdr->type)
131 {
132 case PLDM_SENSOR_AUXILIARY_NAMES_PDR:
133 {
134 auto sensorAuxNames = parseSensorAuxiliaryNamesPDR(pdr);
135 if (!sensorAuxNames)
136 {
137 lg2::error(
138 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
139 "TYPE", pdrHdr->type, "HANDLE",
140 static_cast<uint32_t>(pdrHdr->record_handle));
141 continue;
142 }
143 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
144 break;
145 }
146 case PLDM_NUMERIC_SENSOR_PDR:
147 {
148 auto parsedPdr = parseNumericSensorPDR(pdr);
149 if (!parsedPdr)
150 {
151 lg2::error(
152 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
153 "TYPE", pdrHdr->type, "HANDLE",
154 static_cast<uint32_t>(pdrHdr->record_handle));
155 continue;
156 }
157 numericSensorPdrs.emplace_back(std::move(parsedPdr));
158 break;
159 }
160 case PLDM_COMPACT_NUMERIC_SENSOR_PDR:
161 {
162 auto parsedPdr = parseCompactNumericSensorPDR(pdr);
163 if (!parsedPdr)
164 {
165 lg2::error(
166 "Failed to parse PDR with type {TYPE} handle {HANDLE}",
167 "TYPE", pdrHdr->type, "HANDLE",
168 static_cast<uint32_t>(pdrHdr->record_handle));
169 continue;
170 }
171 auto sensorAuxNames = parseCompactNumericSensorNames(pdr);
172 if (!sensorAuxNames)
173 {
174 lg2::error(
175 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
176 "TYPE", pdrHdr->type, "HANDLE",
177 static_cast<uint32_t>(pdrHdr->record_handle));
178 continue;
179 }
180 compactNumericSensorPdrs.emplace_back(std::move(parsedPdr));
181 sensorAuxiliaryNamesTbl.emplace_back(std::move(sensorAuxNames));
182 break;
183 }
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000184 case PLDM_ENTITY_AUXILIARY_NAMES_PDR:
185 {
186 auto entityNames = parseEntityAuxiliaryNamesPDR(pdr);
187 if (!entityNames)
188 {
189 lg2::error(
190 "Failed to parse sensor name PDR with type {TYPE} handle {HANDLE}",
191 "TYPE", pdrHdr->type, "HANDLE",
192 static_cast<uint32_t>(pdrHdr->record_handle));
193 continue;
194 }
195 entityAuxiliaryNamesTbl.emplace_back(std::move(entityNames));
196 break;
197 }
Gilbert Chende2a1322022-05-24 15:35:21 +0100198 default:
199 {
200 lg2::error("Unsupported PDR with type {TYPE} handle {HANDLE}",
201 "TYPE", pdrHdr->type, "HANDLE",
202 static_cast<uint32_t>(pdrHdr->record_handle));
203 break;
204 }
205 }
206 }
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000207
208 auto tName = findTerminusName();
209 if (tName && !tName.value().empty())
210 {
211 lg2::info("Terminus {TID} has Auxiliary Name {NAME}.", "TID", tid,
212 "NAME", tName.value());
213 terminusName = static_cast<std::string>(tName.value());
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 {
Dung Caob6d39432024-06-05 03:46:47 +0000227 lg2::error("Terminus ID {TID}: Created Inventory path {PATH}.", "TID",
228 tid, "PATH", inventoryPath);
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000229 }
230
231 for (auto pdr : numericSensorPdrs)
232 {
233 addNumericSensor(pdr);
234 }
235
236 for (auto pdr : compactNumericSensorPdrs)
237 {
238 addCompactNumericSensor(pdr);
239 }
Gilbert Chende2a1322022-05-24 15:35:21 +0100240}
241
Patrick Williams366507c2025-02-03 14:28:01 -0500242std::shared_ptr<SensorAuxiliaryNames> Terminus::getSensorAuxiliaryNames(
243 SensorId id)
Gilbert Chende2a1322022-05-24 15:35:21 +0100244{
245 auto it = std::find_if(
246 sensorAuxiliaryNamesTbl.begin(), sensorAuxiliaryNamesTbl.end(),
247 [id](
248 const std::shared_ptr<SensorAuxiliaryNames>& sensorAuxiliaryNames) {
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400249 const auto& [sensorId, sensorCnt, sensorNames] =
250 *sensorAuxiliaryNames;
251 return sensorId == id;
252 });
Gilbert Chende2a1322022-05-24 15:35:21 +0100253
254 if (it != sensorAuxiliaryNamesTbl.end())
255 {
256 return *it;
257 }
258 return nullptr;
259};
260
Patrick Williams366507c2025-02-03 14:28:01 -0500261std::shared_ptr<SensorAuxiliaryNames> Terminus::parseSensorAuxiliaryNamesPDR(
262 const std::vector<uint8_t>& pdrData)
Gilbert Chende2a1322022-05-24 15:35:21 +0100263{
264 constexpr uint8_t nullTerminator = 0;
265 auto pdr = reinterpret_cast<const struct pldm_sensor_auxiliary_names_pdr*>(
266 pdrData.data());
267 const uint8_t* ptr = pdr->names;
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000268 std::vector<AuxiliaryNames> sensorAuxNames{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100269 char16_t alignedBuffer[PLDM_STR_UTF_16_MAX_LEN];
270 for ([[maybe_unused]] const auto& sensor :
271 std::views::iota(0, static_cast<int>(pdr->sensor_count)))
272 {
273 const uint8_t nameStringCount = static_cast<uint8_t>(*ptr);
274 ptr += sizeof(uint8_t);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000275 AuxiliaryNames nameStrings{};
Gilbert Chende2a1322022-05-24 15:35:21 +0100276 for ([[maybe_unused]] const auto& count :
277 std::views::iota(0, static_cast<int>(nameStringCount)))
278 {
279 std::string_view nameLanguageTag(
280 reinterpret_cast<const char*>(ptr));
281 ptr += nameLanguageTag.size() + sizeof(nullTerminator);
282
283 int u16NameStringLen = 0;
284 for (int i = 0; ptr[i] != 0 || ptr[i + 1] != 0; i += 2)
285 {
286 u16NameStringLen++;
287 }
288 /* include terminator */
289 u16NameStringLen++;
290
291 std::fill(std::begin(alignedBuffer), std::end(alignedBuffer), 0);
292 if (u16NameStringLen > PLDM_STR_UTF_16_MAX_LEN)
293 {
Chau Ly38a09d22025-03-05 05:47:43 +0000294 lg2::error("Sensor name too long.");
Gilbert Chende2a1322022-05-24 15:35:21 +0100295 return nullptr;
296 }
297 memcpy(alignedBuffer, ptr, u16NameStringLen * sizeof(uint16_t));
298 std::u16string u16NameString(alignedBuffer, u16NameStringLen);
tal-yacf1e32c12024-08-12 13:12:30 +0300299 ptr += u16NameString.size() * sizeof(uint16_t);
Gilbert Chende2a1322022-05-24 15:35:21 +0100300 std::transform(u16NameString.cbegin(), u16NameString.cend(),
301 u16NameString.begin(),
302 [](uint16_t utf16) { return be16toh(utf16); });
303 std::string nameString =
304 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,
305 char16_t>{}
306 .to_bytes(u16NameString);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000307 nameStrings.emplace_back(std::make_pair(
308 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100309 }
310 sensorAuxNames.emplace_back(std::move(nameStrings));
311 }
312 return std::make_shared<SensorAuxiliaryNames>(
313 pdr->sensor_id, pdr->sensor_count, std::move(sensorAuxNames));
314}
315
Patrick Williams366507c2025-02-03 14:28:01 -0500316std::shared_ptr<EntityAuxiliaryNames> Terminus::parseEntityAuxiliaryNamesPDR(
317 const std::vector<uint8_t>& pdrData)
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000318{
319 auto names_offset = sizeof(struct pldm_pdr_hdr) +
320 PLDM_PDR_ENTITY_AUXILIARY_NAME_PDR_MIN_LENGTH;
321 auto names_size = pdrData.size() - names_offset;
322
Patrick Williams16c2a0a2024-08-16 15:20:59 -0400323 size_t decodedPdrSize =
324 sizeof(struct pldm_entity_auxiliary_names_pdr) + names_size;
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000325 auto vPdr = std::vector<char>(decodedPdrSize);
Pavithra Barithaya36b36932025-01-30 10:33:05 +0530326 auto decodedPdr = new (vPdr.data()) pldm_entity_auxiliary_names_pdr;
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000327
328 auto rc = decode_entity_auxiliary_names_pdr(pdrData.data(), pdrData.size(),
329 decodedPdr, decodedPdrSize);
330
331 if (rc)
332 {
333 lg2::error(
334 "Failed to decode Entity Auxiliary Name PDR data, error {RC}.",
335 "RC", rc);
336 return nullptr;
337 }
338
339 auto vNames =
340 std::vector<pldm_entity_auxiliary_name>(decodedPdr->name_string_count);
341 decodedPdr->names = vNames.data();
342
343 rc = decode_pldm_entity_auxiliary_names_pdr_index(decodedPdr);
344 if (rc)
345 {
346 lg2::error("Failed to decode Entity Auxiliary Name, error {RC}.", "RC",
347 rc);
348 return nullptr;
349 }
350
351 AuxiliaryNames nameStrings{};
352 for (const auto& count :
353 std::views::iota(0, static_cast<int>(decodedPdr->name_string_count)))
354 {
355 std::string_view nameLanguageTag =
356 static_cast<std::string_view>(decodedPdr->names[count].tag);
357 const size_t u16NameStringLen =
358 std::char_traits<char16_t>::length(decodedPdr->names[count].name);
359 std::u16string u16NameString(decodedPdr->names[count].name,
360 u16NameStringLen);
361 std::transform(u16NameString.cbegin(), u16NameString.cend(),
362 u16NameString.begin(),
363 [](uint16_t utf16) { return be16toh(utf16); });
364 std::string nameString =
365 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
366 .to_bytes(u16NameString);
367 nameStrings.emplace_back(std::make_pair(
368 nameLanguageTag, pldm::utils::trimNameForDbus(nameString)));
369 }
370
371 EntityKey key{decodedPdr->container.entity_type,
372 decodedPdr->container.entity_instance_num,
373 decodedPdr->container.entity_container_id};
374
375 return std::make_shared<EntityAuxiliaryNames>(key, nameStrings);
376}
377
Patrick Williams366507c2025-02-03 14:28:01 -0500378std::shared_ptr<pldm_numeric_sensor_value_pdr> Terminus::parseNumericSensorPDR(
379 const std::vector<uint8_t>& pdr)
Gilbert Chende2a1322022-05-24 15:35:21 +0100380{
381 const uint8_t* ptr = pdr.data();
382 auto parsedPdr = std::make_shared<pldm_numeric_sensor_value_pdr>();
383 auto rc = decode_numeric_sensor_pdr_data(ptr, pdr.size(), parsedPdr.get());
384 if (rc)
385 {
386 return nullptr;
387 }
388 return parsedPdr;
389}
390
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000391void Terminus::addNumericSensor(
392 const std::shared_ptr<pldm_numeric_sensor_value_pdr> pdr)
393{
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000394 if (terminusName.empty())
395 {
396 lg2::error(
397 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
398 "TID", tid);
399 return;
400 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000401
Chau Ly38a09d22025-03-05 05:47:43 +0000402 if (!pdr)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000403 {
Chau Ly38a09d22025-03-05 05:47:43 +0000404 lg2::error(
405 "Terminus ID {TID}: Skip adding Numeric Sensor - invalid pointer to PDR.",
406 "TID", tid);
407 return;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000408 }
409
Chau Ly38a09d22025-03-05 05:47:43 +0000410 auto sensorId = pdr->sensor_id;
411 auto sensorNames = getSensorNames(sensorId);
412
413 if (sensorNames.empty())
414 {
415 lg2::error(
416 "Terminus ID {TID}: Failed to get name for Numeric Sensor {SID}",
417 "TID", tid, "SID", sensorId);
418 return;
419 }
420
421 std::string sensorName = sensorNames.front();
422
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000423 try
424 {
425 auto sensor = std::make_shared<NumericSensor>(
426 tid, true, pdr, sensorName, inventoryPath);
427 lg2::info("Created NumericSensor {NAME}", "NAME", sensorName);
428 numericSensors.emplace_back(sensor);
429 }
430 catch (const sdbusplus::exception_t& e)
431 {
432 lg2::error(
433 "Failed to create NumericSensor. error - {ERROR} sensorname - {NAME}",
434 "ERROR", e, "NAME", sensorName);
435 }
436}
437
Patrick Williams366507c2025-02-03 14:28:01 -0500438std::shared_ptr<SensorAuxiliaryNames> Terminus::parseCompactNumericSensorNames(
439 const std::vector<uint8_t>& sPdr)
Gilbert Chende2a1322022-05-24 15:35:21 +0100440{
441 std::vector<std::vector<std::pair<NameLanguageTag, SensorName>>>
442 sensorAuxNames{};
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000443 AuxiliaryNames nameStrings{};
Pavithra Barithaya36b36932025-01-30 10:33:05 +0530444
Gilbert Chende2a1322022-05-24 15:35:21 +0100445 auto pdr =
446 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
447
448 if (sPdr.size() <
449 (sizeof(pldm_compact_numeric_sensor_pdr) - sizeof(uint8_t)))
450 {
451 return nullptr;
452 }
453
454 if (!pdr->sensor_name_length ||
455 (sPdr.size() < (sizeof(pldm_compact_numeric_sensor_pdr) -
456 sizeof(uint8_t) + pdr->sensor_name_length)))
457 {
458 return nullptr;
459 }
460
461 std::string nameString(reinterpret_cast<const char*>(pdr->sensor_name),
462 pdr->sensor_name_length);
Thu Nguyenb8cf46b2024-06-15 02:44:35 +0000463 nameStrings.emplace_back(
464 std::make_pair("en", pldm::utils::trimNameForDbus(nameString)));
Gilbert Chende2a1322022-05-24 15:35:21 +0100465 sensorAuxNames.emplace_back(std::move(nameStrings));
466
467 return std::make_shared<SensorAuxiliaryNames>(pdr->sensor_id, 1,
468 std::move(sensorAuxNames));
469}
470
471std::shared_ptr<pldm_compact_numeric_sensor_pdr>
472 Terminus::parseCompactNumericSensorPDR(const std::vector<uint8_t>& sPdr)
473{
474 auto pdr =
475 reinterpret_cast<const pldm_compact_numeric_sensor_pdr*>(sPdr.data());
476 if (sPdr.size() < sizeof(pldm_compact_numeric_sensor_pdr))
477 {
478 // Handle error: input data too small to contain valid pdr
479 return nullptr;
480 }
481 auto parsedPdr = std::make_shared<pldm_compact_numeric_sensor_pdr>();
482
483 parsedPdr->hdr = pdr->hdr;
484 parsedPdr->terminus_handle = pdr->terminus_handle;
485 parsedPdr->sensor_id = pdr->sensor_id;
486 parsedPdr->entity_type = pdr->entity_type;
487 parsedPdr->entity_instance = pdr->entity_instance;
488 parsedPdr->container_id = pdr->container_id;
489 parsedPdr->sensor_name_length = pdr->sensor_name_length;
490 parsedPdr->base_unit = pdr->base_unit;
491 parsedPdr->unit_modifier = pdr->unit_modifier;
492 parsedPdr->occurrence_rate = pdr->occurrence_rate;
493 parsedPdr->range_field_support = pdr->range_field_support;
494 parsedPdr->warning_high = pdr->warning_high;
495 parsedPdr->warning_low = pdr->warning_low;
496 parsedPdr->critical_high = pdr->critical_high;
497 parsedPdr->critical_low = pdr->critical_low;
498 parsedPdr->fatal_high = pdr->fatal_high;
499 parsedPdr->fatal_low = pdr->fatal_low;
500 return parsedPdr;
501}
502
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000503void Terminus::addCompactNumericSensor(
504 const std::shared_ptr<pldm_compact_numeric_sensor_pdr> pdr)
505{
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000506 if (terminusName.empty())
507 {
508 lg2::error(
509 "Terminus ID {TID}: DOES NOT have name. Skip Adding sensors.",
510 "TID", tid);
511 return;
512 }
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000513
Chau Ly38a09d22025-03-05 05:47:43 +0000514 if (!pdr)
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000515 {
Chau Ly38a09d22025-03-05 05:47:43 +0000516 lg2::error(
517 "Terminus ID {TID}: Skip adding Compact Numeric Sensor - invalid pointer to PDR.",
518 "TID", tid);
519 return;
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000520 }
521
Chau Ly38a09d22025-03-05 05:47:43 +0000522 auto sensorId = pdr->sensor_id;
523 auto sensorNames = getSensorNames(sensorId);
524
525 if (sensorNames.empty())
526 {
527 lg2::error(
528 "Terminus ID {TID}: Failed to get name for Compact Numeric Sensor {SID}",
529 "TID", tid, "SID", sensorId);
530 return;
531 }
532
533 std::string sensorName = sensorNames.front();
534
Thu Nguyen3c5486d2024-08-01 08:03:08 +0000535 try
536 {
537 auto sensor = std::make_shared<NumericSensor>(
538 tid, true, pdr, sensorName, inventoryPath);
539 lg2::info("Created Compact NumericSensor {NAME}", "NAME", sensorName);
540 numericSensors.emplace_back(sensor);
541 }
542 catch (const sdbusplus::exception_t& e)
543 {
544 lg2::error(
545 "Failed to create Compact NumericSensor. error - {ERROR} sensorname - {NAME}",
546 "ERROR", e, "NAME", sensorName);
547 }
548}
549
Gilbert Chen77e6fe72024-08-06 09:23:30 +0000550std::shared_ptr<NumericSensor> Terminus::getSensorObject(SensorId id)
551{
552 if (terminusName.empty())
553 {
554 lg2::error(
555 "Terminus ID {TID}: DOES NOT have terminus name. No numeric sensor object.",
556 "TID", tid);
557 return nullptr;
558 }
559 if (!numericSensors.size())
560 {
561 lg2::error("Terminus ID {TID} name {NAME}: DOES NOT have sensor.",
562 "TID", tid, "NAME", terminusName);
563 return nullptr;
564 }
565
566 for (auto& sensor : numericSensors)
567 {
568 if (!sensor)
569 {
570 continue;
571 }
572
573 if (sensor->sensorId == id)
574 {
575 return sensor;
576 }
577 }
578
579 return nullptr;
580}
Dung Caob6d39432024-06-05 03:46:47 +0000581
582/** @brief Check if a pointer is go through end of table
583 * @param[in] table - pointer to FRU record table
584 * @param[in] p - pointer to each record of FRU record table
585 * @param[in] tableSize - FRU table size
586 */
587static bool isTableEnd(const uint8_t* table, const uint8_t* p,
588 const size_t tableSize)
589{
590 auto offset = p - table;
591 return (tableSize - offset) < sizeof(struct pldm_fru_record_data_format);
592}
593
594void Terminus::updateInventoryWithFru(const uint8_t* fruData,
595 const size_t fruLen)
596{
597 auto tmp = getTerminusName();
598 if (!tmp || tmp.value().empty())
599 {
600 lg2::error(
601 "Terminus ID {TID}: Failed to update Inventory with Fru Data - error : Terminus name is empty.",
602 "TID", tid);
603 return;
604 }
605
606 if (createInventoryPath(static_cast<std::string>(tmp.value())))
607 {
608 lg2::info("Terminus ID {TID}: Created Inventory path.", "TID", tid);
609 }
610
611 auto ptr = fruData;
612 while (!isTableEnd(fruData, ptr, fruLen))
613 {
614 auto record = reinterpret_cast<const pldm_fru_record_data_format*>(ptr);
615 ptr += sizeof(pldm_fru_record_data_format) -
616 sizeof(pldm_fru_record_tlv);
617
618 if (!record->num_fru_fields)
619 {
620 lg2::error(
621 "Invalid number of fields {NUM} of Record ID Type {TYPE} of terminus {TID}",
622 "NUM", record->num_fru_fields, "TYPE", record->record_type,
623 "TID", tid);
624 return;
625 }
626
627 if (record->record_type != PLDM_FRU_RECORD_TYPE_GENERAL)
628 {
629 lg2::error(
630 "Does not support Fru Record ID Type {TYPE} of terminus {TID}",
631 "TYPE", record->record_type, "TID", tid);
632
633 for ([[maybe_unused]] const auto& idx :
634 std::views::iota(0, static_cast<int>(record->num_fru_fields)))
635 {
636 auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(ptr);
637 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length;
638 }
639 continue;
640 }
641 /* FRU General record type */
642 for ([[maybe_unused]] const auto& idx :
643 std::views::iota(0, static_cast<int>(record->num_fru_fields)))
644 {
645 auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(ptr);
646 std::string fruField{};
647 if (tlv->type != PLDM_FRU_FIELD_TYPE_IANA)
648 {
649 auto strOptional =
650 pldm::utils::fruFieldValuestring(tlv->value, tlv->length);
651 if (!strOptional)
652 {
653 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length;
654 continue;
655 }
656 fruField = strOptional.value();
657
658 if (fruField.empty())
659 {
660 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length;
661 continue;
662 }
663 }
664
665 switch (tlv->type)
666 {
667 case PLDM_FRU_FIELD_TYPE_MODEL:
668 inventoryItemBoardInft->model(fruField);
669 break;
670 case PLDM_FRU_FIELD_TYPE_PN:
671 inventoryItemBoardInft->partNumber(fruField);
672 break;
673 case PLDM_FRU_FIELD_TYPE_SN:
674 inventoryItemBoardInft->serialNumber(fruField);
675 break;
676 case PLDM_FRU_FIELD_TYPE_MANUFAC:
677 inventoryItemBoardInft->manufacturer(fruField);
678 break;
679 case PLDM_FRU_FIELD_TYPE_NAME:
680 inventoryItemBoardInft->names({fruField});
681 break;
682 case PLDM_FRU_FIELD_TYPE_VERSION:
683 inventoryItemBoardInft->version(fruField);
684 break;
685 case PLDM_FRU_FIELD_TYPE_ASSET_TAG:
686 inventoryItemBoardInft->assetTag(fruField);
687 break;
688 case PLDM_FRU_FIELD_TYPE_VENDOR:
689 case PLDM_FRU_FIELD_TYPE_CHASSIS:
690 case PLDM_FRU_FIELD_TYPE_SKU:
691 case PLDM_FRU_FIELD_TYPE_DESC:
692 case PLDM_FRU_FIELD_TYPE_EC_LVL:
693 case PLDM_FRU_FIELD_TYPE_OTHER:
694 break;
695 case PLDM_FRU_FIELD_TYPE_IANA:
696 auto iana =
697 pldm::utils::fruFieldParserU32(tlv->value, tlv->length);
698 if (!iana)
699 {
700 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length;
701 continue;
702 }
703 break;
704 }
705 ptr += sizeof(pldm_fru_record_tlv) - 1 + tlv->length;
706 }
707 }
708}
709
Chau Ly38a09d22025-03-05 05:47:43 +0000710std::vector<std::string> Terminus::getSensorNames(const SensorId& sensorId)
711{
712 std::vector<std::string> sensorNames;
713 std::string defaultName =
714 std::format("{}_Sensor_{}", terminusName, unsigned(sensorId));
715 // To ensure there's always a default name at offset 0
716 sensorNames.emplace_back(defaultName);
717
718 auto sensorAuxiliaryNames = getSensorAuxiliaryNames(sensorId);
719 if (!sensorAuxiliaryNames)
720 {
721 return sensorNames;
722 }
723
724 const auto& [id, sensorCount, nameMap] = *sensorAuxiliaryNames;
725 for (const unsigned int& i :
726 std::views::iota(0, static_cast<int>(sensorCount)))
727 {
728 auto sensorName = defaultName;
729 if (i > 0)
730 {
731 // Sensor name at offset 0 will be the default name
732 sensorName += "_" + std::to_string(i);
733 }
734
735 for (const auto& [languageTag, name] : nameMap[i])
736 {
737 if (languageTag == "en" && !name.empty())
738 {
739 sensorName = std::format("{}_{}", terminusName, name);
740 }
741 }
742
743 if (i >= sensorNames.size())
744 {
745 sensorNames.emplace_back(sensorName);
746 }
747 else
748 {
749 sensorNames[i] = sensorName;
750 }
751 }
752
753 return sensorNames;
754}
755
Gilbert Chen6c7fed42022-02-22 15:40:17 +0000756} // namespace platform_mc
757} // namespace pldm