Set a temperature over QMP and read it back through the two-byte and
single-byte register paths, checking the fixed-point encoding and the
extended-range offset. A second case pins the saturation: a temperature
the standard range cannot express reads back clamped, without harming
the measurement itself.

Signed-off-by: Emmanuel Blot <[email protected]>
---
 tests/qtest/tmp421-test.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/tests/qtest/tmp421-test.c b/tests/qtest/tmp421-test.c
index 2307e5f603..390f17b6b2 100644
--- a/tests/qtest/tmp421-test.c
+++ b/tests/qtest/tmp421-test.c
@@ -18,9 +18,13 @@
  * shared with the model, so the test states the values it expects
  * independently of the implementation it is checking.
  */
+#define TMP421_TEMP_MSB0                0x00
 #define TMP421_CONFIG_REG_1             0x09
+#define    TMP421_CONFIG_RANGE            (1 << 2)
 #define TMP421_CONFIG_REG_2             0x0A
 #define TMP421_CONVERSION_RATE_REG      0x0B
+#define TMP421_TEMP_LSB0                0x10
+#define TMP421_RESET                    0xFC
 #define TMP421_MANUFACTURER_ID_REG      0xFE
 #define TMP421_DEVICE_ID_REG            0xFF
 #define TMP421_MANUFACTURER_ID          0x55
@@ -44,6 +48,36 @@ static const TMP421Variant tmp421_variant = { 
TMP421_TEST_ID, 0x21, 0x1c, 2 };
 static const TMP421Variant tmp422_variant = { TMP422_TEST_ID, 0x22, 0x3c, 3 };
 static const TMP421Variant tmp423_variant = { TMP423_TEST_ID, 0x23, 0x7c, 4 };
 
+static QDict *qmp_get_temperature(const char *id, unsigned channel)
+{
+    g_autofree char *prop = g_strdup_printf("temperature%u", channel);
+
+    return qmp("{ 'execute': 'qom-get', 'arguments': { 'path': %s, "
+               "'property': %s } }", id, prop);
+}
+
+static int get_temperature(const char *id, unsigned channel)
+{
+    QDict *response = qmp_get_temperature(id, channel);
+    int ret;
+
+    g_assert(qdict_haskey(response, "return"));
+    ret = qdict_get_int(response, "return");
+    qobject_unref(response);
+    return ret;
+}
+
+static void set_temperature(const char *id, unsigned channel, int value)
+{
+    g_autofree char *prop = g_strdup_printf("temperature%u", channel);
+    QDict *response;
+
+    response = qmp("{ 'execute': 'qom-set', 'arguments': { 'path': %s, "
+                   "'property': %s, 'value': %d } }", id, prop, value);
+    g_assert(qdict_haskey(response, "return"));
+    qobject_unref(response);
+}
+
 static void test_ids(void *obj, void *data, QGuestAllocator *alloc)
 {
     const TMP421Variant *var = data;
@@ -58,6 +92,70 @@ static void test_ids(void *obj, void *data, QGuestAllocator 
*alloc)
     g_assert_cmphex(i2c_get8(i2cdev, TMP421_CONVERSION_RATE_REG), ==, 0x07);
 }
 
+static void test_temperature(void *obj, void *data, QGuestAllocator *alloc)
+{
+    QI2CDevice *i2cdev = obj;
+
+    /* A whole degree lands on a whole register value, fraction cleared. */
+    set_temperature(TMP421_TEST_ID, 0, 25000);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP421_TEMP_MSB0), ==, 0x1900);
+
+    /* The standard range is two's complement below 0 C. */
+    set_temperature(TMP421_TEST_ID, 0, -25000);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP421_TEMP_MSB0), ==, 0xE700);
+
+    /* A temperature the register form represents exactly. */
+    set_temperature(TMP421_TEST_ID, 0, 25063);
+    g_assert_cmpint(get_temperature(TMP421_TEST_ID, 0), ==, 25063);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP421_TEMP_MSB0), ==, 0x1910);
+
+    /* A lone low-byte read returns the same conversion as the pair. */
+    g_assert_cmphex(i2c_get8(i2cdev, TMP421_TEMP_LSB0), ==, 0x10);
+
+    /* Extended range encodes the same measurement with a +64 C offset. */
+    i2c_set8(i2cdev, TMP421_CONFIG_REG_1, TMP421_CONFIG_RANGE);
+    set_temperature(TMP421_TEST_ID, 0, 25063);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP421_TEMP_MSB0), ==, 0x5910);
+
+    /* Leaving it, whether by a write or a reset, reports the same value */
+    i2c_set8(i2cdev, TMP421_CONFIG_REG_1, 0);
+    g_assert_cmpint(get_temperature(TMP421_TEST_ID, 0), ==, 25063);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP421_TEMP_MSB0), ==, 0x1910);
+
+    i2c_set8(i2cdev, TMP421_CONFIG_REG_1, TMP421_CONFIG_RANGE);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP421_TEMP_MSB0), ==, 0x5910);
+    i2c_set8(i2cdev, TMP421_RESET, 0);
+    g_assert_cmpint(get_temperature(TMP421_TEST_ID, 0), ==, 25063);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP421_TEMP_MSB0), ==, 0x1910);
+
+    /* The extended range is unsigned: it reaches past +64 C (Table 1). */
+    i2c_set8(i2cdev, TMP421_CONFIG_REG_1, TMP421_CONFIG_RANGE);
+    set_temperature(TMP421_TEST_ID, 0, 100063);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP421_TEMP_MSB0), ==, 0xA410);
+}
+
+/*
+ * A temperature the standard range cannot express saturates at +127 C (7Fh)
+ * instead of wrapping, and the extended range still reports it in full: the
+ * range picks an encoding, it does not alter the measurement.
+ */
+static void test_range_saturation(void *obj, void *data,
+                                  QGuestAllocator *alloc)
+{
+    QI2CDevice *i2cdev = obj;
+
+    i2c_set8(i2cdev, TMP421_CONFIG_REG_1, TMP421_CONFIG_RANGE);
+    set_temperature(TMP421_TEST_ID, 0, 149938);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP421_TEMP_MSB0), ==, 0xD5F0);
+
+    i2c_set8(i2cdev, TMP421_CONFIG_REG_1, 0);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP421_TEMP_MSB0), ==, 0x7FF0);
+    g_assert_cmpint(get_temperature(TMP421_TEST_ID, 0), ==, 149938);
+
+    i2c_set8(i2cdev, TMP421_CONFIG_REG_1, TMP421_CONFIG_RANGE);
+    g_assert_cmphex(i2c_get16(i2cdev, TMP421_TEMP_MSB0), ==, 0xD5F0);
+}
+
 static void tmp421_register_node(const TMP421Variant *var, const char *type,
                                  uint8_t addr)
 {
@@ -79,6 +177,10 @@ static void tmp421_register_nodes(void)
     tmp421_register_node(&tmp421_variant, "tmp421", 0x4c);
     tmp421_register_node(&tmp422_variant, "tmp422", 0x4d);
     tmp421_register_node(&tmp423_variant, "tmp423", 0x4e);
+
+    /* Temperature encoding is variant-independent; exercise it once. */
+    qos_add_test("temperature", "tmp421", test_temperature, NULL);
+    qos_add_test("range-saturation", "tmp421", test_range_saturation, NULL);
 }
 
 libqos_init(tmp421_register_nodes);

-- 
2.53.0-Meta


Reply via email to