xref: /openbmc/pldm/pldmtool/pldm_fru_cmd.cpp (revision 5bdde3a4f01dda4b2aefe424fd1c8aa529c20a4c)
1f7f5da97SDeepak Kodihalli #include "pldm_fru_cmd.hpp"
2f7f5da97SDeepak Kodihalli 
3f7f5da97SDeepak Kodihalli #include "pldm_cmd_helper.hpp"
4f7f5da97SDeepak Kodihalli 
5*5bdde3a4SJohn Wang #include <endian.h>
6*5bdde3a4SJohn Wang 
7*5bdde3a4SJohn Wang #include <functional>
8*5bdde3a4SJohn Wang #include <tuple>
9*5bdde3a4SJohn Wang 
10f7f5da97SDeepak Kodihalli namespace pldmtool
11f7f5da97SDeepak Kodihalli {
12f7f5da97SDeepak Kodihalli 
13f7f5da97SDeepak Kodihalli namespace fru
14f7f5da97SDeepak Kodihalli {
15f7f5da97SDeepak Kodihalli 
16f7f5da97SDeepak Kodihalli namespace
17f7f5da97SDeepak Kodihalli {
18f7f5da97SDeepak Kodihalli 
19f7f5da97SDeepak Kodihalli using namespace pldmtool::helper;
20f7f5da97SDeepak Kodihalli 
21f7f5da97SDeepak Kodihalli std::vector<std::unique_ptr<CommandInterface>> commands;
22f7f5da97SDeepak Kodihalli 
23f7f5da97SDeepak Kodihalli } // namespace
24f7f5da97SDeepak Kodihalli 
25f7f5da97SDeepak Kodihalli class GetFruRecordTableMetadata : public CommandInterface
26f7f5da97SDeepak Kodihalli {
27f7f5da97SDeepak Kodihalli   public:
28f7f5da97SDeepak Kodihalli     ~GetFruRecordTableMetadata() = default;
29f7f5da97SDeepak Kodihalli     GetFruRecordTableMetadata() = delete;
30f7f5da97SDeepak Kodihalli     GetFruRecordTableMetadata(const GetFruRecordTableMetadata&) = delete;
31f7f5da97SDeepak Kodihalli     GetFruRecordTableMetadata(GetFruRecordTableMetadata&&) = default;
32f7f5da97SDeepak Kodihalli     GetFruRecordTableMetadata&
33f7f5da97SDeepak Kodihalli         operator=(const GetFruRecordTableMetadata&) = delete;
34f7f5da97SDeepak Kodihalli     GetFruRecordTableMetadata& operator=(GetFruRecordTableMetadata&&) = default;
35f7f5da97SDeepak Kodihalli 
36f7f5da97SDeepak Kodihalli     using CommandInterface::CommandInterface;
37f7f5da97SDeepak Kodihalli 
38f7f5da97SDeepak Kodihalli     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
39f7f5da97SDeepak Kodihalli     {
40f7f5da97SDeepak Kodihalli         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr));
41f7f5da97SDeepak Kodihalli         auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
42f7f5da97SDeepak Kodihalli 
43f7f5da97SDeepak Kodihalli         auto rc = encode_get_fru_record_table_metadata_req(
44f7f5da97SDeepak Kodihalli             instanceId, request, PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES);
45f7f5da97SDeepak Kodihalli         return {rc, requestMsg};
46f7f5da97SDeepak Kodihalli     }
47f7f5da97SDeepak Kodihalli 
48f7f5da97SDeepak Kodihalli     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
49f7f5da97SDeepak Kodihalli     {
50f7f5da97SDeepak Kodihalli         uint8_t cc = 0;
51f7f5da97SDeepak Kodihalli         uint8_t fru_data_major_version, fru_data_minor_version;
52f7f5da97SDeepak Kodihalli         uint32_t fru_table_maximum_size, fru_table_length;
53f7f5da97SDeepak Kodihalli         uint16_t total_record_set_identifiers, total_table_records;
54f7f5da97SDeepak Kodihalli         uint32_t checksum;
55f7f5da97SDeepak Kodihalli 
56f7f5da97SDeepak Kodihalli         auto rc = decode_get_fru_record_table_metadata_resp(
57f7f5da97SDeepak Kodihalli             responsePtr, payloadLength, &cc, &fru_data_major_version,
58f7f5da97SDeepak Kodihalli             &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length,
59f7f5da97SDeepak Kodihalli             &total_record_set_identifiers, &total_table_records, &checksum);
60f7f5da97SDeepak Kodihalli         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
61f7f5da97SDeepak Kodihalli         {
62f7f5da97SDeepak Kodihalli             std::cerr << "Response Message Error: "
63f7f5da97SDeepak Kodihalli                       << "rc=" << rc << ",cc=" << (int)cc << std::endl;
64f7f5da97SDeepak Kodihalli             return;
65f7f5da97SDeepak Kodihalli         }
66f7f5da97SDeepak Kodihalli         std::cout << "FRUDATAMajorVersion : "
67f7f5da97SDeepak Kodihalli                   << static_cast<uint32_t>(fru_data_major_version) << std::endl;
68f7f5da97SDeepak Kodihalli         std::cout << "FRUDATAMinorVersion : "
69f7f5da97SDeepak Kodihalli                   << static_cast<uint32_t>(fru_data_minor_version) << std::endl;
70f7f5da97SDeepak Kodihalli         std::cout << "FRUTableMaximumSize : " << fru_table_maximum_size
71f7f5da97SDeepak Kodihalli                   << std::endl;
72f7f5da97SDeepak Kodihalli         std::cout << "FRUTableLength : " << fru_table_length << std::endl;
73f7f5da97SDeepak Kodihalli         std::cout << "Total number of Record Set Identifiers in table : "
74f7f5da97SDeepak Kodihalli                   << total_record_set_identifiers << std::endl;
75f7f5da97SDeepak Kodihalli         std::cout << "Total number of records in table :  "
76f7f5da97SDeepak Kodihalli                   << total_table_records << std::endl;
77f7f5da97SDeepak Kodihalli         std::cout << "FRU DATAStructureTableIntegrityChecksum :  " << checksum
78f7f5da97SDeepak Kodihalli                   << std::endl;
79f7f5da97SDeepak Kodihalli     }
80f7f5da97SDeepak Kodihalli };
81f7f5da97SDeepak Kodihalli 
82*5bdde3a4SJohn Wang class FRUTablePrint
83*5bdde3a4SJohn Wang {
84*5bdde3a4SJohn Wang   public:
85*5bdde3a4SJohn Wang     explicit FRUTablePrint(const uint8_t* table, size_t table_size) :
86*5bdde3a4SJohn Wang         table(table), table_size(table_size)
87*5bdde3a4SJohn Wang     {}
88*5bdde3a4SJohn Wang 
89*5bdde3a4SJohn Wang     void print()
90*5bdde3a4SJohn Wang     {
91*5bdde3a4SJohn Wang         auto p = table;
92*5bdde3a4SJohn Wang         while (!isTableEnd(p))
93*5bdde3a4SJohn Wang         {
94*5bdde3a4SJohn Wang             auto record =
95*5bdde3a4SJohn Wang                 reinterpret_cast<const pldm_fru_record_data_format*>(p);
96*5bdde3a4SJohn Wang             std::cout << "FRU Record Set Identifier: "
97*5bdde3a4SJohn Wang                       << (int)le16toh(record->record_set_id) << std::endl;
98*5bdde3a4SJohn Wang             std::cout << "FRU Record Type: "
99*5bdde3a4SJohn Wang                       << typeToString(fruRecordTypes, record->record_type)
100*5bdde3a4SJohn Wang                       << std::endl;
101*5bdde3a4SJohn Wang             std::cout << "Number of FRU fields: " << (int)record->num_fru_fields
102*5bdde3a4SJohn Wang                       << std::endl;
103*5bdde3a4SJohn Wang             std::cout << "Encoding Type for FRU fields: "
104*5bdde3a4SJohn Wang                       << typeToString(fruEncodingType, record->encoding_type)
105*5bdde3a4SJohn Wang                       << std::endl;
106*5bdde3a4SJohn Wang 
107*5bdde3a4SJohn Wang             auto isGeneralRec = true;
108*5bdde3a4SJohn Wang             if (record->record_type != PLDM_FRU_RECORD_TYPE_GENERAL)
109*5bdde3a4SJohn Wang             {
110*5bdde3a4SJohn Wang                 isGeneralRec = false;
111*5bdde3a4SJohn Wang             }
112*5bdde3a4SJohn Wang 
113*5bdde3a4SJohn Wang             p += sizeof(pldm_fru_record_data_format) -
114*5bdde3a4SJohn Wang                  sizeof(pldm_fru_record_tlv);
115*5bdde3a4SJohn Wang             for (int i = 0; i < record->num_fru_fields; i++)
116*5bdde3a4SJohn Wang             {
117*5bdde3a4SJohn Wang                 auto tlv = reinterpret_cast<const pldm_fru_record_tlv*>(p);
118*5bdde3a4SJohn Wang                 if (isGeneralRec)
119*5bdde3a4SJohn Wang                 {
120*5bdde3a4SJohn Wang                     fruFieldPrint(record->record_type, tlv->type, tlv->length,
121*5bdde3a4SJohn Wang                                   tlv->value);
122*5bdde3a4SJohn Wang                 }
123*5bdde3a4SJohn Wang                 p += sizeof(pldm_fru_record_tlv) - 1 + tlv->length;
124*5bdde3a4SJohn Wang             }
125*5bdde3a4SJohn Wang         }
126*5bdde3a4SJohn Wang     }
127*5bdde3a4SJohn Wang 
128*5bdde3a4SJohn Wang   private:
129*5bdde3a4SJohn Wang     const uint8_t* table;
130*5bdde3a4SJohn Wang     size_t table_size;
131*5bdde3a4SJohn Wang 
132*5bdde3a4SJohn Wang     bool isTableEnd(const uint8_t* p)
133*5bdde3a4SJohn Wang     {
134*5bdde3a4SJohn Wang         auto offset = p - table;
135*5bdde3a4SJohn Wang         return (table_size - offset) <= 7;
136*5bdde3a4SJohn Wang     }
137*5bdde3a4SJohn Wang 
138*5bdde3a4SJohn Wang     static inline const std::map<uint8_t, const char*> fruEncodingType{
139*5bdde3a4SJohn Wang         {PLDM_FRU_ENCODING_UNSPECIFIED, "Unspecified"},
140*5bdde3a4SJohn Wang         {PLDM_FRU_ENCODING_ASCII, "ASCII"},
141*5bdde3a4SJohn Wang         {PLDM_FRU_ENCODING_UTF8, "UTF8"},
142*5bdde3a4SJohn Wang         {PLDM_FRU_ENCODING_UTF16, "UTF16"},
143*5bdde3a4SJohn Wang         {PLDM_FRU_ENCODING_UTF16LE, "UTF16LE"},
144*5bdde3a4SJohn Wang         {PLDM_FRU_ENCODING_UTF16BE, "UTF16BE"}};
145*5bdde3a4SJohn Wang 
146*5bdde3a4SJohn Wang     static inline const std::map<uint8_t, const char*> fruRecordTypes{
147*5bdde3a4SJohn Wang         {PLDM_FRU_RECORD_TYPE_GENERAL, "General"},
148*5bdde3a4SJohn Wang         {PLDM_FRU_RECORD_TYPE_OEM, "OEM"}};
149*5bdde3a4SJohn Wang 
150*5bdde3a4SJohn Wang     std::string typeToString(std::map<uint8_t, const char*> typeMap,
151*5bdde3a4SJohn Wang                              uint8_t type)
152*5bdde3a4SJohn Wang     {
153*5bdde3a4SJohn Wang         auto typeString = std::to_string(type);
154*5bdde3a4SJohn Wang         try
155*5bdde3a4SJohn Wang         {
156*5bdde3a4SJohn Wang             return typeString + "(" + typeMap.at(type) + ")";
157*5bdde3a4SJohn Wang         }
158*5bdde3a4SJohn Wang         catch (const std::out_of_range& e)
159*5bdde3a4SJohn Wang         {
160*5bdde3a4SJohn Wang             return typeString;
161*5bdde3a4SJohn Wang         }
162*5bdde3a4SJohn Wang     }
163*5bdde3a4SJohn Wang 
164*5bdde3a4SJohn Wang     using FruFieldParser =
165*5bdde3a4SJohn Wang         std::function<std::string(const uint8_t* value, uint8_t length)>;
166*5bdde3a4SJohn Wang 
167*5bdde3a4SJohn Wang     using FieldType = uint8_t;
168*5bdde3a4SJohn Wang     using RecordType = uint8_t;
169*5bdde3a4SJohn Wang     using FieldName = std::string;
170*5bdde3a4SJohn Wang     using FruFieldTypes =
171*5bdde3a4SJohn Wang         std::map<FieldType, std::tuple<FieldName, FruFieldParser>>;
172*5bdde3a4SJohn Wang 
173*5bdde3a4SJohn Wang     static std::string fruFieldParserString(const uint8_t* value,
174*5bdde3a4SJohn Wang                                             uint8_t length)
175*5bdde3a4SJohn Wang     {
176*5bdde3a4SJohn Wang         return std::string(reinterpret_cast<const char*>(value), length);
177*5bdde3a4SJohn Wang     }
178*5bdde3a4SJohn Wang 
179*5bdde3a4SJohn Wang     static std::string fruFieldParserTimestamp(const uint8_t*, uint8_t)
180*5bdde3a4SJohn Wang     {
181*5bdde3a4SJohn Wang         return std::string("TODO");
182*5bdde3a4SJohn Wang     }
183*5bdde3a4SJohn Wang 
184*5bdde3a4SJohn Wang     static std::string fruFieldParserU32(const uint8_t* value, uint8_t length)
185*5bdde3a4SJohn Wang     {
186*5bdde3a4SJohn Wang         assert(length == 4);
187*5bdde3a4SJohn Wang         uint32_t v;
188*5bdde3a4SJohn Wang         std::memcpy(&v, value, length);
189*5bdde3a4SJohn Wang         return std::to_string(le32toh(v));
190*5bdde3a4SJohn Wang     }
191*5bdde3a4SJohn Wang 
192*5bdde3a4SJohn Wang     static inline const FruFieldTypes fruGeneralFieldTypes = {
193*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_CHASSIS, {"Chassis", fruFieldParserString}},
194*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_MODEL, {"Model", fruFieldParserString}},
195*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_PN, {"Part Number", fruFieldParserString}},
196*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_SN, {"Serial Number", fruFieldParserString}},
197*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_MANUFAC, {"Manufacturer", fruFieldParserString}},
198*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_MANUFAC_DATE,
199*5bdde3a4SJohn Wang          {"Manufacture Date", fruFieldParserTimestamp}},
200*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_VENDOR, {"Vendor", fruFieldParserString}},
201*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_NAME, {"Name", fruFieldParserString}},
202*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_SKU, {"SKU", fruFieldParserString}},
203*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_VERSION, {"Version", fruFieldParserString}},
204*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_ASSET_TAG, {"Asset Tag", fruFieldParserString}},
205*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_DESC, {"Description", fruFieldParserString}},
206*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_EC_LVL,
207*5bdde3a4SJohn Wang          {"Engineering Change Level", fruFieldParserString}},
208*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_OTHER,
209*5bdde3a4SJohn Wang          {"Other Information", fruFieldParserString}},
210*5bdde3a4SJohn Wang         {PLDM_FRU_FIELD_TYPE_IANA, {"Vendor IANA", fruFieldParserU32}},
211*5bdde3a4SJohn Wang     };
212*5bdde3a4SJohn Wang 
213*5bdde3a4SJohn Wang     static inline const FruFieldTypes fruOEMFieldTypes = {
214*5bdde3a4SJohn Wang         {1, {"Vendor IANA", fruFieldParserU32}},
215*5bdde3a4SJohn Wang 
216*5bdde3a4SJohn Wang     };
217*5bdde3a4SJohn Wang 
218*5bdde3a4SJohn Wang     static inline const std::map<RecordType, FruFieldTypes> fruFieldTypes{
219*5bdde3a4SJohn Wang         {PLDM_FRU_RECORD_TYPE_GENERAL, fruGeneralFieldTypes},
220*5bdde3a4SJohn Wang         {PLDM_FRU_RECORD_TYPE_OEM, fruOEMFieldTypes}};
221*5bdde3a4SJohn Wang 
222*5bdde3a4SJohn Wang     void fruFieldPrint(uint8_t recordType, uint8_t type, uint8_t length,
223*5bdde3a4SJohn Wang                        const uint8_t* value)
224*5bdde3a4SJohn Wang     {
225*5bdde3a4SJohn Wang         auto& [typeString, parser] = fruFieldTypes.at(recordType).at(type);
226*5bdde3a4SJohn Wang 
227*5bdde3a4SJohn Wang         std::cout << "\tFRU Field Type: " << typeString << std::endl;
228*5bdde3a4SJohn Wang         std::cout << "\tFRU Field Length: " << (int)(length) << std::endl;
229*5bdde3a4SJohn Wang         std::cout << "\tFRU Field Value: " << parser(value, length)
230*5bdde3a4SJohn Wang                   << std::endl;
231*5bdde3a4SJohn Wang     }
232*5bdde3a4SJohn Wang };
233*5bdde3a4SJohn Wang 
234*5bdde3a4SJohn Wang class GetFRURecordByOption : public CommandInterface
235*5bdde3a4SJohn Wang {
236*5bdde3a4SJohn Wang   public:
237*5bdde3a4SJohn Wang     ~GetFRURecordByOption() = default;
238*5bdde3a4SJohn Wang     GetFRURecordByOption() = delete;
239*5bdde3a4SJohn Wang     GetFRURecordByOption(const GetFRURecordByOption&) = delete;
240*5bdde3a4SJohn Wang     GetFRURecordByOption(GetFruRecordTableMetadata&&) = delete;
241*5bdde3a4SJohn Wang     GetFRURecordByOption& operator=(const GetFRURecordByOption&) = delete;
242*5bdde3a4SJohn Wang     GetFRURecordByOption& operator=(GetFRURecordByOption&&) = delete;
243*5bdde3a4SJohn Wang 
244*5bdde3a4SJohn Wang     explicit GetFRURecordByOption(const char* type, const char* name,
245*5bdde3a4SJohn Wang                                   CLI::App* app) :
246*5bdde3a4SJohn Wang         CommandInterface(type, name, app)
247*5bdde3a4SJohn Wang     {
248*5bdde3a4SJohn Wang         app->add_option("-i, --identifier", recordSetIdentifier,
249*5bdde3a4SJohn Wang                         "Record Set Identifier\n"
250*5bdde3a4SJohn Wang                         "Possible values: {All record sets = 0, Specific "
251*5bdde3a4SJohn Wang                         "record set = 1 – 65535}")
252*5bdde3a4SJohn Wang             ->required();
253*5bdde3a4SJohn Wang         app->add_option("-r, --record", recordType,
254*5bdde3a4SJohn Wang                         "Record Type\n"
255*5bdde3a4SJohn Wang                         "Possible values: {All record types = 0, Specific "
256*5bdde3a4SJohn Wang                         "record types = 1 – 255}")
257*5bdde3a4SJohn Wang             ->required();
258*5bdde3a4SJohn Wang         app->add_option("-f, --field", fieldType,
259*5bdde3a4SJohn Wang                         "Field Type\n"
260*5bdde3a4SJohn Wang                         "Possible values: {All record field types = 0, "
261*5bdde3a4SJohn Wang                         "Specific field types = 1 – 15}")
262*5bdde3a4SJohn Wang             ->required();
263*5bdde3a4SJohn Wang     }
264*5bdde3a4SJohn Wang 
265*5bdde3a4SJohn Wang     std::pair<int, std::vector<uint8_t>> createRequestMsg() override
266*5bdde3a4SJohn Wang     {
267*5bdde3a4SJohn Wang         if (fieldType != 0 && recordType == 0)
268*5bdde3a4SJohn Wang         {
269*5bdde3a4SJohn Wang             throw std::invalid_argument("if field type is non-zero, the record "
270*5bdde3a4SJohn Wang                                         "type shall also be non-zero");
271*5bdde3a4SJohn Wang         }
272*5bdde3a4SJohn Wang 
273*5bdde3a4SJohn Wang         auto payloadLength = sizeof(pldm_get_fru_record_by_option_req);
274*5bdde3a4SJohn Wang 
275*5bdde3a4SJohn Wang         std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + payloadLength,
276*5bdde3a4SJohn Wang                                         0);
277*5bdde3a4SJohn Wang         auto reqMsg = reinterpret_cast<pldm_msg*>(requestMsg.data());
278*5bdde3a4SJohn Wang 
279*5bdde3a4SJohn Wang         auto rc = encode_get_fru_record_by_option_req(
280*5bdde3a4SJohn Wang             instanceId, 0 /* DataTransferHandle */, 0 /* FRUTableHandle */,
281*5bdde3a4SJohn Wang             recordSetIdentifier, recordType, fieldType, PLDM_GET_FIRSTPART,
282*5bdde3a4SJohn Wang             reqMsg, payloadLength);
283*5bdde3a4SJohn Wang 
284*5bdde3a4SJohn Wang         return {rc, requestMsg};
285*5bdde3a4SJohn Wang     }
286*5bdde3a4SJohn Wang 
287*5bdde3a4SJohn Wang     void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
288*5bdde3a4SJohn Wang     {
289*5bdde3a4SJohn Wang         uint8_t cc;
290*5bdde3a4SJohn Wang         uint32_t dataTransferHandle;
291*5bdde3a4SJohn Wang         uint8_t transferFlag;
292*5bdde3a4SJohn Wang         variable_field fruData;
293*5bdde3a4SJohn Wang 
294*5bdde3a4SJohn Wang         auto rc = decode_get_fru_record_by_option_resp(
295*5bdde3a4SJohn Wang             responsePtr, payloadLength, &cc, &dataTransferHandle, &transferFlag,
296*5bdde3a4SJohn Wang             &fruData);
297*5bdde3a4SJohn Wang 
298*5bdde3a4SJohn Wang         if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
299*5bdde3a4SJohn Wang         {
300*5bdde3a4SJohn Wang             std::cerr << "Response Message Error: "
301*5bdde3a4SJohn Wang                       << "rc=" << rc << ",cc=" << (int)cc << std::endl;
302*5bdde3a4SJohn Wang             return;
303*5bdde3a4SJohn Wang         }
304*5bdde3a4SJohn Wang 
305*5bdde3a4SJohn Wang         FRUTablePrint tablePrint(fruData.ptr, fruData.length);
306*5bdde3a4SJohn Wang         tablePrint.print();
307*5bdde3a4SJohn Wang     }
308*5bdde3a4SJohn Wang 
309*5bdde3a4SJohn Wang   private:
310*5bdde3a4SJohn Wang     uint16_t recordSetIdentifier;
311*5bdde3a4SJohn Wang     uint8_t recordType;
312*5bdde3a4SJohn Wang     uint8_t fieldType;
313*5bdde3a4SJohn Wang };
314*5bdde3a4SJohn Wang 
315f7f5da97SDeepak Kodihalli void registerCommand(CLI::App& app)
316f7f5da97SDeepak Kodihalli {
317f7f5da97SDeepak Kodihalli     auto fru = app.add_subcommand("fru", "FRU type command");
318f7f5da97SDeepak Kodihalli     fru->require_subcommand(1);
319f7f5da97SDeepak Kodihalli     auto getFruRecordTableMetadata = fru->add_subcommand(
320f7f5da97SDeepak Kodihalli         "GetFruRecordTableMetadata", "get FRU record table metadata");
321f7f5da97SDeepak Kodihalli     commands.push_back(std::make_unique<GetFruRecordTableMetadata>(
322f7f5da97SDeepak Kodihalli         "fru", "GetFruRecordTableMetadata", getFruRecordTableMetadata));
323*5bdde3a4SJohn Wang 
324*5bdde3a4SJohn Wang     auto getFRURecordByOption =
325*5bdde3a4SJohn Wang         fru->add_subcommand("GetFRURecordByOption", "get FRU Record By Option");
326*5bdde3a4SJohn Wang     commands.push_back(std::make_unique<GetFRURecordByOption>(
327*5bdde3a4SJohn Wang         "fru", "GetFRURecordByOption", getFRURecordByOption));
328f7f5da97SDeepak Kodihalli }
329f7f5da97SDeepak Kodihalli 
330f7f5da97SDeepak Kodihalli } // namespace fru
331f7f5da97SDeepak Kodihalli 
332f7f5da97SDeepak Kodihalli } // namespace pldmtool
333