pdr: Add decode_numeric_effecter_pdr_data()

Add `decode_numeric_effecter_pdr_data` API to decode the numeric
effecter PDR data in DSP0248_1.2.2 table 87. The API will be used to
retrieve the data fields of numeric effecter from the PDRs in `pldmd`.

Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Change-Id: I323a1288cb0262bd39f4f28701ddc7dbb70c33c8
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b05b8b6..f417653 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,7 @@
 11. state_set: Add CONNECTED and DISCONNECTED enum for Link State set
 12. entity: Add enum for Network Interface Connectors and Network Ports
     Connection Types
+13. pdr: Add decode_numeric_effecter_pdr_data()
 
 ### Changed
 
diff --git a/include/libpldm/platform.h b/include/libpldm/platform.h
index a2c001c..324af66 100644
--- a/include/libpldm/platform.h
+++ b/include/libpldm/platform.h
@@ -82,6 +82,15 @@
 	 PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_SENSOR_DATA_SIZE_MIN_LENGTH +      \
 	 PLDM_PDR_NUMERIC_SENSOR_PDR_VARIED_RANGE_FIELD_MIN_LENGTH)
 
+/* Minimum length of numeric effecter PDR */
+#define PLDM_PDR_NUMERIC_EFFECTER_PDR_FIXED_LENGTH			   56
+#define PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_EFFECTER_DATA_SIZE_MIN_LENGTH 2
+#define PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_RANGE_FIELD_MIN_LENGTH	   5
+#define PLDM_PDR_NUMERIC_EFFECTER_PDR_MIN_LENGTH                               \
+	(PLDM_PDR_NUMERIC_EFFECTER_PDR_FIXED_LENGTH +                          \
+	 PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_EFFECTER_DATA_SIZE_MIN_LENGTH +  \
+	 PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_RANGE_FIELD_MIN_LENGTH)
+
 #define PLDM_INVALID_EFFECTER_ID 0xffff
 #define PLDM_TID_RESERVED	 0xff
 
@@ -2192,6 +2201,18 @@
 int encode_set_event_receiver_resp(uint8_t instance_id, uint8_t completion_code,
 				   struct pldm_msg *msg);
 
+/** @brief Decode Numeric effecter Pdr data
+ *
+ *  @param[in] pdr_data - PDR data of the numeric effecter in DSP0248_1.2.2
+ *         table 87. This must be a pointer to the PDR data in the GetPDR
+ *         message body
+ *  @param[in] pdr_data_length - Length of pdr data
+ *  @param[out] pdr_value - the numeric effecter PDR data struct
+ */
+int decode_numeric_effecter_pdr_data(
+	const void *pdr_data, size_t pdr_data_length,
+	struct pldm_numeric_effecter_value_pdr *pdr_value);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/msgbuf/platform.h b/src/msgbuf/platform.h
index 7ca36c9..c52a66d 100644
--- a/src/msgbuf/platform.h
+++ b/src/msgbuf/platform.h
@@ -143,6 +143,44 @@
 	return -PLDM_ERROR_INVALID_DATA;
 }
 
+#define pldm_msgbuf_extract_effecter_data(ctx, tag, dst)                       \
+	pldm_msgbuf_extract_typecheck(union_effecter_data_size,                \
+				      pldm__msgbuf_extract_range_field_format, \
+				      dst, ctx, tag, (void *)&(dst))
+__attribute__((always_inline)) static inline int
+pldm__msgbuf_extract_effecter_data(struct pldm_msgbuf *ctx,
+				   enum pldm_effecter_data_size tag, void *ed)
+{
+	switch (tag) {
+	case PLDM_EFFECTER_DATA_SIZE_UINT8:
+		return pldm__msgbuf_extract_uint8(
+			ctx, ((char *)ed) + offsetof(union_effecter_data_size,
+						     value_u8));
+	case PLDM_EFFECTER_DATA_SIZE_SINT8:
+		return pldm__msgbuf_extract_int8(
+			ctx, ((char *)ed) + offsetof(union_effecter_data_size,
+						     value_s8));
+	case PLDM_EFFECTER_DATA_SIZE_UINT16:
+		return pldm__msgbuf_extract_uint16(
+			ctx, ((char *)ed) + offsetof(union_effecter_data_size,
+						     value_u16));
+	case PLDM_EFFECTER_DATA_SIZE_SINT16:
+		return pldm__msgbuf_extract_int16(
+			ctx, ((char *)ed) + offsetof(union_effecter_data_size,
+						     value_s16));
+	case PLDM_EFFECTER_DATA_SIZE_UINT32:
+		return pldm__msgbuf_extract_uint32(
+			ctx, ((char *)ed) + offsetof(union_effecter_data_size,
+						     value_u32));
+	case PLDM_EFFECTER_DATA_SIZE_SINT32:
+		return pldm__msgbuf_extract_int32(
+			ctx, ((char *)ed) + offsetof(union_effecter_data_size,
+						     value_s32));
+	}
+
+	return -PLDM_ERROR_INVALID_DATA;
+}
+
 #ifdef __cplusplus
 #include <type_traits>
 
diff --git a/src/platform.c b/src/platform.c
index 6f7b940..75f94c5 100644
--- a/src/platform.c
+++ b/src/platform.c
@@ -2429,3 +2429,94 @@
 
 	return pldm_msgbuf_destroy_consumed(buf);
 }
+
+LIBPLDM_ABI_TESTING
+int decode_numeric_effecter_pdr_data(
+	const void *pdr_data, size_t pdr_data_length,
+	struct pldm_numeric_effecter_value_pdr *pdr_value)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	struct pldm_value_pdr_hdr hdr;
+	int rc;
+
+	rc = pldm_msgbuf_init(buf, PLDM_PDR_NUMERIC_EFFECTER_PDR_MIN_LENGTH,
+			      pdr_data, pdr_data_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract_value_pdr_hdr(buf, &hdr);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_platform_pdr_hdr_validate(
+		&hdr, PLDM_PDR_NUMERIC_EFFECTER_PDR_MIN_LENGTH,
+		pdr_data_length);
+	if (rc) {
+		return rc;
+	}
+
+	memcpy(&pdr_value->hdr, &hdr, sizeof(hdr));
+
+	pldm_msgbuf_extract(buf, pdr_value->terminus_handle);
+	pldm_msgbuf_extract(buf, pdr_value->effecter_id);
+	pldm_msgbuf_extract(buf, pdr_value->entity_type);
+	pldm_msgbuf_extract(buf, pdr_value->entity_instance);
+	pldm_msgbuf_extract(buf, pdr_value->container_id);
+	pldm_msgbuf_extract(buf, pdr_value->effecter_semantic_id);
+	pldm_msgbuf_extract(buf, pdr_value->effecter_init);
+	pldm_msgbuf_extract(buf, pdr_value->effecter_auxiliary_names);
+	pldm_msgbuf_extract(buf, pdr_value->base_unit);
+	pldm_msgbuf_extract(buf, pdr_value->unit_modifier);
+	pldm_msgbuf_extract(buf, pdr_value->rate_unit);
+	pldm_msgbuf_extract(buf, pdr_value->base_oem_unit_handle);
+	pldm_msgbuf_extract(buf, pdr_value->aux_unit);
+	pldm_msgbuf_extract(buf, pdr_value->aux_unit_modifier);
+	pldm_msgbuf_extract(buf, pdr_value->aux_rate_unit);
+	pldm_msgbuf_extract(buf, pdr_value->aux_oem_unit_handle);
+	pldm_msgbuf_extract(buf, pdr_value->is_linear);
+
+	rc = pldm_msgbuf_extract(buf, pdr_value->effecter_data_size);
+	if (rc) {
+		return rc;
+	}
+	if (pdr_value->effecter_data_size > PLDM_SENSOR_DATA_SIZE_MAX) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract(buf, pdr_value->resolution);
+	pldm_msgbuf_extract(buf, pdr_value->offset);
+	pldm_msgbuf_extract(buf, pdr_value->accuracy);
+	pldm_msgbuf_extract(buf, pdr_value->plus_tolerance);
+	pldm_msgbuf_extract(buf, pdr_value->minus_tolerance);
+	pldm_msgbuf_extract(buf, pdr_value->state_transition_interval);
+	pldm_msgbuf_extract(buf, pdr_value->transition_interval);
+	pldm_msgbuf_extract_effecter_data(buf, pdr_value->effecter_data_size,
+					  pdr_value->max_settable);
+	pldm_msgbuf_extract_effecter_data(buf, pdr_value->effecter_data_size,
+					  pdr_value->min_settable);
+
+	rc = pldm_msgbuf_extract(buf, pdr_value->range_field_format);
+	if (rc) {
+		return rc;
+	}
+	if (pdr_value->range_field_format > PLDM_RANGE_FIELD_FORMAT_MAX) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract(buf, pdr_value->range_field_support.byte);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->nominal_value);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->normal_max);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->normal_min);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->rated_max);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->rated_min);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
diff --git a/tests/libpldm_platform_test.cpp b/tests/libpldm_platform_test.cpp
index f3ec7e7..be08201 100644
--- a/tests/libpldm_platform_test.cpp
+++ b/tests/libpldm_platform_test.cpp
@@ -4137,3 +4137,721 @@
         decode_numeric_sensor_pdr_data(pdr1.data(), pdr1.size(), &decodedPdr);
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
 }
+
+TEST(decodeNumericEffecterPdrData, Uint8Test)
+{
+    std::vector<uint8_t> pdr1{
+        0x1,
+        0x0,
+        0x0,
+        0x0,                       // record handle
+        0x1,                       // PDRHeaderVersion
+        PLDM_NUMERIC_EFFECTER_PDR, // PDRType
+        0x0,
+        0x0, // recordChangeNumber
+        PLDM_PDR_NUMERIC_EFFECTER_PDR_MIN_LENGTH,
+        0, // dataLength
+        0,
+        0, // PLDMTerminusHandle
+        0x1,
+        0x0, // effecterID=1
+        PLDM_ENTITY_POWER_SUPPLY,
+        0, // entityType=Power Supply(120)
+        1,
+        0, // entityInstanceNumber
+        1,
+        0, // containerID=1
+        0x2,
+        0x0,                           // effecter_semantic_id=2
+        PLDM_NO_INIT,                  // effecterInit
+        false,                         // effecterAuxiliaryNames
+        PLDM_SENSOR_UNIT_DEGRESS_C,    // baseUint(2)=degrees C
+        0,                             // unitModifier
+        0,                             // rateUnit
+        0,                             // baseOEMUnitHandle
+        0,                             // auxUnit
+        0,                             // auxUnitModifier
+        4,                             // auxRateUnit
+        0,                             // auxOEMUnitHandle
+        true,                          // isLinear
+        PLDM_EFFECTER_DATA_SIZE_UINT8, // effecterDataSize
+        0,
+        0,
+        0xc0,
+        0x3f, // resolution=1.5
+        0,
+        0,
+        0x80,
+        0x3f, // offset=1.0
+        0,
+        0, // accuracy
+        0, // plusTolerance
+        0, // minusTolerance
+        0,
+        0,
+        0x80,
+        0x3f, // stateTransistionInterval=1.0
+        0,
+        0,
+        0x80,
+        0x3f,                          // transition_interval=1.0
+        255,                           // maxSetdable
+        0,                             // minSetable
+        PLDM_RANGE_FIELD_FORMAT_UINT8, // rangeFieldFormat
+        0x1f,                          // rangeFieldsupport
+        50,                            // nominalValue = 50
+        60,                            // normalMax = 60
+        40,                            // normalMin = 40
+        90,                            // rated_max = 90
+        10                             // rated_min = 10
+    };
+
+    struct pldm_numeric_effecter_value_pdr decodedPdr;
+    auto rc =
+        decode_numeric_effecter_pdr_data(pdr1.data(), pdr1.size(), &decodedPdr);
+    EXPECT_EQ(PLDM_SUCCESS, rc);
+    EXPECT_EQ(1, decodedPdr.hdr.record_handle);
+    EXPECT_EQ(1, decodedPdr.hdr.version);
+    EXPECT_EQ(PLDM_NUMERIC_EFFECTER_PDR, decodedPdr.hdr.type);
+    EXPECT_EQ(0, decodedPdr.hdr.record_change_num);
+    EXPECT_EQ(PLDM_PDR_NUMERIC_EFFECTER_PDR_MIN_LENGTH, decodedPdr.hdr.length);
+    EXPECT_EQ(1, decodedPdr.effecter_id);
+    EXPECT_EQ(PLDM_ENTITY_POWER_SUPPLY, decodedPdr.entity_type);
+    EXPECT_EQ(1, decodedPdr.entity_instance);
+    EXPECT_EQ(1, decodedPdr.container_id);
+    EXPECT_EQ(2, decodedPdr.effecter_semantic_id);
+    EXPECT_EQ(PLDM_NO_INIT, decodedPdr.effecter_init);
+    EXPECT_EQ(false, decodedPdr.effecter_auxiliary_names);
+    EXPECT_EQ(PLDM_SENSOR_UNIT_DEGRESS_C, decodedPdr.base_unit);
+    EXPECT_EQ(0, decodedPdr.unit_modifier);
+    EXPECT_EQ(0, decodedPdr.rate_unit);
+    EXPECT_EQ(0, decodedPdr.base_oem_unit_handle);
+    EXPECT_EQ(0, decodedPdr.aux_unit);
+    EXPECT_EQ(0, decodedPdr.aux_unit_modifier);
+    EXPECT_EQ(4, decodedPdr.aux_rate_unit);
+    EXPECT_EQ(0, decodedPdr.aux_oem_unit_handle);
+    EXPECT_EQ(true, decodedPdr.is_linear);
+    EXPECT_EQ(PLDM_EFFECTER_DATA_SIZE_UINT8, decodedPdr.effecter_data_size);
+    EXPECT_FLOAT_EQ(1.5f, decodedPdr.resolution);
+    EXPECT_FLOAT_EQ(1.0f, decodedPdr.offset);
+    EXPECT_EQ(0, decodedPdr.accuracy);
+    EXPECT_EQ(0, decodedPdr.plus_tolerance);
+    EXPECT_EQ(0, decodedPdr.minus_tolerance);
+    EXPECT_FLOAT_EQ(1.0f, decodedPdr.state_transition_interval);
+    EXPECT_FLOAT_EQ(1.0f, decodedPdr.transition_interval);
+    EXPECT_EQ(255, decodedPdr.max_settable.value_u8);
+    EXPECT_EQ(0, decodedPdr.min_settable.value_u8);
+    EXPECT_EQ(PLDM_RANGE_FIELD_FORMAT_UINT8, decodedPdr.range_field_format);
+    EXPECT_EQ(0x1f, decodedPdr.range_field_support.byte);
+    EXPECT_EQ(50, decodedPdr.nominal_value.value_u8);
+    EXPECT_EQ(60, decodedPdr.normal_max.value_u8);
+    EXPECT_EQ(40, decodedPdr.normal_min.value_u8);
+    EXPECT_EQ(90, decodedPdr.rated_max.value_u8);
+    EXPECT_EQ(10, decodedPdr.rated_min.value_u8);
+}
+
+TEST(decodeNumericEffecterPdrData, Sint8Test)
+{
+    std::vector<uint8_t> pdr1{
+        0x1,
+        0x0,
+        0x0,
+        0x0,                       // record handle
+        0x1,                       // PDRHeaderVersion
+        PLDM_NUMERIC_EFFECTER_PDR, // PDRType
+        0x0,
+        0x0, // recordChangeNumber
+        PLDM_PDR_NUMERIC_EFFECTER_PDR_FIXED_LENGTH +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_EFFECTER_DATA_SIZE_MIN_LENGTH +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_RANGE_FIELD_MIN_LENGTH,
+        0, // dataLength
+        0,
+        0, // PLDMTerminusHandle
+        0x1,
+        0x0, // effecterID=1
+        PLDM_ENTITY_POWER_SUPPLY,
+        0, // entityType=Power Supply(120)
+        1,
+        0, // entityInstanceNumber
+        0x1,
+        0x0, // containerID=1
+        0x2,
+        0x0,                           // effecter_semantic_id=2
+        PLDM_NO_INIT,                  // effecterInit
+        false,                         // effecterAuxiliaryNames
+        PLDM_SENSOR_UNIT_DEGRESS_C,    // baseUint(2)=degrees C
+        0,                             // unitModifier
+        0,                             // rateUnit
+        0,                             // baseOEMUnitHandle
+        0,                             // auxUnit
+        0,                             // auxUnitModifier
+        0,                             // auxRateUnit
+        0,                             // auxOEMUnitHandle
+        true,                          // isLinear
+        PLDM_RANGE_FIELD_FORMAT_SINT8, // effecterDataSize
+        0,
+        0,
+        0,
+        0, // resolution
+        0,
+        0,
+        0,
+        0, // offset
+        0,
+        0, // accuracy
+        0, // plusTolerance
+        0, // minusTolerance
+        0,
+        0,
+        0x80,
+        0x3f, // stateTransistionInterval=1.0
+        0,
+        0,
+        0x80,
+        0x3f,                          // transition_interval=1.0
+        0x64,                          // maxSetdable = 100
+        0x9c,                          // minSetable = -100
+        PLDM_RANGE_FIELD_FORMAT_SINT8, // rangeFieldFormat
+        0x1f,                          // rangeFieldsupport
+        0,                             // nominalValue = 0
+        5,                             // normalMax = 5
+        0xfb,                          // normalMin = -5
+        30,                            // rated_max = 30
+        0xe2                           // rated_min = -30
+    };
+
+    struct pldm_numeric_effecter_value_pdr decodedPdr;
+    auto rc =
+        decode_numeric_effecter_pdr_data(pdr1.data(), pdr1.size(), &decodedPdr);
+    EXPECT_EQ(PLDM_SUCCESS, rc);
+
+    EXPECT_EQ(PLDM_EFFECTER_DATA_SIZE_SINT8, decodedPdr.effecter_data_size);
+    EXPECT_EQ(100, decodedPdr.max_settable.value_s8);
+    EXPECT_EQ(-100, decodedPdr.min_settable.value_s8);
+    EXPECT_EQ(PLDM_RANGE_FIELD_FORMAT_SINT8, decodedPdr.range_field_format);
+    EXPECT_EQ(0x1f, decodedPdr.range_field_support.byte);
+    EXPECT_EQ(0, decodedPdr.nominal_value.value_s8);
+    EXPECT_EQ(5, decodedPdr.normal_max.value_s8);
+    EXPECT_EQ(-5, decodedPdr.normal_min.value_s8);
+    EXPECT_EQ(30, decodedPdr.rated_max.value_s8);
+    EXPECT_EQ(-30, decodedPdr.rated_min.value_s8);
+}
+
+TEST(decodeNumericEffecterPdrData, Uint16Test)
+{
+    std::vector<uint8_t> pdr1{
+        0x1,
+        0x0,
+        0x0,
+        0x0,                       // record handle
+        0x1,                       // PDRHeaderVersion
+        PLDM_NUMERIC_EFFECTER_PDR, // PDRType
+        0x0,
+        0x0, // recordChangeNumber
+        PLDM_PDR_NUMERIC_EFFECTER_PDR_FIXED_LENGTH +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_EFFECTER_DATA_SIZE_MIN_LENGTH *
+                2 +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_RANGE_FIELD_MIN_LENGTH * 2,
+        0, // dataLength
+        0,
+        0, // PLDMTerminusHandle
+        0x1,
+        0x0, // effecterID=1
+        PLDM_ENTITY_POWER_SUPPLY,
+        0, // entityType=Power Supply(120)
+        1,
+        0, // entityInstanceNumber
+        0x1,
+        0x0, // containerID=1
+        0x2,
+        0x0,                            // effecter_semantic_id=2
+        PLDM_NO_INIT,                   // effecterInit
+        false,                          // effecterAuxiliaryNames
+        PLDM_SENSOR_UNIT_DEGRESS_C,     // baseUint(2)=degrees C
+        0,                              // unitModifier
+        0,                              // rateUnit
+        0,                              // baseOEMUnitHandle
+        0,                              // auxUnit
+        0,                              // auxUnitModifier
+        0,                              // auxRateUnit
+        0,                              // auxOEMUnitHandle
+        true,                           // isLinear
+        PLDM_EFFECTER_DATA_SIZE_UINT16, // effecterDataSize
+        0,
+        0,
+        0,
+        0, // resolution
+        0,
+        0,
+        0,
+        0, // offset
+        0,
+        0, // accuracy
+        0, // plusTolerance
+        0, // minusTolerance
+        0,
+        0,
+        0x80,
+        0x3f, // stateTransistionInterval=1.0
+        0,
+        0,
+        0x80,
+        0x3f, // transition_interval=1.0
+        0,
+        0x10, // maxSetdable = 4096
+        0,
+        0,                              // minSetable = 0
+        PLDM_RANGE_FIELD_FORMAT_UINT16, // rangeFieldFormat
+        0x1f,                           // rangeFieldsupport
+        0x88,
+        0x13, // nominalValue = 5,000
+        0x70,
+        0x17, // normalMax = 6,000
+        0xa0,
+        0x0f, // normalMin = 4,000
+        0x28,
+        0x23, // rated_max = 9,000
+        0xe8,
+        0x03 // rated_min = 1,000
+    };
+
+    struct pldm_numeric_effecter_value_pdr decodedPdr;
+    auto rc =
+        decode_numeric_effecter_pdr_data(pdr1.data(), pdr1.size(), &decodedPdr);
+    EXPECT_EQ(PLDM_SUCCESS, rc);
+
+    EXPECT_EQ(PLDM_EFFECTER_DATA_SIZE_UINT16, decodedPdr.effecter_data_size);
+    EXPECT_EQ(4096, decodedPdr.max_settable.value_u16);
+    EXPECT_EQ(0, decodedPdr.min_settable.value_u16);
+    EXPECT_EQ(PLDM_RANGE_FIELD_FORMAT_UINT16, decodedPdr.range_field_format);
+    EXPECT_EQ(0x1f, decodedPdr.range_field_support.byte);
+    EXPECT_EQ(5000, decodedPdr.nominal_value.value_u16);
+    EXPECT_EQ(6000, decodedPdr.normal_max.value_u16);
+    EXPECT_EQ(4000, decodedPdr.normal_min.value_u16);
+    EXPECT_EQ(9000, decodedPdr.rated_max.value_u16);
+    EXPECT_EQ(1000, decodedPdr.rated_min.value_u16);
+}
+
+TEST(decodeNumericEffecterPdrData, Sint16Test)
+{
+    std::vector<uint8_t> pdr1{
+        0x1,
+        0x0,
+        0x0,
+        0x0,                       // record handle
+        0x1,                       // PDRHeaderVersion
+        PLDM_NUMERIC_EFFECTER_PDR, // PDRType
+        0x0,
+        0x0, // recordChangeNumber
+        PLDM_PDR_NUMERIC_EFFECTER_PDR_FIXED_LENGTH +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_EFFECTER_DATA_SIZE_MIN_LENGTH *
+                2 +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_RANGE_FIELD_MIN_LENGTH * 2,
+        0, // dataLength
+        0,
+        0, // PLDMTerminusHandle
+        0x1,
+        0x0, // effecterID=1
+        PLDM_ENTITY_POWER_SUPPLY,
+        0, // entityType=Power Supply(120)
+        1,
+        0, // entityInstanceNumber
+        0x1,
+        0x0, // containerID=1
+        0x2,
+        0x0,                            // effecter_semantic_id=2
+        PLDM_NO_INIT,                   // effecterInit
+        false,                          // effecterAuxiliaryNames
+        PLDM_SENSOR_UNIT_DEGRESS_C,     // baseUint(2)=degrees C
+        0,                              // unitModifier
+        0,                              // rateUnit
+        0,                              // baseOEMUnitHandle
+        0,                              // auxUnit
+        0,                              // auxUnitModifier
+        0,                              // auxRateUnit
+        0,                              // auxOEMUnitHandle
+        true,                           // isLinear
+        PLDM_EFFECTER_DATA_SIZE_SINT16, // effecterDataSize
+        0,
+        0,
+        0,
+        0, // resolution
+        0,
+        0,
+        0,
+        0, // offset
+        0,
+        0, // accuracy
+        0, // plusTolerance
+        0, // minusTolerance
+        0,
+        0,
+        0x80,
+        0x3f, // stateTransistionInterval=1.0
+        0,
+        0,
+        0x80,
+        0x3f, // transition_interval=1.0
+        0xe8,
+        0x03, // maxSetdable = 1000
+        0x18,
+        0xfc,                           // minSetable = -1000
+        PLDM_RANGE_FIELD_FORMAT_SINT16, // rangeFieldFormat
+        0x1f,                           // rangeFieldsupport
+        0,
+        0, // nominalValue = 0
+        0xf4,
+        0x01, // normalMax = 500
+        0x0c,
+        0xfe, // normalMin = -500
+        0xb8,
+        0x0b, // rated_max = 3,000
+        0x48,
+        0xf4 // rated_min = -3,000
+    };
+
+    struct pldm_numeric_effecter_value_pdr decodedPdr;
+    auto rc =
+        decode_numeric_effecter_pdr_data(pdr1.data(), pdr1.size(), &decodedPdr);
+    EXPECT_EQ(PLDM_SUCCESS, rc);
+
+    EXPECT_EQ(PLDM_EFFECTER_DATA_SIZE_SINT16, decodedPdr.effecter_data_size);
+    EXPECT_EQ(1000, decodedPdr.max_settable.value_s16);
+    EXPECT_EQ(-1000, decodedPdr.min_settable.value_s16);
+    EXPECT_EQ(PLDM_RANGE_FIELD_FORMAT_SINT16, decodedPdr.range_field_format);
+    EXPECT_EQ(0x1f, decodedPdr.range_field_support.byte);
+    EXPECT_EQ(0, decodedPdr.nominal_value.value_s16);
+    EXPECT_EQ(500, decodedPdr.normal_max.value_s16);
+    EXPECT_EQ(-500, decodedPdr.normal_min.value_s16);
+    EXPECT_EQ(3000, decodedPdr.rated_max.value_s16);
+    EXPECT_EQ(-3000, decodedPdr.rated_min.value_s16);
+}
+
+TEST(decodeNumericEffecterPdrData, Uint32Test)
+{
+    std::vector<uint8_t> pdr1{
+        0x1,
+        0x0,
+        0x0,
+        0x0,                       // record handle
+        0x1,                       // PDRHeaderVersion
+        PLDM_NUMERIC_EFFECTER_PDR, // PDRType
+        0x0,
+        0x0, // recordChangeNumber
+        PLDM_PDR_NUMERIC_EFFECTER_PDR_FIXED_LENGTH +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_EFFECTER_DATA_SIZE_MIN_LENGTH *
+                4 +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_RANGE_FIELD_MIN_LENGTH * 4,
+        0, // dataLength
+        0,
+        0, // PLDMTerminusHandle
+        0x1,
+        0x0, // effecterID=1
+        PLDM_ENTITY_POWER_SUPPLY,
+        0, // entityType=Power Supply(120)
+        1,
+        0, // entityInstanceNumber
+        0x1,
+        0x0, // containerID=1
+        0x2,
+        0x0,                            // effecter_semantic_id=2
+        PLDM_NO_INIT,                   // effecterInit
+        false,                          // effecterAuxiliaryNames
+        PLDM_SENSOR_UNIT_DEGRESS_C,     // baseUint(2)=degrees C
+        0,                              // unitModifier
+        0,                              // rateUnit
+        0,                              // baseOEMUnitHandle
+        0,                              // auxUnit
+        0,                              // auxUnitModifier
+        0,                              // auxRateUnit
+        0,                              // auxOEMUnitHandle
+        true,                           // isLinear
+        PLDM_EFFECTER_DATA_SIZE_UINT32, // effecterDataSize
+        0,
+        0,
+        0,
+        0, // resolution
+        0,
+        0,
+        0,
+        0, // offset
+        0,
+        0, // accuracy
+        0, // plusTolerance
+        0, // minusTolerance
+        0,
+        0,
+        0x80,
+        0x3f, // stateTransistionInterval=1.0
+        0,
+        0,
+        0x80,
+        0x3f, // transition_interval=1.0
+        0,
+        0x10,
+        0,
+        0, // maxSetdable = 4096
+        0,
+        0,
+        0,
+        0,                              // minSetable = 0
+        PLDM_RANGE_FIELD_FORMAT_UINT32, // rangeFieldFormat
+        0x1f,                           // rangeFieldsupport
+        0x40,
+        0x4b,
+        0x4c,
+        0x00, // nominalValue = 5,000,000
+        0x80,
+        0x8d,
+        0x5b,
+        0x00, // normalMax = 6,000,000
+        0x00,
+        0x09,
+        0x3d,
+        0x00, // normalMin = 4,000,000
+        0x40,
+        0x54,
+        0x89,
+        0x00, // rated_max = 9,000,000
+        0x40,
+        0x42,
+        0x0f,
+        0x00 // rated_min = 1,000,000
+    };
+
+    struct pldm_numeric_effecter_value_pdr decodedPdr;
+    auto rc =
+        decode_numeric_effecter_pdr_data(pdr1.data(), pdr1.size(), &decodedPdr);
+    EXPECT_EQ(PLDM_SUCCESS, rc);
+
+    EXPECT_EQ(PLDM_EFFECTER_DATA_SIZE_UINT32, decodedPdr.effecter_data_size);
+    EXPECT_EQ(4096, decodedPdr.max_settable.value_u32);
+    EXPECT_EQ(0, decodedPdr.min_settable.value_u32);
+    EXPECT_EQ(PLDM_RANGE_FIELD_FORMAT_UINT32, decodedPdr.range_field_format);
+    EXPECT_EQ(0x1f, decodedPdr.range_field_support.byte);
+    EXPECT_EQ(5000000, decodedPdr.nominal_value.value_u32);
+    EXPECT_EQ(6000000, decodedPdr.normal_max.value_u32);
+    EXPECT_EQ(4000000, decodedPdr.normal_min.value_u32);
+    EXPECT_EQ(9000000, decodedPdr.rated_max.value_u32);
+    EXPECT_EQ(1000000, decodedPdr.rated_min.value_u32);
+}
+
+TEST(decodeNumericEffecterPdrData, Sint32Test)
+{
+    std::vector<uint8_t> pdr1{
+        0x1,
+        0x0,
+        0x0,
+        0x0,                       // record handle
+        0x1,                       // PDRHeaderVersion
+        PLDM_NUMERIC_EFFECTER_PDR, // PDRType
+        0x0,
+        0x0, // recordChangeNumber
+        PLDM_PDR_NUMERIC_EFFECTER_PDR_FIXED_LENGTH +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_EFFECTER_DATA_SIZE_MIN_LENGTH *
+                4 +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_RANGE_FIELD_MIN_LENGTH * 4,
+        0, // dataLength
+        0,
+        0, // PLDMTerminusHandle
+        0x1,
+        0x0, // effecterID=1
+        PLDM_ENTITY_POWER_SUPPLY,
+        0, // entityType=Power Supply(120)
+        1,
+        0, // entityInstanceNumber
+        0x1,
+        0x0, // containerID=1
+        0x2,
+        0x0,                            // effecter_semantic_id=2
+        PLDM_NO_INIT,                   // effecterInit
+        false,                          // effecterAuxiliaryNames
+        PLDM_SENSOR_UNIT_DEGRESS_C,     // baseUint(2)=degrees C
+        0,                              // unitModifier
+        0,                              // rateUnit
+        0,                              // baseOEMUnitHandle
+        0,                              // auxUnit
+        0,                              // auxUnitModifier
+        0,                              // auxRateUnit
+        0,                              // auxOEMUnitHandle
+        true,                           // isLinear
+        PLDM_EFFECTER_DATA_SIZE_SINT32, // effecterDataSize
+        0,
+        0,
+        0,
+        0, // resolution
+        0,
+        0,
+        0,
+        0, // offset
+        0,
+        0, // accuracy
+        0, // plusTolerance
+        0, // minusTolerance
+        0,
+        0,
+        0x80,
+        0x3f, // stateTransistionInterval=1.0
+        0,
+        0,
+        0x80,
+        0x3f, // transition_interval=1.0
+        0xa0,
+        0x86,
+        0x01,
+        0x00, // maxSetdable = 100000
+        0x60,
+        0x79,
+        0xfe,
+        0xff,                           // minSetable = -10000
+        PLDM_RANGE_FIELD_FORMAT_SINT32, // rangeFieldFormat
+        0x1f,                           // rangeFieldsupport
+        0,
+        0,
+        0,
+        0, // nominalValue = 0
+        0x20,
+        0xa1,
+        0x07,
+        0x00, // normalMax = 500,000
+        0xe0,
+        0x5e,
+        0xf8,
+        0xff, // normalMin = -500,000
+        0xc0,
+        0xc6,
+        0x2d,
+        0x00, // rated_max = 3,000,000
+        0x40,
+        0x39,
+        0xd2,
+        0xff // rated_min = -3,000,000
+    };
+
+    struct pldm_numeric_effecter_value_pdr decodedPdr;
+    auto rc =
+        decode_numeric_effecter_pdr_data(pdr1.data(), pdr1.size(), &decodedPdr);
+    EXPECT_EQ(PLDM_SUCCESS, rc);
+    EXPECT_EQ(PLDM_EFFECTER_DATA_SIZE_SINT32, decodedPdr.effecter_data_size);
+    EXPECT_EQ(100000, decodedPdr.max_settable.value_s32);
+    EXPECT_EQ(-100000, decodedPdr.min_settable.value_s32);
+    EXPECT_EQ(PLDM_RANGE_FIELD_FORMAT_SINT32, decodedPdr.range_field_format);
+    EXPECT_EQ(0x1f, decodedPdr.range_field_support.byte);
+    EXPECT_EQ(0, decodedPdr.nominal_value.value_s32);
+    EXPECT_EQ(500000, decodedPdr.normal_max.value_s32);
+    EXPECT_EQ(-500000, decodedPdr.normal_min.value_s32);
+    EXPECT_EQ(3000000, decodedPdr.rated_max.value_s32);
+    EXPECT_EQ(-3000000, decodedPdr.rated_min.value_s32);
+}
+
+TEST(decodeNumericEffecterPdrData, Real32Test)
+{
+    std::vector<uint8_t> pdr1{
+        0x1,
+        0x0,
+        0x0,
+        0x0,                       // record handle
+        0x1,                       // PDRHeaderVersion
+        PLDM_NUMERIC_EFFECTER_PDR, // PDRType
+        0x0,
+        0x0, // recordChangeNumber
+        PLDM_PDR_NUMERIC_EFFECTER_PDR_FIXED_LENGTH +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_EFFECTER_DATA_SIZE_MIN_LENGTH *
+                4 +
+            PLDM_PDR_NUMERIC_EFFECTER_PDR_VARIED_RANGE_FIELD_MIN_LENGTH * 4,
+        0, // dataLength
+        0,
+
+        0, // PLDMTerminusHandle
+        0x1,
+        0x0, // effecterID=1
+        PLDM_ENTITY_POWER_SUPPLY,
+        0, // entityType=Power Supply(120)
+        1,
+        0, // entityInstanceNumber
+        0x1,
+        0x0, // containerID=1
+        0x2,
+        0x0,                            // effecter_semantic_id=2
+        PLDM_NO_INIT,                   // effecterInit
+        false,                          // effecterAuxiliaryNames
+        PLDM_SENSOR_UNIT_DEGRESS_C,     // baseUint(2)=degrees C
+        0,                              // unitModifier
+        0,                              // rateUnit
+        0,                              // baseOEMUnitHandle
+        0,                              // auxUnit
+        0,                              // auxUnitModifier
+        0,                              // auxRateUnit
+        0,                              // auxOEMUnitHandle
+        true,                           // isLinear
+        PLDM_EFFECTER_DATA_SIZE_SINT32, // effecterDataSize
+        0,
+        0,
+        0,
+        0, // resolution
+        0,
+        0,
+        0,
+        0, // offset
+        0,
+        0, // accuracy
+        0, // plusTolerance
+        0, // minusTolerance
+        0,
+        0,
+        0x80,
+        0x3f, // stateTransistionInterval=1.0
+        0,
+        0,
+        0x80,
+        0x3f, // transition_interval=1.0
+        0xa0,
+        0x86,
+        0x01,
+        0x00, // maxSetdable = 100000
+        0x60,
+        0x79,
+        0xfe,
+        0xff,                           // minSetable = -10000
+        PLDM_RANGE_FIELD_FORMAT_REAL32, // rangeFieldFormat
+        0x1f,                           // rangeFieldsupport
+        0,
+        0,
+        0,
+        0, // nominalValue = 0.0
+        0x33,
+        0x33,
+        0x48,
+        0x42, // normalMax = 50.05
+        0x33,
+        0x33,
+        0x48,
+        0xc2, // normalMin = -50.05
+        0x62,
+        0x00,
+        0x96,
+        0x43, // rated_max = 300.003
+        0x62,
+        0x00,
+        0x96,
+        0xc3 // rated_min = -300.003
+    };
+
+    struct pldm_numeric_effecter_value_pdr decodedPdr;
+    auto rc =
+        decode_numeric_effecter_pdr_data(pdr1.data(), pdr1.size(), &decodedPdr);
+    EXPECT_EQ(PLDM_SUCCESS, rc);
+
+    EXPECT_EQ(PLDM_EFFECTER_DATA_SIZE_SINT32, decodedPdr.effecter_data_size);
+    EXPECT_FLOAT_EQ(1.0f, decodedPdr.state_transition_interval);
+    EXPECT_FLOAT_EQ(1.0f, decodedPdr.transition_interval);
+    EXPECT_EQ(100000, decodedPdr.max_settable.value_s32);
+    EXPECT_EQ(-100000, decodedPdr.min_settable.value_s32);
+    EXPECT_EQ(PLDM_RANGE_FIELD_FORMAT_REAL32, decodedPdr.range_field_format);
+    EXPECT_EQ(0x1f, decodedPdr.range_field_support.byte);
+    EXPECT_FLOAT_EQ(0, decodedPdr.nominal_value.value_f32);
+    EXPECT_FLOAT_EQ(50.05f, decodedPdr.normal_max.value_f32);
+    EXPECT_FLOAT_EQ(-50.05f, decodedPdr.normal_min.value_f32);
+    EXPECT_FLOAT_EQ(300.003f, decodedPdr.rated_max.value_f32);
+    EXPECT_FLOAT_EQ(-300.003f, decodedPdr.rated_min.value_f32);
+}