dsp: platform: Add sensor enable responder

Add responder definitions and decode routines for
SetStateSensorEnables and SetNumericSensorEnable

Change-Id: Ic93da95f6b3cda4a99951943ebba1b1e20b95d79
Signed-off-by: Matt Johnston <matt@codeconstruct.com.au>
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 27f6cb7..5a38ba2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,8 @@
 - firmware update: Add support for DSP0267 v1.2.0 by adding
   `component_opaque_data` fields to correctly parse their contents.
 - firmware_update: Add 1.3.0 version updates.
+- platform: Add SetStateSensorEnables and SetNumericSensorEnable responder
+  decode.
 
 - firmware update: Add support for DSP0267 v1.3.0 by: Adding
   `reference_manifest_data` and `payload_checksum` fields to correctly parse
diff --git a/include/libpldm/platform.h b/include/libpldm/platform.h
index 4cce891..cc696a4 100644
--- a/include/libpldm/platform.h
+++ b/include/libpldm/platform.h
@@ -321,6 +321,9 @@
 	PLDM_PLATFORM_INVALID_PROTOCOL_TYPE = 0x80,
 	PLDM_PLATFORM_ENABLE_METHOD_NOT_SUPPORTED = 0x81,
 	PLDM_PLATFORM_HEARTBEAT_FREQUENCY_TOO_HIGH = 0x82,
+
+	PLDM_PLATFORM_INVALID_SENSOR_OPERATIONAL_STATE = 0x81,
+	PLDM_PLATFORM_EVENT_GENERATION_NOT_SUPPORTED = 0x82,
 };
 
 /** @brief PLDM Event types
@@ -357,6 +360,15 @@
 	PLDM_SENSOR_INTEST
 };
 
+/** @brief PLDM operation states for Set Numeric/State Sensor State.
+ *  This is a subset of pldm_sensor_operational_state.
+ */
+enum pldm_set_sensor_operational_state {
+	PLDM_SET_SENSOR_ENABLED,
+	PLDM_SET_SENSOR_DISABLED,
+	PLDM_SET_SENSOR_UNAVAILABLE,
+};
+
 /** @brief PLDM pldmPDRRepositoryChgEvent class eventData format
  */
 enum pldm_pdr_repository_chg_event_data_format {
@@ -1355,6 +1367,38 @@
 	uint8_t present_reading[1];
 } __attribute__((packed));
 
+/** @struct pldm_set_numeric_sensor_enable_req
+ *
+ *  Structure representing a SetNumericSensorEnable request
+ */
+struct pldm_set_numeric_sensor_enable_req {
+	uint16_t sensor_id;
+	enum pldm_set_sensor_operational_state op_state;
+	enum pldm_sensor_event_message_enable event_enable;
+};
+
+/** @struct pldm_set_state_sensor_enable_field
+ *
+ *  Structure representing PLDM set state sensor enables fields
+ */
+struct pldm_set_state_sensor_enable_field {
+	enum pldm_set_sensor_operational_state op_state;
+	enum pldm_sensor_event_message_enable event_enable;
+};
+
+#define PLDM_SET_STATE_SENSOR_ENABLES_MAX_COUNT 8
+
+/** @struct pldm_set_state_sensor_enables_req
+ *
+ *  Structure representing a SetStateSensorEnables request
+ */
+struct pldm_set_state_sensor_enables_req {
+	uint16_t sensor_id;
+	uint8_t field_count;
+	struct pldm_set_state_sensor_enable_field
+		fields[PLDM_SET_STATE_SENSOR_ENABLES_MAX_COUNT];
+};
+
 /* Responder */
 
 /* SetNumericEffecterValue */
@@ -2677,6 +2721,40 @@
  */
 int decode_pldm_file_descriptor_pdr(const void *data, size_t data_length,
 				    struct pldm_file_descriptor_pdr *pdr);
+
+/** @brief Decode SetNumericSensorEnable request
+ *
+ *  @param[in] msg - PLDM request message.
+ *  @param[in] payload_length - Length of request message.
+ *  @param[out] req - Returned decoded request.
+ *
+ *  @return error code: 0 on success
+ *                      -EINVAL if the function input parameters are incorrect
+ *                      -EPROTO if the input request message is invalid
+ *                      -EBADMSG if the input request message is too long
+ *                      -EOVERFLOW if the input request message is too short.
+ */
+int decode_set_numeric_sensor_enable_req(
+	const struct pldm_msg *msg, size_t payload_length,
+	struct pldm_set_numeric_sensor_enable_req *req);
+
+/** @brief Decode SetStateSensorEnables request
+ *
+ *  @param[in] msg - PLDM request message.
+ *  @param[in] payload_length - Length of request message.
+ *  @param[out] req - Returned decoded request.
+ *                    .field_count is set to the number of populated fields.
+ *
+ *  @return error code: 0 on success
+ *                      -EINVAL if the function input parameters are incorrect
+ *                      -EPROTO if the input request message is invalid
+ *                      -EBADMSG if the input request message is too long
+ *                      -EOVERFLOW if the input request message is too short.
+ */
+int decode_set_state_sensor_enables_req(
+	const struct pldm_msg *msg, size_t payload_length,
+	struct pldm_set_state_sensor_enables_req *req);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/dsp/platform.c b/src/dsp/platform.c
index 693727e..297a033 100644
--- a/src/dsp/platform.c
+++ b/src/dsp/platform.c
@@ -2504,6 +2504,101 @@
 }
 
 LIBPLDM_ABI_TESTING
+int decode_set_numeric_sensor_enable_req(
+	const struct pldm_msg *msg, size_t payload_length,
+	struct pldm_set_numeric_sensor_enable_req *req)
+{
+	PLDM_MSGBUF_DEFINE_P(buf);
+	uint8_t event_enable = 0;
+	uint8_t op_state = 0;
+	int rc;
+
+	if (msg == NULL || req == NULL) {
+		return -EINVAL;
+	}
+
+	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract(buf, req->sensor_id);
+	pldm_msgbuf_extract(buf, op_state);
+	pldm_msgbuf_extract(buf, event_enable);
+
+	rc = pldm_msgbuf_complete_consumed(buf);
+	if (rc) {
+		return rc;
+	}
+
+	if (op_state > PLDM_SET_SENSOR_UNAVAILABLE) {
+		return -EPROTO;
+	}
+
+	if (event_enable > PLDM_STATE_EVENTS_ONLY_ENABLED) {
+		return -EPROTO;
+	}
+
+	req->op_state = op_state;
+	req->event_enable = event_enable;
+
+	return 0;
+}
+
+LIBPLDM_ABI_TESTING
+int decode_set_state_sensor_enables_req(
+	const struct pldm_msg *msg, size_t payload_length,
+	struct pldm_set_state_sensor_enables_req *req)
+{
+	PLDM_MSGBUF_DEFINE_P(buf);
+	int rc;
+
+	if (msg == NULL || req == NULL) {
+		return -EINVAL;
+	}
+
+	rc = pldm_msgbuf_init_errno(buf, 3, msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract(buf, req->sensor_id);
+	rc = pldm_msgbuf_extract(buf, req->field_count);
+	if (rc) {
+		return rc;
+	}
+
+	if (req->field_count < 1 ||
+	    req->field_count > PLDM_SET_STATE_SENSOR_ENABLES_MAX_COUNT) {
+		return -EPROTO;
+	}
+
+	for (uint8_t i = 0; i < req->field_count; i++) {
+		uint8_t event_enable_val = 0;
+		uint8_t op_state_val = 0;
+
+		pldm_msgbuf_extract(buf, op_state_val);
+		rc = pldm_msgbuf_extract(buf, event_enable_val);
+		if (rc) {
+			return pldm_msgbuf_discard(buf, rc);
+		}
+
+		if (op_state_val > PLDM_SET_SENSOR_UNAVAILABLE) {
+			return pldm_msgbuf_discard(buf, -EPROTO);
+		}
+
+		if (event_enable_val > PLDM_STATE_EVENTS_ONLY_ENABLED) {
+			return pldm_msgbuf_discard(buf, -EPROTO);
+		}
+
+		req->fields[i].op_state = op_state_val;
+		req->fields[i].event_enable = event_enable_val;
+	}
+
+	return pldm_msgbuf_complete_consumed(buf);
+}
+
+LIBPLDM_ABI_TESTING
 int encode_get_event_receiver_req(uint8_t instance_id, struct pldm_msg *msg,
 				  size_t payload_length LIBPLDM_CC_UNUSED)
 {
diff --git a/tests/dsp/platform.cpp b/tests/dsp/platform.cpp
index 1cfdb0a..4427cbc 100644
--- a/tests/dsp/platform.cpp
+++ b/tests/dsp/platform.cpp
@@ -3594,6 +3594,175 @@
 }
 
 #ifdef LIBPLDM_API_TESTING
+TEST(SetNumericSensorEnable, testDecodeRequest)
+{
+    int rc;
+    struct pldm_set_numeric_sensor_enable_req decoded;
+
+    const std::array<uint8_t, hdrSize + 5> req
+        // PLDM header
+        {
+            PLDM_PLATFORM, 0x80, PLDM_SET_NUMERIC_SENSOR_ENABLE,
+            0x67,          0x45, // sensor ID 0x4567
+            0x00,                // sensorOperationalState
+            0x01,                // sensorEventMessageEnable
+            0x00,                // extra
+        };
+
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    auto msg = reinterpret_cast<const pldm_msg*>(req.data());
+
+    // Good decode
+    rc = decode_set_numeric_sensor_enable_req(msg, 4, &decoded);
+    EXPECT_EQ(rc, 0);
+    EXPECT_EQ(decoded.sensor_id, 0x4567);
+    EXPECT_EQ(decoded.op_state, PLDM_SENSOR_ENABLED);
+    EXPECT_EQ(decoded.event_enable, PLDM_EVENTS_DISABLED);
+
+    // Fail short
+    rc = decode_set_numeric_sensor_enable_req(msg, 3, &decoded);
+    EXPECT_EQ(rc, -EOVERFLOW);
+    // Fail long
+    rc = decode_set_numeric_sensor_enable_req(msg, 5, &decoded);
+    EXPECT_EQ(rc, -EBADMSG);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
+TEST(SetNumericSensorEnable, testDecodeInvalidOpRequest)
+{
+    int rc;
+    struct pldm_set_numeric_sensor_enable_req decoded;
+
+    const std::array<uint8_t, hdrSize + 4> req
+        // PLDM header
+        {
+            PLDM_PLATFORM, 0x80, PLDM_SET_NUMERIC_SENSOR_ENABLE,
+            0x67,          0x45, // sensor ID 0x4567
+            0x30,                // Invalid sensorOperationalState
+            0x01,                // sensorEventMessageEnable
+        };
+
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    auto msg = reinterpret_cast<const pldm_msg*>(req.data());
+
+    rc = decode_set_numeric_sensor_enable_req(msg, 4, &decoded);
+    EXPECT_EQ(rc, -EPROTO);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
+TEST(SetNumericSensorEnable, testDecodeInvalidEventRequest)
+{
+    int rc;
+    struct pldm_set_numeric_sensor_enable_req decoded;
+
+    const std::array<uint8_t, hdrSize + 4> req
+        // PLDM header
+        {
+            PLDM_PLATFORM, 0x80, PLDM_SET_NUMERIC_SENSOR_ENABLE,
+            0x67,          0x45, // sensor ID 0x4567
+            0x00,                // sensorOperationalState
+            0x77,                // Invalid sensorEventMessageEnable
+        };
+
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    auto msg = reinterpret_cast<const pldm_msg*>(req.data());
+
+    rc = decode_set_numeric_sensor_enable_req(msg, 4, &decoded);
+    EXPECT_EQ(rc, -EPROTO);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
+TEST(SetStateSensorEnables, testDecodeRequest)
+{
+    int rc;
+    struct pldm_set_state_sensor_enables_req decoded;
+
+    const std::array<uint8_t, hdrSize + 8> req
+        // PLDM header
+        {
+            PLDM_PLATFORM, 0x80, PLDM_SET_STATE_SENSOR_ENABLES,
+            0x67,          0x45, // sensor ID 0x4567
+            0x02,                // count
+            0x01,          0x00, // field 0
+            0x02,          0x01, // field 1
+            0x00,                // extra byte
+        };
+
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    auto msg = reinterpret_cast<const pldm_msg*>(req.data());
+
+    // Good decode
+    rc = decode_set_state_sensor_enables_req(msg, 7, &decoded);
+    EXPECT_EQ(rc, 0);
+    EXPECT_EQ(decoded.sensor_id, 0x4567);
+    EXPECT_EQ(decoded.field_count, 2);
+    EXPECT_EQ(decoded.fields[0].op_state, PLDM_SET_SENSOR_DISABLED);
+    EXPECT_EQ(decoded.fields[0].event_enable, PLDM_NO_EVENT_GENERATION);
+    EXPECT_EQ(decoded.fields[1].op_state, PLDM_SET_SENSOR_UNAVAILABLE);
+    EXPECT_EQ(decoded.fields[1].event_enable, PLDM_EVENTS_DISABLED);
+
+    // Short message
+    rc = decode_set_state_sensor_enables_req(msg, 6, &decoded);
+    EXPECT_EQ(rc, -EOVERFLOW);
+
+    // Overlength message
+    rc = decode_set_state_sensor_enables_req(msg, 8, &decoded);
+    EXPECT_EQ(rc, -EBADMSG);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
+TEST(SetStateSensorEnables, testDecodeInvalidOpRequest)
+{
+    int rc;
+    struct pldm_set_state_sensor_enables_req decoded;
+
+    const std::array<uint8_t, hdrSize + 7> req
+        // PLDM header
+        {
+            PLDM_PLATFORM, 0x80, PLDM_SET_STATE_SENSOR_ENABLES,
+            0x67,          0x45, // sensor ID 0x4567
+            0x02,                // count
+            0x01,          0x00, // field 0
+            0x99,          0x01, // field 1 invalid op
+        };
+
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    auto msg = reinterpret_cast<const pldm_msg*>(req.data());
+
+    rc = decode_set_state_sensor_enables_req(msg, 7, &decoded);
+    EXPECT_EQ(rc, -EPROTO);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
+TEST(SetStateSensorEnables, testDecodeInvalidEventRequest)
+{
+    int rc;
+    struct pldm_set_state_sensor_enables_req decoded;
+
+    const std::array<uint8_t, hdrSize + 7> req
+        // PLDM header
+        {
+            PLDM_PLATFORM, 0x80, PLDM_SET_STATE_SENSOR_ENABLES,
+            0x67,          0x45, // sensor ID 0x4567
+            0x02,                // count
+            0x01,          0x00, // field 0
+            0x00,          0x77, // field 1 invalid event
+        };
+
+    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
+    auto msg = reinterpret_cast<const pldm_msg*>(req.data());
+
+    rc = decode_set_state_sensor_enables_req(msg, 7, &decoded);
+    EXPECT_EQ(rc, -EPROTO);
+}
+#endif // LIBPLDM_API_TESTING
+
+#ifdef LIBPLDM_API_TESTING
 TEST(GetEventReceiver, testGoodEncodeRequest)
 {
     std::array<uint8_t, hdrSize> requestMsg{};