libpldm: Implement encode/decode for GetStateSensorReadings

The spec of GetStateSensorReadings command refers to DSP0248_1.2.0: 20.2

Change-Id: I8b2222196d1b960697b73d83911937c4164b09af
Signed-off-by: Jolie Ku <jolie_ku@wistron.com>
diff --git a/libpldm/platform.c b/libpldm/platform.c
index aef6c5e..cd332e6 100644
--- a/libpldm/platform.c
+++ b/libpldm/platform.c
@@ -428,3 +428,130 @@
 
 	return PLDM_SUCCESS;
 }
+
+int encode_get_state_sensor_readings_resp(uint8_t instance_id,
+					  uint8_t completion_code,
+					  uint8_t comp_sensor_count,
+					  get_sensor_state_field *field,
+					  struct pldm_msg *msg)
+{
+	struct pldm_header_info header = {0};
+	int rc = PLDM_SUCCESS;
+
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_GET_STATE_SENSOR_READINGS;
+
+	if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
+		return rc;
+	}
+
+	if (comp_sensor_count < 0x1 || comp_sensor_count > 0x8) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_get_state_sensor_readings_resp *response =
+	    (struct pldm_get_state_sensor_readings_resp *)msg->payload;
+
+	response->completion_code = completion_code;
+	response->comp_sensor_count = comp_sensor_count;
+	memcpy(response->field, field,
+	       (sizeof(get_sensor_state_field) * comp_sensor_count));
+
+	return rc;
+}
+
+int encode_get_state_sensor_readings_req(uint8_t instance_id,
+					 uint16_t sensor_id,
+					 bitfield8_t sensor_rearm,
+					 uint8_t reserved, 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_GET_STATE_SENSOR_READINGS;
+
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_state_sensor_readings_req *request =
+	    (struct pldm_get_state_sensor_readings_req *)msg->payload;
+
+	request->sensor_id = htole16(sensor_id);
+	request->reserved = reserved;
+	request->sensor_rearm = sensor_rearm;
+
+	return PLDM_SUCCESS;
+}
+
+int decode_get_state_sensor_readings_resp(const struct pldm_msg *msg,
+					  size_t payload_length,
+					  uint8_t *completion_code,
+					  uint8_t *comp_sensor_count,
+					  get_sensor_state_field *field)
+{
+	if (msg == NULL || completion_code == NULL ||
+	    comp_sensor_count == NULL || field == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length > PLDM_GET_STATE_SENSOR_READINGS_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_state_sensor_readings_resp *response =
+	    (struct pldm_get_state_sensor_readings_resp *)msg->payload;
+
+	if (response->comp_sensor_count < 0x1 ||
+	    response->comp_sensor_count > 0x8) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (response->comp_sensor_count > *comp_sensor_count) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+	*comp_sensor_count = response->comp_sensor_count;
+
+	memcpy(field, response->field,
+	       (sizeof(get_sensor_state_field) * (*comp_sensor_count)));
+
+	return PLDM_SUCCESS;
+}
+
+int decode_get_state_sensor_readings_req(const struct pldm_msg *msg,
+					 size_t payload_length,
+					 uint16_t *sensor_id,
+					 bitfield8_t *sensor_rearm,
+					 uint8_t *reserved)
+{
+	if (msg == NULL || sensor_id == NULL || sensor_rearm == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_state_sensor_readings_req *request =
+	    (struct pldm_get_state_sensor_readings_req *)msg->payload;
+
+	*sensor_id = le16toh(request->sensor_id);
+	*reserved = request->reserved;
+	memcpy(&(sensor_rearm->byte), &(request->sensor_rearm.byte),
+	       sizeof(request->sensor_rearm.byte));
+
+	return PLDM_SUCCESS;
+}
diff --git a/libpldm/platform.h b/libpldm/platform.h
index 0cce1b4..0371d1c 100644
--- a/libpldm/platform.h
+++ b/libpldm/platform.h
@@ -12,8 +12,10 @@
 
 /* Maximum size for request */
 #define PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES 19
+#define PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES 4
 /* Response lengths are inclusive of completion code */
 #define PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES 1
+#define PLDM_GET_STATE_SENSOR_READINGS_RESP_BYTES 34
 
 #define PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES 1
 #define PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES 4
@@ -35,7 +37,33 @@
 
 enum effecter_state { PLDM_INVALID_VALUE = 0xFF };
 
+enum sensor_operational_state {
+	ENABLED = 0x00,
+	DISABLED = 0x01,
+	UNAVAILABLE = 0x02,
+	STATUSUNKNOWN = 0x03,
+	FAILED = 0x04,
+	INITIALIZING = 0x05,
+	SHUTTINGDOWN = 0x06,
+	INTEST = 0x07
+};
+
+enum present_state {
+	UNKNOWN = 0x0,
+	NORMAL = 0x01,
+	WARNING = 0x02,
+	CRITICAL = 0x03,
+	FATAL = 0x04,
+	LOWERWARNING = 0x05,
+	LOWERCRITICAL = 0x06,
+	LOWERFATAL = 0x07,
+	UPPERWARNING = 0x08,
+	UPPERCRITICAL = 0x09,
+	UPPERFATAL = 0x0a
+};
+
 enum pldm_platform_commands {
+	PLDM_GET_STATE_SENSOR_READINGS = 0x21,
 	PLDM_SET_NUMERIC_EFFECTER_VALUE = 0x31,
 	PLDM_SET_STATE_EFFECTER_STATES = 0x39,
 	PLDM_GET_PDR = 0x51,
@@ -127,6 +155,20 @@
 	uint8_t effecter_state; //!< Expected state of the effecter
 } __attribute__((packed)) set_effecter_state_field;
 
+/** @struct get_sensor_readings_field
+ *
+ *  Structure representing a stateField in GetStateSensorReadings command */
+
+typedef struct state_field_for_get_state_sensor_readings {
+	uint8_t sensor_op_state; //!< The state of the sensor itself
+	uint8_t present_state;   //!< Return a state value
+	uint8_t previous_state; //!< The state that the presentState was entered
+				//! from. This must be different from the
+				//! present state
+	uint8_t event_state;    //!< Return a state value from a PLDM State Set
+			     //! that is associated with the sensor
+} __attribute__((packed)) get_sensor_state_field;
+
 /** @struct PLDM_SetStateEffecterStates_Request
  *
  *  Structure representing PLDM set state effecter states request.
@@ -174,6 +216,26 @@
 	uint8_t effecter_value[1];
 } __attribute__((packed));
 
+/** @struct pldm_get_state_sensor_readings_req
+ *
+ *  Structure representing PLDM get state sensor readings request.
+ */
+struct pldm_get_state_sensor_readings_req {
+	uint16_t sensor_id;
+	bitfield8_t sensor_rearm;
+	uint8_t reserved;
+} __attribute__((packed));
+
+/** @struct pldm_get_state_sensor_readings_resp
+ *
+ *  Structure representing PLDM get state sensor readings response.
+ */
+struct pldm_get_state_sensor_readings_resp {
+	uint8_t completion_code;
+	uint8_t comp_sensor_count;
+	get_sensor_state_field field[1];
+} __attribute__((packed));
+
 /* Responder */
 
 /* SetNumericEffecterValue */
@@ -299,6 +361,48 @@
 		       uint8_t *transfer_op_flag, uint16_t *request_cnt,
 		       uint16_t *record_chg_num);
 
+/* GetStateSensorReadings */
+
+/** @brief Decode GetStateSensorReadings request data
+ *
+ *  @param[in] msg - Request message
+ *  @param[in] payload_length - Length of request message payload
+ *  @param[out] sensor_id - used to identify and access the simple or composite
+ *         sensor
+ *  @param[out] sensor_rearm - Each bit location in this field corresponds to a
+ *         particular sensor within the state sensor, where bit [0] corresponds
+ *         to the first state sensor (sensor offset 0) and bit [7] corresponds
+ *         to the eighth sensor (sensor offset 7), sequentially.
+ *  @param[out] reserved - value: 0x00
+ *  @return pldm_completion_codes
+ */
+
+int decode_get_state_sensor_readings_req(const struct pldm_msg *msg,
+					 size_t payload_length,
+					 uint16_t *sensor_id,
+					 bitfield8_t *sensor_rearm,
+					 uint8_t *reserved);
+
+/** @brief Encode GetStateSensorReadings response data
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] completion_code - PLDM completion code
+ *  @param[out] comp_sensor_count - The number of individual sets of sensor
+ *         information that this command accesses
+ *  @param[out] field - Each stateField is an instance of a stateField structure
+ *         that is used to return the present operational state setting and the
+ *         present state and event state for a particular set of sensor
+ *         information contained within the state sensor
+ *  @param[out] msg - Message will be written to this
+ *  @return pldm_completion_codes
+ */
+
+int encode_get_state_sensor_readings_resp(uint8_t instance_id,
+					  uint8_t completion_code,
+					  uint8_t comp_sensor_count,
+					  get_sensor_state_field *field,
+					  struct pldm_msg *msg);
+
 /* Requester */
 
 /* GetPDR */
@@ -433,6 +537,48 @@
 					   size_t payload_length,
 					   uint8_t *completion_code);
 
+/** @brief Create a PLDM request message for GetStateSensorReadings
+ *
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] sensor_id - used to identify and access the simple or composite
+ *         sensor
+ *  @param[in] sensorRearm - Each bit location in this field corresponds to a
+ *         particular sensor within the state sensor, where bit [0] corresponds
+ *         to the first state sensor (sensor offset 0) and bit [7] corresponds
+ *         to the eighth sensor (sensor offset 7), sequentially
+ *  @param[in] reserved - value: 0x00
+ *  @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.payload'
+ */
+
+int encode_get_state_sensor_readings_req(uint8_t instance_id,
+					 uint16_t sensor_id,
+					 bitfield8_t sensor_rearm,
+					 uint8_t reserved,
+					 struct pldm_msg *msg);
+
+/** @brief Decode GetStateSensorReadings response data
+ *
+ *  @param[in] msg - Request message
+ *  @param[in] payload_length - Length of response message payload
+ *  @param[out] completion_code - PLDM completion code
+ *  @param[in,out] comp_sensor_count - The number of individual sets of sensor
+ *         information that this command accesses
+ *  @param[out] field - Each stateField is an instance of a stateField structure
+ *         that is used to return the present operational state setting and the
+ *         present state and event state for a particular set of sensor
+ *         information contained within the state sensor
+ *  @return pldm_completion_codes
+ */
+
+int decode_get_state_sensor_readings_resp(const struct pldm_msg *msg,
+					  size_t payload_length,
+					  uint8_t *completion_code,
+					  uint8_t *comp_sensor_count,
+					  get_sensor_state_field *field);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libpldm/tests/libpldm_platform_test.cpp b/libpldm/tests/libpldm_platform_test.cpp
index f810ae4..b6f47c8 100644
--- a/libpldm/tests/libpldm_platform_test.cpp
+++ b/libpldm/tests/libpldm_platform_test.cpp
@@ -546,3 +546,223 @@
         0, PLDM_SUCCESS, NULL, PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES);
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 }
+
+TEST(GetStateSensorReadings, testGoodEncodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_STATE_SENSOR_READINGS_RESP_BYTES>
+        responseMsg{};
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    uint8_t completionCode = 0;
+    uint8_t comp_sensorCnt = 0x2;
+
+    std::array<get_sensor_state_field, 2> stateField{};
+    stateField[0] = {ENABLED, NORMAL, WARNING, UNKNOWN};
+    stateField[1] = {FAILED, UPPERFATAL, UPPERCRITICAL, FATAL};
+
+    auto rc = encode_get_state_sensor_readings_resp(
+        0, PLDM_SUCCESS, comp_sensorCnt, stateField.data(), response);
+
+    struct pldm_get_state_sensor_readings_resp* resp =
+        reinterpret_cast<struct pldm_get_state_sensor_readings_resp*>(
+            response->payload);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completionCode, resp->completion_code);
+    EXPECT_EQ(comp_sensorCnt, resp->comp_sensor_count);
+    EXPECT_EQ(stateField[0].sensor_op_state, resp->field->sensor_op_state);
+    EXPECT_EQ(stateField[0].present_state, resp->field->present_state);
+    EXPECT_EQ(stateField[0].previous_state, resp->field->previous_state);
+    EXPECT_EQ(stateField[0].event_state, resp->field->event_state);
+    EXPECT_EQ(stateField[1].sensor_op_state, resp->field[1].sensor_op_state);
+    EXPECT_EQ(stateField[1].present_state, resp->field[1].present_state);
+    EXPECT_EQ(stateField[1].previous_state, resp->field[1].previous_state);
+    EXPECT_EQ(stateField[1].event_state, resp->field[1].event_state);
+}
+
+TEST(GetStateSensorReadings, testBadEncodeResponse)
+{
+    auto rc = encode_get_state_sensor_readings_resp(0, PLDM_SUCCESS, 0, nullptr,
+                                                    nullptr);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(GetStateSensorReadings, testGoodDecodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_STATE_SENSOR_READINGS_RESP_BYTES>
+        responseMsg{};
+
+    uint8_t completionCode = 0;
+    uint8_t comp_sensorCnt = 2;
+
+    std::array<get_sensor_state_field, 2> stateField{};
+    stateField[0] = {DISABLED, UNKNOWN, UNKNOWN, UNKNOWN};
+    stateField[1] = {ENABLED, LOWERFATAL, LOWERCRITICAL, WARNING};
+
+    uint8_t retcompletion_code = 0;
+    uint8_t retcomp_sensorCnt = 2;
+    std::array<get_sensor_state_field, 2> retstateField{};
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    struct pldm_get_state_sensor_readings_resp* resp =
+        reinterpret_cast<struct pldm_get_state_sensor_readings_resp*>(
+            response->payload);
+
+    resp->completion_code = completionCode;
+    resp->comp_sensor_count = comp_sensorCnt;
+    memcpy(resp->field, &stateField,
+           (sizeof(get_sensor_state_field) * comp_sensorCnt));
+
+    auto rc = decode_get_state_sensor_readings_resp(
+        response, responseMsg.size() - hdrSize, &retcompletion_code,
+        &retcomp_sensorCnt, retstateField.data());
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completionCode, retcompletion_code);
+    EXPECT_EQ(comp_sensorCnt, retcomp_sensorCnt);
+    EXPECT_EQ(stateField[0].sensor_op_state, retstateField[0].sensor_op_state);
+    EXPECT_EQ(stateField[0].present_state, retstateField[0].present_state);
+    EXPECT_EQ(stateField[0].previous_state, retstateField[0].previous_state);
+    EXPECT_EQ(stateField[0].event_state, retstateField[0].event_state);
+    EXPECT_EQ(stateField[1].sensor_op_state, retstateField[1].sensor_op_state);
+    EXPECT_EQ(stateField[1].present_state, retstateField[1].present_state);
+    EXPECT_EQ(stateField[1].previous_state, retstateField[1].previous_state);
+    EXPECT_EQ(stateField[1].event_state, retstateField[1].event_state);
+}
+
+TEST(GetStateSensorReadings, testBadDecodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_STATE_SENSOR_READINGS_RESP_BYTES>
+        responseMsg{};
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_get_state_sensor_readings_resp(
+        response, responseMsg.size() - hdrSize, nullptr, nullptr, nullptr);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    uint8_t completionCode = 0;
+    uint8_t comp_sensorCnt = 1;
+
+    std::array<get_sensor_state_field, 1> stateField{};
+    stateField[0] = {ENABLED, UPPERFATAL, UPPERCRITICAL, WARNING};
+
+    uint8_t retcompletion_code = 0;
+    uint8_t retcomp_sensorCnt = 0;
+    std::array<get_sensor_state_field, 1> retstateField{};
+
+    struct pldm_get_state_sensor_readings_resp* resp =
+        reinterpret_cast<struct pldm_get_state_sensor_readings_resp*>(
+            response->payload);
+
+    resp->completion_code = completionCode;
+    resp->comp_sensor_count = comp_sensorCnt;
+    memcpy(resp->field, &stateField,
+           (sizeof(get_sensor_state_field) * comp_sensorCnt));
+
+    rc = decode_get_state_sensor_readings_resp(
+        response, responseMsg.size() - hdrSize, &retcompletion_code,
+        &retcomp_sensorCnt, retstateField.data());
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(GetStateSensorReadings, testGoodEncodeRequest)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES>
+        requestMsg{};
+
+    uint16_t sensorId = 0xAB;
+    bitfield8_t sensorRearm;
+    sensorRearm.byte = 0x03;
+
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto rc = encode_get_state_sensor_readings_req(0, sensorId, sensorRearm, 0,
+                                                   request);
+
+    struct pldm_get_state_sensor_readings_req* req =
+        reinterpret_cast<struct pldm_get_state_sensor_readings_req*>(
+            request->payload);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(sensorId, le16toh(req->sensor_id));
+    EXPECT_EQ(sensorRearm.byte, req->sensor_rearm.byte);
+}
+
+TEST(GetStateSensorReadings, testBadEncodeRequest)
+{
+    bitfield8_t sensorRearm;
+    sensorRearm.byte = 0x0;
+
+    auto rc =
+        encode_get_state_sensor_readings_req(0, 0, sensorRearm, 0, nullptr);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(GetStateSensorReadings, testGoodDecodeRequest)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES>
+        requestMsg{};
+
+    uint16_t sensorId = 0xCD;
+    bitfield8_t sensorRearm;
+    sensorRearm.byte = 0x10;
+
+    uint16_t retsensorId;
+    bitfield8_t retsensorRearm;
+    uint8_t retreserved;
+
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    struct pldm_get_state_sensor_readings_req* req =
+        reinterpret_cast<struct pldm_get_state_sensor_readings_req*>(
+            request->payload);
+
+    req->sensor_id = htole16(sensorId);
+    req->sensor_rearm.byte = sensorRearm.byte;
+
+    auto rc = decode_get_state_sensor_readings_req(
+        request, requestMsg.size() - hdrSize, &retsensorId, &retsensorRearm,
+        &retreserved);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(sensorId, retsensorId);
+    EXPECT_EQ(sensorRearm.byte, retsensorRearm.byte);
+    EXPECT_EQ(0, retreserved);
+}
+
+TEST(GetStateSensorReadings, testBadDecodeRequest)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES>
+        requestMsg{};
+
+    auto rc = decode_get_state_sensor_readings_req(
+        nullptr, requestMsg.size() - hdrSize, nullptr, nullptr, nullptr);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    uint16_t sensorId = 0x11;
+    bitfield8_t sensorRearm;
+    sensorRearm.byte = 0x04;
+
+    uint16_t retsensorId;
+    bitfield8_t retsensorRearm;
+    uint8_t retreserved;
+
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    struct pldm_get_state_sensor_readings_req* req =
+        reinterpret_cast<struct pldm_get_state_sensor_readings_req*>(
+            request->payload);
+
+    req->sensor_id = htole16(sensorId);
+    req->sensor_rearm.byte = sensorRearm.byte;
+
+    rc = decode_get_state_sensor_readings_req(
+        request, requestMsg.size() - hdrSize - 1, &retsensorId, &retsensorRearm,
+        &retreserved);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}