libpldm : add encode/decode APIs for SetStateEffecterStates

This commit implements the encode request and decode
response APIs for the SetStateEffecterStates command.
This enables BMC requester apps to send this command and
process the received response.

Change-Id: I1436c8730553b5a1aed8cda1fa90b8742e5be228
Signed-off-by: vkaverap <vkaverap@in.ibm.com>
diff --git a/libpldm/platform.c b/libpldm/platform.c
index 8bdd406..9d3a427 100644
--- a/libpldm/platform.c
+++ b/libpldm/platform.c
@@ -22,6 +22,52 @@
 	return rc;
 }
 
+int encode_set_state_effecter_states_req(uint8_t instance_id,
+					 uint16_t effecter_id,
+					 uint8_t comp_effecter_count,
+					 set_effecter_state_field *field,
+					 struct pldm_msg *msg)
+{
+	struct pldm_header_info header = {0};
+	int rc = PLDM_SUCCESS;
+
+	header.msg_type = PLDM_REQUEST;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_SET_STATE_EFFECTER_STATES;
+
+	if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
+		return rc;
+	}
+
+	if (comp_effecter_count < 0x1 || comp_effecter_count > 0x8) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	uint8_t *encoded_msg = msg->body.payload;
+	effecter_id = htole16(effecter_id);
+	memcpy(encoded_msg, &effecter_id, sizeof(effecter_id));
+	encoded_msg += sizeof(effecter_id);
+	memcpy(encoded_msg, &comp_effecter_count, sizeof(comp_effecter_count));
+	encoded_msg += sizeof(comp_effecter_count);
+	memcpy(encoded_msg, field,
+	       (sizeof(set_effecter_state_field) * comp_effecter_count));
+
+	return PLDM_SUCCESS;
+}
+
+int decode_set_state_effecter_states_resp(const struct pldm_msg_payload *msg,
+					  uint8_t *completion_code)
+{
+	if (msg == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = *(uint8_t *)msg->payload;
+
+	return PLDM_SUCCESS;
+}
+
 int decode_set_state_effecter_states_req(const struct pldm_msg_payload *msg,
 					 uint16_t *effecter_id,
 					 uint8_t *comp_effecter_count,
diff --git a/libpldm/platform.h b/libpldm/platform.h
index 7741863..42169db 100644
--- a/libpldm/platform.h
+++ b/libpldm/platform.h
@@ -71,6 +71,40 @@
 					 uint8_t *comp_effecter_count,
 					 set_effecter_state_field *field);
 
+/** @brief Create a PLDM request message for SetStateEffecterStates
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] effecter_id - used to identify and access the effecter
+ *  @param[in] comp_effecter_count - number of individual sets of effecter
+ *         information. Upto eight sets of state effecter info can be accessed
+ *         for a given effecter.
+ *  @param[in] field - each unit is an instance of the stateField structure
+ *         that is used to set the requested state for a particular effecter
+ *         within the state effecter. This field holds the starting address of
+ *         the stateField values. The user is responsible to allocate the
+ *         memory prior to calling this command. The user has to allocate the
+ *         field parameter as sizeof(set_effecter_state_field) *
+ *         comp_effecter_count
+ *  @param[out] msg - Message will be written to this
+ *  @return pldm_completion_codes
+ *  @note  Caller is responsible for memory alloc and dealloc of param
+ *         'msg.body.payload'
+ */
+
+int encode_set_state_effecter_states_req(uint8_t instance_id,
+					 uint16_t effecter_id,
+					 uint8_t comp_effecter_count,
+					 set_effecter_state_field *field,
+					 struct pldm_msg *msg);
+
+/** @brief Decode SetStateEffecterStates response data
+ *  @param[in] msg - Request message payload
+ *  @param[out] completion_code - PLDM completion code
+ *  @return pldm_completion_codes
+ */
+int decode_set_state_effecter_states_resp(const struct pldm_msg_payload *msg,
+					  uint8_t *completion_code);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/test/libpldm_platform_test.cpp b/test/libpldm_platform_test.cpp
index 0de82e4..1e14b25 100644
--- a/test/libpldm_platform_test.cpp
+++ b/test/libpldm_platform_test.cpp
@@ -24,6 +24,66 @@
     ASSERT_EQ(completionCode, response.body.payload[0]);
 }
 
+TEST(SetStateEffecterStates, testEncodeRequest)
+{
+    pldm_msg request{};
+    uint16_t effecterId = 0x0A;
+    uint8_t compEffecterCnt = 0x2;
+    std::array<set_effecter_state_field, 8> stateField{};
+    stateField[0] = {PLDM_REQUEST_SET, 2};
+    stateField[1] = {PLDM_REQUEST_SET, 3};
+
+    std::array<uint8_t, PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES> requestMsg{};
+
+    request.body.payload = requestMsg.data();
+    request.body.payload_length = requestMsg.size();
+
+    auto rc = encode_set_state_effecter_states_req(
+        0, effecterId, compEffecterCnt, stateField.data(), &request);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(effecterId, request.body.payload[0]);
+    ASSERT_EQ(compEffecterCnt, request.body.payload[sizeof(effecterId)]);
+    ASSERT_EQ(
+        stateField[0].set_request,
+        request.body.payload[sizeof(effecterId) + sizeof(compEffecterCnt)]);
+    ASSERT_EQ(
+        stateField[0].effecter_state,
+        request.body.payload[sizeof(effecterId) + sizeof(compEffecterCnt) +
+                             sizeof(stateField[0].set_request)]);
+    ASSERT_EQ(
+        stateField[1].set_request,
+        request.body.payload[sizeof(effecterId) + sizeof(compEffecterCnt) +
+                             sizeof(stateField[0])]);
+    ASSERT_EQ(
+        stateField[1].effecter_state,
+        request.body.payload[sizeof(effecterId) + sizeof(compEffecterCnt) +
+                             sizeof(stateField[0]) +
+                             sizeof(stateField[1].set_request)]);
+}
+
+TEST(SetStateEffecterStates, testGoodDecodeResponse)
+{
+    std::array<uint8_t, PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES>
+        responseMsg{};
+
+    pldm_msg_payload response{};
+    response.payload = responseMsg.data();
+    response.payload_length = responseMsg.size();
+
+    uint8_t completion_code = 0xA0;
+
+    uint8_t retcompletion_code = 0;
+
+    memcpy(response.payload, &completion_code, sizeof(completion_code));
+
+    auto rc =
+        decode_set_state_effecter_states_resp(&response, &retcompletion_code);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(completion_code, retcompletion_code);
+}
+
 TEST(SetStateEffecterStates, testGoodDecodeRequest)
 {
     std::array<uint8_t, PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES> requestMsg{};
@@ -74,3 +134,17 @@
 
     ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 }
+
+TEST(SetStateEffecterStates, testBadDecodeResponse)
+{
+    std::array<uint8_t, PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES>
+        responseMsg{};
+
+    pldm_msg_payload response{};
+    response.payload = responseMsg.data();
+    response.payload_length = responseMsg.size();
+
+    auto rc = decode_set_state_effecter_states_resp(&response, NULL);
+
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}