modbus-data.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * Copyright © 2010-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include <stdlib.h>
  19. #ifndef _MSC_VER
  20. #include <stdint.h>
  21. #else
  22. #include "stdint.h"
  23. #endif
  24. #include <string.h>
  25. #include <assert.h>
  26. #include "modbus.h"
  27. #if defined(HAVE_BYTESWAP_H)
  28. # include <byteswap.h>
  29. #endif
  30. #if defined(__GNUC__)
  31. # define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10)
  32. # if GCC_VERSION >= 430
  33. // Since GCC >= 4.30, GCC provides __builtin_bswapXX() alternatives so we switch to them
  34. # undef bswap_32
  35. # define bswap_32 __builtin_bswap32
  36. # endif
  37. #endif
  38. #if !defined (bswap_16) || !defined (bswap_32)
  39. # warning "Fallback on C functions for bswap_32"
  40. static inline uint16_t bswap_16(uint16_t x)
  41. {
  42. return (x >> 8) | (x << 8);
  43. }
  44. static inline uint32_t bswap_32(uint32_t x)
  45. {
  46. return (bswap_16(x & 0xffff) << 16) | (bswap_16(x >> 16));
  47. }
  48. #endif
  49. /* Sets many bits from a single byte value (all 8 bits of the byte value are
  50. set) */
  51. void modbus_set_bits_from_byte(uint8_t *dest, int index, const uint8_t value)
  52. {
  53. int i;
  54. for (i=0; i < 8; i++) {
  55. dest[index+i] = (value & (1 << i)) ? 1 : 0;
  56. }
  57. }
  58. /* Sets many bits from a table of bytes (only the bits between index and
  59. index + nb_bits are set) */
  60. void modbus_set_bits_from_bytes(uint8_t *dest, int index, unsigned int nb_bits,
  61. const uint8_t *tab_byte)
  62. {
  63. unsigned int i;
  64. int shift = 0;
  65. for (i = index; i < index + nb_bits; i++) {
  66. dest[i] = tab_byte[(i - index) / 8] & (1 << shift) ? 1 : 0;
  67. /* gcc doesn't like: shift = (++shift) % 8; */
  68. shift++;
  69. shift %= 8;
  70. }
  71. }
  72. /* Gets the byte value from many bits.
  73. To obtain a full byte, set nb_bits to 8. */
  74. uint8_t modbus_get_byte_from_bits(const uint8_t *src, int index,
  75. unsigned int nb_bits)
  76. {
  77. unsigned int i;
  78. uint8_t value = 0;
  79. if (nb_bits > 8) {
  80. /* Assert is ignored if NDEBUG is set */
  81. assert(nb_bits < 8);
  82. nb_bits = 8;
  83. }
  84. for (i=0; i < nb_bits; i++) {
  85. value |= (src[index+i] << i);
  86. }
  87. return value;
  88. }
  89. /* Get a float from 4 bytes in Modbus format (ABCD) */
  90. float modbus_get_float(const uint16_t *src)
  91. {
  92. float f;
  93. uint32_t i;
  94. i = (((uint32_t)src[1]) << 16) + src[0];
  95. memcpy(&f, &i, sizeof(float));
  96. return f;
  97. }
  98. /* Get a float from 4 bytes in inversed Modbus format (DCBA) */
  99. float modbus_get_float_dcba(const uint16_t *src)
  100. {
  101. float f;
  102. uint32_t i;
  103. i = bswap_32((((uint32_t)src[1]) << 16) + src[0]);
  104. memcpy(&f, &i, sizeof(float));
  105. return f;
  106. }
  107. /* Set a float to 4 bytes in Modbus format (ABCD) */
  108. void modbus_set_float(float f, uint16_t *dest)
  109. {
  110. uint32_t i;
  111. memcpy(&i, &f, sizeof(uint32_t));
  112. dest[0] = (uint16_t)i;
  113. dest[1] = (uint16_t)(i >> 16);
  114. }
  115. /* Set a float to 4 bytes in inversed Modbus format (DCBA) */
  116. void modbus_set_float_dcba(float f, uint16_t *dest)
  117. {
  118. uint32_t i;
  119. memcpy(&i, &f, sizeof(uint32_t));
  120. i = bswap_32(i);
  121. dest[0] = (uint16_t)i;
  122. dest[1] = (uint16_t)(i >> 16);
  123. }