usb-dbg: User Setting frame: Support Boot Order

Description:
- Support boot order feature for ocp debug card
- Change boot sequence data type from array to vector.

Design:
- The behavior of user set/get boot option on debug card will same
  as the oem set/get boot order cmd. The functions 'getBootOrder'
  and 'setBootOrder' are extracted from the OEM set/get boot order
  cmd for OCP debug card operation to use.

Usage:
1. Press uart button to the host want to check.
2. Go to boot order in User Setting frame will get current
   boot order.
3. After selecting the boot option, the option will be set
   on the top of the order. And this boot sequence will be
   get by BIOS and save after the host reboot.

Signed-off-by: Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>
Change-Id: If1a2d91f43133e1779f61719a9816f974e068da3
diff --git a/src/usb-dbg.cpp b/src/usb-dbg.cpp
index ec52543..dfecd94 100644
--- a/src/usb-dbg.cpp
+++ b/src/usb-dbg.cpp
@@ -43,6 +43,15 @@
 int getSensorThreshold(std::string&, std::string&);
 } // namespace storage
 
+namespace boot
+{
+std::tuple<std::string, std::string> objPath(size_t id);
+void setBootOrder(std::string bootObjPath, const std::vector<uint8_t>& bootSeq,
+                  std::string hostName);
+void getBootOrder(std::string bootObjPath, std::vector<uint8_t>& bootSeq,
+                  std::string hostName);
+} // namespace boot
+
 void getMaxHostPosition(size_t& maxPosition)
 {
     try
@@ -1155,82 +1164,77 @@
     }
 }
 
-static uint8_t panel_boot_order(uint8_t)
+static uint8_t panel_boot_order(uint8_t selectedItemIndex)
 {
-    /* To be implemented */
-#if 0
-    int i;
-    unsigned char buff[MAX_VALUE_LEN], pickup, len;
+    static constexpr size_t sizeBootOrder = 6;
+    static constexpr size_t bootValid = 0x80;
+
+    std::vector<uint8_t> bootSeq;
+
+    ctrl_panel& bootOrderPanel = panels[PANEL_BOOT_ORDER];
+
     size_t pos = plat_get_fru_sel();
-    if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0)
-    {
-        if (item > 0 && item < SIZE_BOOT_ORDER)
-        {
-            pickup = buff[item];
-            while (item > 1)
-            {
-                buff[item] = buff[item - 1];
-                item--;
-            }
-            buff[item] = pickup;
-            buff[0] |= 0x80;
-            pal_set_boot_order(pos, buff, buff, &len);
 
-            // refresh items
-            return panels[PANEL_BOOT_ORDER].select(0);
+    if (pos == FRU_ALL)
+    {
+        bootOrderPanel.item_num = 0;
+        return PANEL_BOOT_ORDER;
+    }
+
+    auto [bootObjPath, hostName] = ipmi::boot::objPath(pos);
+    ipmi::boot::getBootOrder(bootObjPath, bootSeq, hostName);
+
+    uint8_t& bootMode = bootSeq.front();
+
+    // One item is selected to set a new boot sequence.
+    // The selected item become the first boot order.
+    if (selectedItemIndex > 0 && selectedItemIndex < sizeBootOrder)
+    {
+        // Move the selected item to second element (the first one is boot mode)
+        std::rotate(bootSeq.begin() + 1, bootSeq.begin() + selectedItemIndex,
+                    bootSeq.begin() + selectedItemIndex + 1);
+
+        bootMode |= bootValid;
+        try
+        {
+            ipmi::boot::setBootOrder(bootObjPath, bootSeq, hostName);
+        }
+        catch (const std::exception& e)
+        {
+            lg2::error("Fail to set boot order : {ERROR}", "ERROR", e);
         }
 
-        // '*': boot flags valid, BIOS has not yet read
-        snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32, "Boot Order%c",
-                 (buff[0] & 0x80) ? '*' : '\0');
+        // refresh items
+        return bootOrderPanel.select(0);
+    }
 
-        for (i = 1; i < SIZE_BOOT_ORDER; i++)
+    // '*': boot flags valid, BIOS has not yet read
+    bootOrderPanel.item_str[0] = std::string("Boot Order") +
+                                 ((bootMode & bootValid) ? "*" : "");
+
+    static const std::unordered_map<uint8_t, const char*>
+        bootOrderMappingTable = {
+            {0x00, " USB device"}, {0x01, " Network v4"}, {0x02, " SATA HDD"},
+            {0x03, " SATA-CDROM"}, {0x04, " Other"},      {0x09, " Network v6"},
+        };
+
+    size_t validItem = 0;
+    for (size_t i = 1; i < sizeBootOrder; i++)
+    {
+        auto find = bootOrderMappingTable.find(bootSeq[i]);
+        if (find == bootOrderMappingTable.end())
         {
-            switch (buff[i])
-            {
-                case 0x0:
-                    snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
-                             " USB device");
-                    break;
-                case 0x1:
-                    snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
-                             " Network v4");
-                    break;
-                case (0x1 | 0x8):
-                    snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
-                             " Network v6");
-                    break;
-                case 0x2:
-                    snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
-                             " SATA HDD");
-                    break;
-                case 0x3:
-                    snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
-                             " SATA-CDROM");
-                    break;
-                case 0x4:
-                    snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
-                             " Other");
-                    break;
-                default:
-                    panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0';
-                    break;
-            }
+            lg2::error("Unknown boot order : {BOOTORDER}", "BOOTORDER",
+                       bootSeq[i]);
+            break;
         }
 
-        // remove empty items
-        for (i--;
-             (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0);
-             i--)
-            ;
+        bootOrderPanel.item_str[i] = find->second;
 
-        panels[PANEL_BOOT_ORDER].item_num = i;
+        validItem++;
     }
-    else
-    {
-        panels[PANEL_BOOT_ORDER].item_num = 0;
-    }
-#endif
+
+    bootOrderPanel.item_num = validItem;
     return PANEL_BOOT_ORDER;
 }
 
@@ -1298,10 +1302,12 @@
 
     buffer[0] = panel;
     buffer[1] = item;
-    buffer[2] = strlen(panels[panel].item_str[item]);
+    buffer[2] = std::size(panels[panel].item_str[item]);
+
     if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE)
     {
-        memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]);
+        std::memcpy(&buffer[3], (panels[panel].item_str[item]).c_str(),
+                    buffer[2]);
     }
     *count = buffer[2] + 3;
     return IPMI_CC_OK;