From 08ed259fe65666ab3115fb93848ec0b6b5661f56 Mon Sep 17 00:00:00 2001 From: Stéphane Raimbault Date: Mon, 14 Apr 2014 21:35:44 +0200 Subject: [PATCH] Rewrite and extend functions to manipulate float values --- doc/modbus_get_float.txt | 2 ++ doc/modbus_get_float_dcba.txt | 8 +++----- doc/modbus_set_float.txt | 6 +++--- src/modbus-data.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- src/modbus.h | 7 +++++++ tests/unit-test-client.c | 64 +++++++++++++++++++++++++++++++--------------------------------- tests/unit-test.h.in | 14 +++++++++++--- 7 files changed, 143 insertions(+), 55 deletions(-) diff --git a/doc/modbus_get_float.txt b/doc/modbus_get_float.txt index 8f1149b..cb4bdbc 100644 --- a/doc/modbus_get_float.txt +++ b/doc/modbus_get_float.txt @@ -11,6 +11,8 @@ SYNOPSIS -------- *float modbus_get_float(const uint16_t *'src');* +Warning, this function is *deprecated* since libmodbus v3.2.0 and has been +replaced by *modbus_get_float_dcba()*. DESCRIPTION ----------- diff --git a/doc/modbus_get_float_dcba.txt b/doc/modbus_get_float_dcba.txt index d35083d..9e7a8c3 100644 --- a/doc/modbus_get_float_dcba.txt +++ b/doc/modbus_get_float_dcba.txt @@ -15,9 +15,9 @@ SYNOPSIS DESCRIPTION ----------- The *modbus_get_float_dcba()* function shall get a float from 4 bytes in -inversed Modbus format (DCBA order). The _src_ array must be pointer on two 16 -bits values, for example, if the first word is set to 0x9a22 and the second to -0x6544, the float value read will be 916.540649. +inversed Modbus format (DCBA order instead of ABCD). The _src_ array must be +pointer on two 16 bits values, for example, if the first word is set to 0x9a22 +and the second to 0x6544, the float value read will be 916.540649. RETURN VALUE @@ -28,8 +28,6 @@ The function shall return a float. SEE ALSO -------- linkmb:modbus_set_float_dcba[3] -linkmb:modbus_set_float[3] -linkmb:modbus_get_float[3] AUTHORS diff --git a/doc/modbus_set_float.txt b/doc/modbus_set_float.txt index 073470b..f124022 100644 --- a/doc/modbus_set_float.txt +++ b/doc/modbus_set_float.txt @@ -1,7 +1,6 @@ modbus_set_float(3) =================== - NAME ---- modbus_set_float - set a float value from 2 registers @@ -11,6 +10,8 @@ SYNOPSIS -------- *void modbus_set_float(float 'f', uint16_t *'dest');* +Warning, this function is *deprecated* since libmodbus v3.2.0 and has been +replaced by *modbus_set_float_dcba()*. DESCRIPTION ----------- @@ -26,9 +27,8 @@ There is no return values. SEE ALSO -------- -linkmb:modbus_set_float[3] +linkmb:modbus_get_float[3] linkmb:modbus_set_float_dcba[3] -linkmb:modbus_get_float_dcba[3] AUTHORS ------- diff --git a/src/modbus-data.c b/src/modbus-data.c index b2fa640..ec5e262 100644 --- a/src/modbus-data.c +++ b/src/modbus-data.c @@ -1,5 +1,5 @@ /* - * Copyright © 2010-2011 Stéphane Raimbault + * Copyright © 2010-2014 Stéphane Raimbault * * SPDX-License-Identifier: LGPL-2.1+ */ @@ -13,6 +13,12 @@ #include #include +#if defined(_WIN32) +# include +#else +# include +#endif + #include "modbus.h" #if defined(HAVE_BYTESWAP_H) @@ -96,47 +102,116 @@ uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, return value; } -/* Get a float from 4 bytes in Modbus format (ABCD) */ -float modbus_get_float(const uint16_t *src) +/* Get a float from 4 bytes (Modbus) without any conversion (ABCD) */ +float modbus_get_float_abcd(const uint16_t *src) { float f; uint32_t i; - i = (((uint32_t)src[1]) << 16) + src[0]; + i = ntohl(((uint32_t)src[0] << 16) + src[1]); memcpy(&f, &i, sizeof(float)); return f; } -/* Get a float from 4 bytes in inversed Modbus format (DCBA) */ +/* Get a float from 4 bytes (Modbus) with byte and word swap conversion (DCBA) */ float modbus_get_float_dcba(const uint16_t *src) { float f; uint32_t i; - i = bswap_32((((uint32_t)src[1]) << 16) + src[0]); + i = ntohl(bswap_32((((uint32_t)src[0]) << 16) + src[1])); memcpy(&f, &i, sizeof(float)); return f; } -/* Set a float to 4 bytes in Modbus format (ABCD) */ -void modbus_set_float(float f, uint16_t *dest) +/* Get a float from 4 bytes (Modbus) with byte swap conversion (BADC) */ +float modbus_get_float_badc(const uint16_t *src) +{ + float f; + uint32_t i; + + i = ntohl((uint32_t)(bswap_16(src[0]) << 16) + bswap_16(src[1])); + memcpy(&f, &i, sizeof(float)); + + return f; +} + +/* Get a float from 4 bytes (Modbus) in the format CDAB */ +float modbus_get_float_cdab(const uint16_t *src) +{ + float f; + uint32_t i; + + i = ntohl((((uint32_t)src[1]) << 16) + src[0]); + memcpy(&f, &i, sizeof(float)); + + return f; +} + +/* DEPRECATED - Get a float from 4 bytes in sort of Modbus format */ +float modbus_get_float(const uint16_t *src) +{ + float f; + uint32_t i; + + i = (((uint32_t)src[1]) << 16) + src[0]; + memcpy(&f, &i, sizeof(float)); + + return f; +} + +/* Set a float to 4 bytes for Modbus w/o any conversion (ABCD) */ +void modbus_set_float_abcd(float f, uint16_t *dest) +{ + uint32_t i; + + memcpy(&i, &f, sizeof(uint32_t)); + i = htonl(i); + dest[0] = (uint16_t)(i >> 16); + dest[1] = (uint16_t)i; +} + +/* Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA) */ +void modbus_set_float_dcba(float f, uint16_t *dest) { uint32_t i; memcpy(&i, &f, sizeof(uint32_t)); + i = bswap_32(htonl(i)); + dest[0] = (uint16_t)(i >> 16); + dest[1] = (uint16_t)i; +} + +/* Set a float to 4 bytes for Modbus with byte swap conversion (BADC) */ +void modbus_set_float_badc(float f, uint16_t *dest) +{ + uint32_t i; + + memcpy(&i, &f, sizeof(uint32_t)); + i = htonl(i); + dest[0] = (uint16_t)bswap_16(i >> 16); + dest[1] = (uint16_t)bswap_16(i & 0xFFFF); +} + +/* Set a float to 4 bytes for Modbus with word swap conversion (CDAB) */ +void modbus_set_float_cdab(float f, uint16_t *dest) +{ + uint32_t i; + + memcpy(&i, &f, sizeof(uint32_t)); + i = htonl(i); dest[0] = (uint16_t)i; dest[1] = (uint16_t)(i >> 16); } -/* Set a float to 4 bytes in inversed Modbus format (DCBA) */ -void modbus_set_float_dcba(float f, uint16_t *dest) +/* DEPRECATED - Set a float to 4 bytes in a sort of Modbus format! */ +void modbus_set_float(float f, uint16_t *dest) { uint32_t i; memcpy(&i, &f, sizeof(uint32_t)); - i = bswap_32(i); dest[0] = (uint16_t)i; dest[1] = (uint16_t)(i >> 16); } diff --git a/src/modbus.h b/src/modbus.h index 0ff745d..47a69d1 100644 --- a/src/modbus.h +++ b/src/modbus.h @@ -268,9 +268,16 @@ MODBUS_API void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int const uint8_t *tab_byte); MODBUS_API uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, unsigned int nb_bits); MODBUS_API float modbus_get_float(const uint16_t *src); +MODBUS_API float modbus_get_float_abcd(const uint16_t *src); MODBUS_API float modbus_get_float_dcba(const uint16_t *src); +MODBUS_API float modbus_get_float_badc(const uint16_t *src); +MODBUS_API float modbus_get_float_cdab(const uint16_t *src); + MODBUS_API void modbus_set_float(float f, uint16_t *dest); +MODBUS_API void modbus_set_float_abcd(float f, uint16_t *dest); MODBUS_API void modbus_set_float_dcba(float f, uint16_t *dest); +MODBUS_API void modbus_set_float_badc(float f, uint16_t *dest); +MODBUS_API void modbus_set_float_cdab(float f, uint16_t *dest); #include "modbus-tcp.h" #include "modbus-rtu.h" diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index 15ba9e4..cfb2c18 100644 --- a/tests/unit-test-client.c +++ b/tests/unit-test-client.c @@ -24,6 +24,7 @@ int send_crafted_request(modbus_t *ctx, int function, uint8_t *req, int req_size, uint16_t max_value, uint16_t bytes, int backend_length, int backend_offset); +int equal_dword(uint16_t *tab_reg, const uint32_t value); #define BUG_REPORT(_cond, _format, _args ...) \ printf("\nLine %d: assertion error for '%s': " _format "\n", __LINE__, # _cond, ## _args) @@ -37,6 +38,10 @@ int send_crafted_request(modbus_t *ctx, int function, } \ }; +int equal_dword(uint16_t *tab_reg, const uint32_t value) { + return ((tab_reg[0] == (value >> 16)) && (tab_reg[1] == (value & 0xFFFF))); +} + int main(int argc, char *argv[]) { const int NB_REPORT_SLAVE_ID = 10; @@ -49,7 +54,6 @@ int main(int argc, char *argv[]) int nb_points; int rc; float real; - uint32_t ireal; uint32_t old_response_to_sec; uint32_t old_response_to_usec; uint32_t new_response_to_sec; @@ -267,38 +271,6 @@ int main(int argc, char *argv[]) tab_rp_registers[i], UT_INPUT_REGISTERS_TAB[i]); } - printf("\nTEST FLOATS\n"); - /** FLOAT **/ - printf("1/4 Set float: "); - modbus_set_float(UT_REAL, tab_rp_registers); - if (tab_rp_registers[1] == (UT_IREAL >> 16) && - tab_rp_registers[0] == (UT_IREAL & 0xFFFF)) { - printf("OK\n"); - } else { - /* Avoid *((uint32_t *)tab_rp_registers) - * https://github.com/stephane/libmodbus/pull/104 */ - ireal = (uint32_t) tab_rp_registers[0] & 0xFFFF; - ireal |= (uint32_t) tab_rp_registers[1] << 16; - printf("FAILED (%x != %x)\n", ireal, UT_IREAL); - goto close; - } - - printf("2/4 Get float: "); - real = modbus_get_float(tab_rp_registers); - ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); - - printf("3/4 Set float in DBCA order: "); - modbus_set_float_dcba(UT_REAL, tab_rp_registers); - ireal = (uint32_t) tab_rp_registers[0] & 0xFFFF; - ireal |= (uint32_t) tab_rp_registers[1] << 16; - ASSERT_TRUE(tab_rp_registers[1] == (UT_IREAL_DCBA >> 16) && - tab_rp_registers[0] == (UT_IREAL_DCBA & 0xFFFF), - "FAILED (%x != %x)\n", ireal, UT_IREAL_DCBA); - - printf("4/4 Get float in DCBA order: "); - real = modbus_get_float_dcba(tab_rp_registers); - ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); - /* MASKS */ printf("1/1 Write mask: "); rc = modbus_write_register(ctx, UT_REGISTERS_ADDRESS, 0x12); @@ -309,6 +281,32 @@ int main(int argc, char *argv[]) "FAILED (%0X != %0X)\n", tab_rp_registers[0], 0x17); + printf("\nTEST FLOATS\n"); + /** FLOAT **/ + printf("1/4 Set/get float ABCD: "); + modbus_set_float_abcd(UT_REAL, tab_rp_registers); + ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_ABCD), "FAILED Set float ABCD"); + real = modbus_get_float_abcd(tab_rp_registers); + ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); + + printf("2/4 Set/get float DCBA: "); + modbus_set_float_dcba(UT_REAL, tab_rp_registers); + ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_DCBA), "FAILED Set float DCBA"); + real = modbus_get_float_dcba(tab_rp_registers); + ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); + + printf("3/4 Set/get float BADC: "); + modbus_set_float_badc(UT_REAL, tab_rp_registers); + ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_BADC), "FAILED Set float BADC"); + real = modbus_get_float_badc(tab_rp_registers); + ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); + + printf("4/4 Set/get float CDAB: "); + modbus_set_float_cdab(UT_REAL, tab_rp_registers); + ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_CDAB), "FAILED Set float CDAB"); + real = modbus_get_float_cdab(tab_rp_registers); + ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); + printf("\nAt this point, error messages doesn't mean the test has failed\n"); /** ILLEGAL DATA ADDRESS **/ diff --git a/tests/unit-test.h.in b/tests/unit-test.h.in index 93ba032..b753ad3 100644 --- a/tests/unit-test.h.in +++ b/tests/unit-test.h.in @@ -55,8 +55,16 @@ const uint16_t UT_INPUT_REGISTERS_ADDRESS = 0x108; const uint16_t UT_INPUT_REGISTERS_NB = 0x1; const uint16_t UT_INPUT_REGISTERS_TAB[] = { 0x000A }; -const float UT_REAL = 916.540649; -const uint32_t UT_IREAL = 0x4465229a; -const uint32_t UT_IREAL_DCBA = 0x9a226544; +const float UT_REAL = 123456.00; + +const uint32_t UT_IREAL_ABCD = 0x0020F147; +const uint32_t UT_IREAL_DCBA = 0x47F12000; +const uint32_t UT_IREAL_BADC = 0x200047F1; +const uint32_t UT_IREAL_CDAB = 0xF1470020; + +/* const uint32_t UT_IREAL_ABCD = 0x47F12000); +const uint32_t UT_IREAL_DCBA = 0x0020F147; +const uint32_t UT_IREAL_BADC = 0xF1470020; +const uint32_t UT_IREAL_CDAB = 0x200047F1;*/ #endif /* _UNIT_TEST_H_ */ -- libgit2 0.21.4