Add response handlers for base discovery

Google-Bug-Id: 312354702
Change-Id: I2ad257111579ddb1ed6486345a6034bd53b98ac6
Signed-off-by: Harsh Tyagi <harshtya@google.com>
diff --git a/util/state_machine/discovery/base/base_disc_state_machine.cpp b/util/state_machine/discovery/base/base_disc_state_machine.cpp
index d52cb39..76f5725 100644
--- a/util/state_machine/discovery/base/base_disc_state_machine.cpp
+++ b/util/state_machine/discovery/base/base_disc_state_machine.cpp
@@ -291,10 +291,194 @@
 }
 
 OperationStatus BaseDiscoveryStateMachine::pushCommandResponse(
-    [[maybe_unused]] struct pldm_msg* respMsg, [[maybe_unused]] size_t respSize)
+    const struct pldm_msg* respMsg, size_t respSize)
 {
-    // TODO(@harshtya): Implement pushCommandResponse
-    return OperationStatus::Success;
+    switch (this->nextCommand)
+    {
+        case PLDM_GET_TID:
+        {
+            uint8_t completionCode = DEFAULT_INITIAL_VAL;
+            uint8_t tid = DEFAULT_INITIAL_VAL;
+            int rc = decode_get_tid_resp(respMsg,
+                                         respSize - sizeof(struct pldm_msg_hdr),
+                                         &completionCode, &tid);
+            if (rc || completionCode)
+            {
+                this->requesterStatus = StateMachineStatus::RequestFailed;
+                stdplus::print(stderr,
+                               "Get TID response decode failed with rc:"
+                               " {} and completion code: {}\n",
+                               rc, std::to_string(completionCode));
+                return OperationStatus::IncorrectResponseMsg;
+            }
+            this->tid = tid;
+            this->nextCommand = PLDM_GET_PLDM_TYPES;
+            this->requesterStatus = StateMachineStatus::ReadyToPickNextRequest;
+            return OperationStatus::Success;
+        }
+
+        case PLDM_GET_PLDM_TYPES:
+        {
+            uint8_t completionCode = DEFAULT_INITIAL_VAL;
+            int rc = decode_get_types_resp(
+                respMsg, respSize - sizeof(struct pldm_msg_hdr),
+                &completionCode, this->pldmTypes.data());
+            if (rc || completionCode)
+            {
+                this->requesterStatus = StateMachineStatus::RequestFailed;
+                stdplus::print(
+                    stderr,
+                    "Get PLDM Type response decoded for "
+                    "pldm GetTypes failed with rc: {} and completion code: {}\n",
+                    rc, std::to_string(completionCode));
+                return OperationStatus::IncorrectResponseMsg;
+            }
+
+            // Setting the initial pldm_type as PLDM_BASE
+            this->commandPldmType = PLDM_BASE;
+            this->nextCommand = PLDM_GET_PLDM_VERSION;
+            this->requesterStatus = StateMachineStatus::ReadyToPickNextRequest;
+            return OperationStatus::Success;
+        }
+        case PLDM_GET_PLDM_VERSION:
+        {
+            ver32_t versionOut;
+            uint8_t completionCode = DEFAULT_INITIAL_VAL;
+            uint8_t retFlag = DEFAULT_INITIAL_VAL;
+            uint32_t retTransferHandle = DEFAULT_INITIAL_VAL;
+            int rc = decode_get_version_resp(
+                respMsg, respSize - sizeof(struct pldm_msg_hdr),
+                &completionCode, &retTransferHandle, &retFlag, &versionOut);
+
+            if (rc || completionCode)
+            {
+                this->requesterStatus = StateMachineStatus::RequestFailed;
+                stdplus::print(
+                    stderr,
+                    "Get PLDM Versions response decoded for "
+                    "pldm get versions failed on pldm type: {} with rc: {}  and "
+                    "completion code: {}\n",
+                    std::to_string(this->commandPldmType), rc,
+                    std::to_string(completionCode));
+                return OperationStatus::IncorrectResponseMsg;
+            }
+            uint8_t currentPldmType = this->commandPldmType;
+            this->pldmVersions[currentPldmType] = versionOut;
+
+            std::optional<uint8_t> nextPldmType =
+                getNextPldmTypeToBeProcessed(currentPldmType);
+
+            if (nextPldmType.has_value())
+            {
+                // get the version for the next pldm type
+                this->commandPldmType = nextPldmType.value();
+                this->nextCommand = PLDM_GET_PLDM_VERSION;
+                this->requesterStatus =
+                    StateMachineStatus::ReadyToPickNextRequest;
+            }
+            else
+            {
+                // All available pldm types processed
+                this->nextCommand = PLDM_GET_PLDM_COMMANDS;
+                this->requesterStatus =
+                    StateMachineStatus::ReadyToPickNextRequest;
+                this->commandPldmType = PLDM_BASE;
+            }
+            return OperationStatus::Success;
+        }
+        case PLDM_GET_PLDM_COMMANDS:
+        {
+            uint8_t completionCode = DEFAULT_INITIAL_VAL;
+            bitfield8_t pldmCmds[PLDM_MAX_CMDS_PER_TYPE / 8];
+            int rc = decode_get_commands_resp(
+                respMsg, respSize - sizeof(struct pldm_msg_hdr),
+                &completionCode, pldmCmds);
+            if (rc || completionCode)
+            {
+                this->requesterStatus = StateMachineStatus::RequestFailed;
+                stdplus::print(
+                    stderr,
+                    "Get PLDM Cmds response decoded for "
+                    "pldm get cmds failed on pldm type: {} with rc: {} and "
+                    "completion code: {}\n",
+                    std::to_string(this->commandPldmType), rc,
+                    std::to_string(completionCode));
+                return OperationStatus::IncorrectResponseMsg;
+            }
+            uint8_t currentPldmType = this->commandPldmType;
+
+            for (int i = 0; i < (PLDM_MAX_CMDS_PER_TYPE / 8); i++)
+            {
+                this->pldmCommands[currentPldmType][i] = pldmCmds[i].byte;
+            }
+
+            std::optional<uint8_t> nextPldmType =
+                getNextPldmTypeToBeProcessed(currentPldmType);
+
+            if (nextPldmType.has_value())
+            {
+                this->commandPldmType = nextPldmType.value();
+                this->nextCommand = PLDM_GET_PLDM_COMMANDS;
+                this->requesterStatus =
+                    StateMachineStatus::ReadyToPickNextRequest;
+            }
+            else
+            {
+                // All available pldm types processed
+                this->nextCommand =
+                    static_cast<int>(OperationStatus::NoNextCommandFound);
+                this->requesterStatus = StateMachineStatus::NoPendingAction;
+                // Setting base PLDM type the PLDM Commands - default
+                this->commandPldmType = PLDM_BASE;
+            }
+            return OperationStatus::Success;
+        }
+        default:
+            return OperationStatus::OperationFailure;
+    }
+}
+
+std::optional<uint8_t>
+    BaseDiscoveryStateMachine::getNextPldmTypeToBeProcessed(uint8_t currentType)
+{
+    // Each bit in a byte returned in pldm type response represents a pldm type
+    // Hence we process each bit to get the corresponding versions and commands
+    // for that bit
+    int byte = currentType / 8;
+    int bit = currentType % 8;
+    bool isBitSet = false;
+
+    while (byte < 8 && !isBitSet)
+    {
+        uint8_t currentByte = this->pldmTypes[byte].byte;
+        int index = bit + 1;
+
+        // Skip already traversed bits of the current byte
+        currentByte = currentByte >> (bit + 1);
+        while (currentByte)
+        {
+            if (currentByte & 1)
+            {
+                isBitSet = true;
+                bit = index;
+                break;
+            }
+            index++;
+            currentByte = currentByte >> 1;
+        }
+
+        if (!isBitSet)
+        {
+            byte++;
+            bit = -1; // We need to start from 0th bit of
+                      // the next byte
+        }
+    }
+    if (byte == 8 && !isBitSet)
+    {
+        return std::nullopt;
+    }
+    return (bit + byte * 8);
 }
 
 void BaseDiscoveryStateMachine::printState()
diff --git a/util/state_machine/discovery/base/base_disc_state_machine.hpp b/util/state_machine/discovery/base/base_disc_state_machine.hpp
index d1b15f9..55091bb 100644
--- a/util/state_machine/discovery/base/base_disc_state_machine.hpp
+++ b/util/state_machine/discovery/base/base_disc_state_machine.hpp
@@ -32,7 +32,7 @@
 
     OperationStatus triggerNextCommand() override;
 
-    OperationStatus pushCommandResponse(struct pldm_msg* respMsg,
+    OperationStatus pushCommandResponse(const struct pldm_msg* respMsg,
                                         size_t respSize) override;
 
     void printState() override;
diff --git a/util/state_machine/state_machine_factory.hpp b/util/state_machine/state_machine_factory.hpp
index 0539fb6..d00a065 100644
--- a/util/state_machine/state_machine_factory.hpp
+++ b/util/state_machine/state_machine_factory.hpp
@@ -59,7 +59,7 @@
     /**
      * @brief Updates the state machine after receiving a response
      */
-    virtual OperationStatus pushCommandResponse(struct pldm_msg* respMsg,
+    virtual OperationStatus pushCommandResponse(const struct pldm_msg* respMsg,
                                                 size_t respSize) = 0;
 
     /**