fram-utils: Add board part number to FRU data from FRAM.

There are following changes:
- The board part number is derived from the board serial number found in the FRAM data. If the serial number starts with a version number of 6.0 or greater followed by 'G', the part number is set to "CNL3560-NFBE-3.0-G"; otherwise, it defaults to "CNL3560-NFBE-2.0-G". This change aligns with how gsys determines the part number for Cavium devices.

- Updated redfish response for cavium for board part number

Tested: Unit test pass
PiperOrigin-RevId: 826212659
Change-Id: I84f7ed32cddf44dbaf51936201fa86939905d45b
diff --git a/tlbmc/utils/fram_utils.cc b/tlbmc/utils/fram_utils.cc
index 166f80f..69cb5f4 100644
--- a/tlbmc/utils/fram_utils.cc
+++ b/tlbmc/utils/fram_utils.cc
@@ -11,6 +11,7 @@
 #include "absl/status/statusor.h"
 #include "absl/strings/ascii.h"
 #include "absl/strings/match.h"
+#include "absl/strings/numbers.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_split.h"
 #include "absl/strings/string_view.h"
@@ -25,6 +26,7 @@
   std::string board_info;
   std::string board_product_name;
   std::string board_serial_number;
+  std::string board_part_number;
 };
 
 constexpr absl::string_view kBoardSerialNumberKey = "Board Serial Number:";
@@ -129,6 +131,22 @@
       continue;
     }
   }
+
+  // Determine part number based on serial number, mimicking gsys
+  // CaviumPartInfo::GetPartInfo
+  parsed_data.board_part_number = "CNL3560-NFBE-2.0-G";
+  if (!parsed_data.board_serial_number.empty()) {
+    size_t g_pos = parsed_data.board_serial_number.find('G');
+    if (g_pos != std::string::npos && g_pos > 0) {
+      double version_num = 0.0;
+      if (absl::SimpleAtod(parsed_data.board_serial_number.substr(0, g_pos),
+                           &version_num) &&
+          version_num >= 6.0) {
+        parsed_data.board_part_number = "CNL3560-NFBE-3.0-G";
+      }
+    }
+  }
+
   return parsed_data;  // Return the struct of extracted key-value pairs.
 }
 
@@ -172,6 +190,12 @@
   if (!parsed_data.board_info.empty()) {
     (*fru_data->mutable_fields())["BOARD_INFO"] = parsed_data.board_info;
   }
+  if (!parsed_data.board_part_number.empty()) {
+    fru_data->mutable_fru_info()->set_board_part_number(
+        parsed_data.board_part_number);
+    (*fru_data->mutable_fields())["BOARD_PART_NUMBER"] =
+        parsed_data.board_part_number;
+  }
 
   return fru;
 }