Commit 08ed259fe65666ab3115fb93848ec0b6b5661f56
1 parent
caade94b
Rewrite and extend functions to manipulate float values
Showing
7 changed files
with
143 additions
and
55 deletions
doc/modbus_get_float.txt
doc/modbus_get_float_dcba.txt
| ... | ... | @@ -15,9 +15,9 @@ SYNOPSIS |
| 15 | 15 | DESCRIPTION |
| 16 | 16 | ----------- |
| 17 | 17 | The *modbus_get_float_dcba()* function shall get a float from 4 bytes in |
| 18 | -inversed Modbus format (DCBA order). The _src_ array must be pointer on two 16 | |
| 19 | -bits values, for example, if the first word is set to 0x9a22 and the second to | |
| 20 | -0x6544, the float value read will be 916.540649. | |
| 18 | +inversed Modbus format (DCBA order instead of ABCD). The _src_ array must be | |
| 19 | +pointer on two 16 bits values, for example, if the first word is set to 0x9a22 | |
| 20 | +and the second to 0x6544, the float value read will be 916.540649. | |
| 21 | 21 | |
| 22 | 22 | |
| 23 | 23 | RETURN VALUE |
| ... | ... | @@ -28,8 +28,6 @@ The function shall return a float. |
| 28 | 28 | SEE ALSO |
| 29 | 29 | -------- |
| 30 | 30 | linkmb:modbus_set_float_dcba[3] |
| 31 | -linkmb:modbus_set_float[3] | |
| 32 | -linkmb:modbus_get_float[3] | |
| 33 | 31 | |
| 34 | 32 | |
| 35 | 33 | AUTHORS | ... | ... |
doc/modbus_set_float.txt
| 1 | 1 | modbus_set_float(3) |
| 2 | 2 | =================== |
| 3 | 3 | |
| 4 | - | |
| 5 | 4 | NAME |
| 6 | 5 | ---- |
| 7 | 6 | modbus_set_float - set a float value from 2 registers |
| ... | ... | @@ -11,6 +10,8 @@ SYNOPSIS |
| 11 | 10 | -------- |
| 12 | 11 | *void modbus_set_float(float 'f', uint16_t *'dest');* |
| 13 | 12 | |
| 13 | +Warning, this function is *deprecated* since libmodbus v3.2.0 and has been | |
| 14 | +replaced by *modbus_set_float_dcba()*. | |
| 14 | 15 | |
| 15 | 16 | DESCRIPTION |
| 16 | 17 | ----------- |
| ... | ... | @@ -26,9 +27,8 @@ There is no return values. |
| 26 | 27 | |
| 27 | 28 | SEE ALSO |
| 28 | 29 | -------- |
| 29 | -linkmb:modbus_set_float[3] | |
| 30 | +linkmb:modbus_get_float[3] | |
| 30 | 31 | linkmb:modbus_set_float_dcba[3] |
| 31 | -linkmb:modbus_get_float_dcba[3] | |
| 32 | 32 | |
| 33 | 33 | AUTHORS |
| 34 | 34 | ------- | ... | ... |
src/modbus-data.c
| 1 | 1 | /* |
| 2 | - * Copyright © 2010-2011 Stéphane Raimbault <stephane.raimbault@gmail.com> | |
| 2 | + * Copyright © 2010-2014 Stéphane Raimbault <stephane.raimbault@gmail.com> | |
| 3 | 3 | * |
| 4 | 4 | * SPDX-License-Identifier: LGPL-2.1+ |
| 5 | 5 | */ |
| ... | ... | @@ -13,6 +13,12 @@ |
| 13 | 13 | #include <string.h> |
| 14 | 14 | #include <assert.h> |
| 15 | 15 | |
| 16 | +#if defined(_WIN32) | |
| 17 | +# include <winsock2.h> | |
| 18 | +#else | |
| 19 | +# include <arpa/inet.h> | |
| 20 | +#endif | |
| 21 | + | |
| 16 | 22 | #include "modbus.h" |
| 17 | 23 | |
| 18 | 24 | #if defined(HAVE_BYTESWAP_H) |
| ... | ... | @@ -96,47 +102,116 @@ uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, |
| 96 | 102 | return value; |
| 97 | 103 | } |
| 98 | 104 | |
| 99 | -/* Get a float from 4 bytes in Modbus format (ABCD) */ | |
| 100 | -float modbus_get_float(const uint16_t *src) | |
| 105 | +/* Get a float from 4 bytes (Modbus) without any conversion (ABCD) */ | |
| 106 | +float modbus_get_float_abcd(const uint16_t *src) | |
| 101 | 107 | { |
| 102 | 108 | float f; |
| 103 | 109 | uint32_t i; |
| 104 | 110 | |
| 105 | - i = (((uint32_t)src[1]) << 16) + src[0]; | |
| 111 | + i = ntohl(((uint32_t)src[0] << 16) + src[1]); | |
| 106 | 112 | memcpy(&f, &i, sizeof(float)); |
| 107 | 113 | |
| 108 | 114 | return f; |
| 109 | 115 | } |
| 110 | 116 | |
| 111 | -/* Get a float from 4 bytes in inversed Modbus format (DCBA) */ | |
| 117 | +/* Get a float from 4 bytes (Modbus) with byte and word swap conversion (DCBA) */ | |
| 112 | 118 | float modbus_get_float_dcba(const uint16_t *src) |
| 113 | 119 | { |
| 114 | 120 | float f; |
| 115 | 121 | uint32_t i; |
| 116 | 122 | |
| 117 | - i = bswap_32((((uint32_t)src[1]) << 16) + src[0]); | |
| 123 | + i = ntohl(bswap_32((((uint32_t)src[0]) << 16) + src[1])); | |
| 118 | 124 | memcpy(&f, &i, sizeof(float)); |
| 119 | 125 | |
| 120 | 126 | return f; |
| 121 | 127 | } |
| 122 | 128 | |
| 123 | -/* Set a float to 4 bytes in Modbus format (ABCD) */ | |
| 124 | -void modbus_set_float(float f, uint16_t *dest) | |
| 129 | +/* Get a float from 4 bytes (Modbus) with byte swap conversion (BADC) */ | |
| 130 | +float modbus_get_float_badc(const uint16_t *src) | |
| 131 | +{ | |
| 132 | + float f; | |
| 133 | + uint32_t i; | |
| 134 | + | |
| 135 | + i = ntohl((uint32_t)(bswap_16(src[0]) << 16) + bswap_16(src[1])); | |
| 136 | + memcpy(&f, &i, sizeof(float)); | |
| 137 | + | |
| 138 | + return f; | |
| 139 | +} | |
| 140 | + | |
| 141 | +/* Get a float from 4 bytes (Modbus) in the format CDAB */ | |
| 142 | +float modbus_get_float_cdab(const uint16_t *src) | |
| 143 | +{ | |
| 144 | + float f; | |
| 145 | + uint32_t i; | |
| 146 | + | |
| 147 | + i = ntohl((((uint32_t)src[1]) << 16) + src[0]); | |
| 148 | + memcpy(&f, &i, sizeof(float)); | |
| 149 | + | |
| 150 | + return f; | |
| 151 | +} | |
| 152 | + | |
| 153 | +/* DEPRECATED - Get a float from 4 bytes in sort of Modbus format */ | |
| 154 | +float modbus_get_float(const uint16_t *src) | |
| 155 | +{ | |
| 156 | + float f; | |
| 157 | + uint32_t i; | |
| 158 | + | |
| 159 | + i = (((uint32_t)src[1]) << 16) + src[0]; | |
| 160 | + memcpy(&f, &i, sizeof(float)); | |
| 161 | + | |
| 162 | + return f; | |
| 163 | +} | |
| 164 | + | |
| 165 | +/* Set a float to 4 bytes for Modbus w/o any conversion (ABCD) */ | |
| 166 | +void modbus_set_float_abcd(float f, uint16_t *dest) | |
| 167 | +{ | |
| 168 | + uint32_t i; | |
| 169 | + | |
| 170 | + memcpy(&i, &f, sizeof(uint32_t)); | |
| 171 | + i = htonl(i); | |
| 172 | + dest[0] = (uint16_t)(i >> 16); | |
| 173 | + dest[1] = (uint16_t)i; | |
| 174 | +} | |
| 175 | + | |
| 176 | +/* Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA) */ | |
| 177 | +void modbus_set_float_dcba(float f, uint16_t *dest) | |
| 125 | 178 | { |
| 126 | 179 | uint32_t i; |
| 127 | 180 | |
| 128 | 181 | memcpy(&i, &f, sizeof(uint32_t)); |
| 182 | + i = bswap_32(htonl(i)); | |
| 183 | + dest[0] = (uint16_t)(i >> 16); | |
| 184 | + dest[1] = (uint16_t)i; | |
| 185 | +} | |
| 186 | + | |
| 187 | +/* Set a float to 4 bytes for Modbus with byte swap conversion (BADC) */ | |
| 188 | +void modbus_set_float_badc(float f, uint16_t *dest) | |
| 189 | +{ | |
| 190 | + uint32_t i; | |
| 191 | + | |
| 192 | + memcpy(&i, &f, sizeof(uint32_t)); | |
| 193 | + i = htonl(i); | |
| 194 | + dest[0] = (uint16_t)bswap_16(i >> 16); | |
| 195 | + dest[1] = (uint16_t)bswap_16(i & 0xFFFF); | |
| 196 | +} | |
| 197 | + | |
| 198 | +/* Set a float to 4 bytes for Modbus with word swap conversion (CDAB) */ | |
| 199 | +void modbus_set_float_cdab(float f, uint16_t *dest) | |
| 200 | +{ | |
| 201 | + uint32_t i; | |
| 202 | + | |
| 203 | + memcpy(&i, &f, sizeof(uint32_t)); | |
| 204 | + i = htonl(i); | |
| 129 | 205 | dest[0] = (uint16_t)i; |
| 130 | 206 | dest[1] = (uint16_t)(i >> 16); |
| 131 | 207 | } |
| 132 | 208 | |
| 133 | -/* Set a float to 4 bytes in inversed Modbus format (DCBA) */ | |
| 134 | -void modbus_set_float_dcba(float f, uint16_t *dest) | |
| 209 | +/* DEPRECATED - Set a float to 4 bytes in a sort of Modbus format! */ | |
| 210 | +void modbus_set_float(float f, uint16_t *dest) | |
| 135 | 211 | { |
| 136 | 212 | uint32_t i; |
| 137 | 213 | |
| 138 | 214 | memcpy(&i, &f, sizeof(uint32_t)); |
| 139 | - i = bswap_32(i); | |
| 140 | 215 | dest[0] = (uint16_t)i; |
| 141 | 216 | dest[1] = (uint16_t)(i >> 16); |
| 142 | 217 | } | ... | ... |
src/modbus.h
| ... | ... | @@ -268,9 +268,16 @@ MODBUS_API void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int |
| 268 | 268 | const uint8_t *tab_byte); |
| 269 | 269 | MODBUS_API uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, unsigned int nb_bits); |
| 270 | 270 | MODBUS_API float modbus_get_float(const uint16_t *src); |
| 271 | +MODBUS_API float modbus_get_float_abcd(const uint16_t *src); | |
| 271 | 272 | MODBUS_API float modbus_get_float_dcba(const uint16_t *src); |
| 273 | +MODBUS_API float modbus_get_float_badc(const uint16_t *src); | |
| 274 | +MODBUS_API float modbus_get_float_cdab(const uint16_t *src); | |
| 275 | + | |
| 272 | 276 | MODBUS_API void modbus_set_float(float f, uint16_t *dest); |
| 277 | +MODBUS_API void modbus_set_float_abcd(float f, uint16_t *dest); | |
| 273 | 278 | MODBUS_API void modbus_set_float_dcba(float f, uint16_t *dest); |
| 279 | +MODBUS_API void modbus_set_float_badc(float f, uint16_t *dest); | |
| 280 | +MODBUS_API void modbus_set_float_cdab(float f, uint16_t *dest); | |
| 274 | 281 | |
| 275 | 282 | #include "modbus-tcp.h" |
| 276 | 283 | #include "modbus-rtu.h" | ... | ... |
tests/unit-test-client.c
| ... | ... | @@ -24,6 +24,7 @@ int send_crafted_request(modbus_t *ctx, int function, |
| 24 | 24 | uint8_t *req, int req_size, |
| 25 | 25 | uint16_t max_value, uint16_t bytes, |
| 26 | 26 | int backend_length, int backend_offset); |
| 27 | +int equal_dword(uint16_t *tab_reg, const uint32_t value); | |
| 27 | 28 | |
| 28 | 29 | #define BUG_REPORT(_cond, _format, _args ...) \ |
| 29 | 30 | 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, |
| 37 | 38 | } \ |
| 38 | 39 | }; |
| 39 | 40 | |
| 41 | +int equal_dword(uint16_t *tab_reg, const uint32_t value) { | |
| 42 | + return ((tab_reg[0] == (value >> 16)) && (tab_reg[1] == (value & 0xFFFF))); | |
| 43 | +} | |
| 44 | + | |
| 40 | 45 | int main(int argc, char *argv[]) |
| 41 | 46 | { |
| 42 | 47 | const int NB_REPORT_SLAVE_ID = 10; |
| ... | ... | @@ -49,7 +54,6 @@ int main(int argc, char *argv[]) |
| 49 | 54 | int nb_points; |
| 50 | 55 | int rc; |
| 51 | 56 | float real; |
| 52 | - uint32_t ireal; | |
| 53 | 57 | uint32_t old_response_to_sec; |
| 54 | 58 | uint32_t old_response_to_usec; |
| 55 | 59 | uint32_t new_response_to_sec; |
| ... | ... | @@ -267,38 +271,6 @@ int main(int argc, char *argv[]) |
| 267 | 271 | tab_rp_registers[i], UT_INPUT_REGISTERS_TAB[i]); |
| 268 | 272 | } |
| 269 | 273 | |
| 270 | - printf("\nTEST FLOATS\n"); | |
| 271 | - /** FLOAT **/ | |
| 272 | - printf("1/4 Set float: "); | |
| 273 | - modbus_set_float(UT_REAL, tab_rp_registers); | |
| 274 | - if (tab_rp_registers[1] == (UT_IREAL >> 16) && | |
| 275 | - tab_rp_registers[0] == (UT_IREAL & 0xFFFF)) { | |
| 276 | - printf("OK\n"); | |
| 277 | - } else { | |
| 278 | - /* Avoid *((uint32_t *)tab_rp_registers) | |
| 279 | - * https://github.com/stephane/libmodbus/pull/104 */ | |
| 280 | - ireal = (uint32_t) tab_rp_registers[0] & 0xFFFF; | |
| 281 | - ireal |= (uint32_t) tab_rp_registers[1] << 16; | |
| 282 | - printf("FAILED (%x != %x)\n", ireal, UT_IREAL); | |
| 283 | - goto close; | |
| 284 | - } | |
| 285 | - | |
| 286 | - printf("2/4 Get float: "); | |
| 287 | - real = modbus_get_float(tab_rp_registers); | |
| 288 | - ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); | |
| 289 | - | |
| 290 | - printf("3/4 Set float in DBCA order: "); | |
| 291 | - modbus_set_float_dcba(UT_REAL, tab_rp_registers); | |
| 292 | - ireal = (uint32_t) tab_rp_registers[0] & 0xFFFF; | |
| 293 | - ireal |= (uint32_t) tab_rp_registers[1] << 16; | |
| 294 | - ASSERT_TRUE(tab_rp_registers[1] == (UT_IREAL_DCBA >> 16) && | |
| 295 | - tab_rp_registers[0] == (UT_IREAL_DCBA & 0xFFFF), | |
| 296 | - "FAILED (%x != %x)\n", ireal, UT_IREAL_DCBA); | |
| 297 | - | |
| 298 | - printf("4/4 Get float in DCBA order: "); | |
| 299 | - real = modbus_get_float_dcba(tab_rp_registers); | |
| 300 | - ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); | |
| 301 | - | |
| 302 | 274 | /* MASKS */ |
| 303 | 275 | printf("1/1 Write mask: "); |
| 304 | 276 | rc = modbus_write_register(ctx, UT_REGISTERS_ADDRESS, 0x12); |
| ... | ... | @@ -309,6 +281,32 @@ int main(int argc, char *argv[]) |
| 309 | 281 | "FAILED (%0X != %0X)\n", |
| 310 | 282 | tab_rp_registers[0], 0x17); |
| 311 | 283 | |
| 284 | + printf("\nTEST FLOATS\n"); | |
| 285 | + /** FLOAT **/ | |
| 286 | + printf("1/4 Set/get float ABCD: "); | |
| 287 | + modbus_set_float_abcd(UT_REAL, tab_rp_registers); | |
| 288 | + ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_ABCD), "FAILED Set float ABCD"); | |
| 289 | + real = modbus_get_float_abcd(tab_rp_registers); | |
| 290 | + ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); | |
| 291 | + | |
| 292 | + printf("2/4 Set/get float DCBA: "); | |
| 293 | + modbus_set_float_dcba(UT_REAL, tab_rp_registers); | |
| 294 | + ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_DCBA), "FAILED Set float DCBA"); | |
| 295 | + real = modbus_get_float_dcba(tab_rp_registers); | |
| 296 | + ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); | |
| 297 | + | |
| 298 | + printf("3/4 Set/get float BADC: "); | |
| 299 | + modbus_set_float_badc(UT_REAL, tab_rp_registers); | |
| 300 | + ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_BADC), "FAILED Set float BADC"); | |
| 301 | + real = modbus_get_float_badc(tab_rp_registers); | |
| 302 | + ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); | |
| 303 | + | |
| 304 | + printf("4/4 Set/get float CDAB: "); | |
| 305 | + modbus_set_float_cdab(UT_REAL, tab_rp_registers); | |
| 306 | + ASSERT_TRUE(equal_dword(tab_rp_registers, UT_IREAL_CDAB), "FAILED Set float CDAB"); | |
| 307 | + real = modbus_get_float_cdab(tab_rp_registers); | |
| 308 | + ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); | |
| 309 | + | |
| 312 | 310 | printf("\nAt this point, error messages doesn't mean the test has failed\n"); |
| 313 | 311 | |
| 314 | 312 | /** ILLEGAL DATA ADDRESS **/ | ... | ... |
tests/unit-test.h.in
| ... | ... | @@ -55,8 +55,16 @@ const uint16_t UT_INPUT_REGISTERS_ADDRESS = 0x108; |
| 55 | 55 | const uint16_t UT_INPUT_REGISTERS_NB = 0x1; |
| 56 | 56 | const uint16_t UT_INPUT_REGISTERS_TAB[] = { 0x000A }; |
| 57 | 57 | |
| 58 | -const float UT_REAL = 916.540649; | |
| 59 | -const uint32_t UT_IREAL = 0x4465229a; | |
| 60 | -const uint32_t UT_IREAL_DCBA = 0x9a226544; | |
| 58 | +const float UT_REAL = 123456.00; | |
| 59 | + | |
| 60 | +const uint32_t UT_IREAL_ABCD = 0x0020F147; | |
| 61 | +const uint32_t UT_IREAL_DCBA = 0x47F12000; | |
| 62 | +const uint32_t UT_IREAL_BADC = 0x200047F1; | |
| 63 | +const uint32_t UT_IREAL_CDAB = 0xF1470020; | |
| 64 | + | |
| 65 | +/* const uint32_t UT_IREAL_ABCD = 0x47F12000); | |
| 66 | +const uint32_t UT_IREAL_DCBA = 0x0020F147; | |
| 67 | +const uint32_t UT_IREAL_BADC = 0xF1470020; | |
| 68 | +const uint32_t UT_IREAL_CDAB = 0x200047F1;*/ | |
| 61 | 69 | |
| 62 | 70 | #endif /* _UNIT_TEST_H_ */ | ... | ... |