endianconv.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*******************************************************************************
  2. * Copyright (c) 2009, Rockwell Automation, Inc.
  3. * All rights reserved.
  4. *
  5. ******************************************************************************/
  6. #ifdef WIN32
  7. #include <winsock2.h>
  8. #elif defined HPMICRO
  9. #include "lwip/inet.h"
  10. #else
  11. #include <netinet/in.h>
  12. #include <sys/socket.h>
  13. #endif
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include "endianconv.h"
  18. OpenerEndianess g_opener_platform_endianess = kOpenerEndianessUnknown;
  19. /* THESE ROUTINES MODIFY THE BUFFER POINTER*/
  20. /**
  21. * @brief Reads EIP_UINT8 from *buffer and converts little endian to host.
  22. * @param buffer pointer where data should be reed.
  23. * @return EIP_UINT8 data value
  24. */
  25. CipSint GetSintFromMessage(const EipUint8 **const buffer) {
  26. const unsigned char *const buffer_address = (unsigned char *) *buffer;
  27. EipUint8 data = buffer_address[0];
  28. *buffer += 1;
  29. return data;
  30. }
  31. CipByte GetByteFromMessage(const CipOctet **const buffer_address) {
  32. const CipOctet *buffer = *buffer_address;
  33. CipByte data = buffer[0];
  34. *buffer_address += 1;
  35. return data;
  36. }
  37. CipUsint GetUsintFromMessage(const CipOctet **const buffer_address) {
  38. const CipOctet *buffer = *buffer_address;
  39. CipUsint data = buffer[0];
  40. *buffer_address += 1;
  41. return data;
  42. }
  43. CipBool GetBoolFromMessage(const EipBool8 **const buffer_address) {
  44. const EipBool8 *buffer = *buffer_address;
  45. EipBool8 data = buffer[0];
  46. *buffer_address += 1;
  47. return data;
  48. }
  49. /* little-endian-to-host unsigned 16 bit*/
  50. /**
  51. * @brief Reads EIP_UINT16 from *buffer and converts little endian to host.
  52. * @param buffer pointer where data should be reed.
  53. * @return EIP_UINT16 data value
  54. */
  55. CipInt GetIntFromMessage(const EipUint8 **const buffer) {
  56. const unsigned char *const buffer_address = (unsigned char *) *buffer;
  57. EipUint16 data = buffer_address[0] | buffer_address[1] << 8;
  58. *buffer += 2;
  59. return data;
  60. }
  61. CipUint GetUintFromMessage(const CipOctet **const buffer_address) {
  62. const CipOctet *buffer = *buffer_address;
  63. EipUint16 data = buffer[0] | buffer[1] << 8;
  64. *buffer_address += 2;
  65. return data;
  66. }
  67. CipWord GetWordFromMessage(const CipOctet **const buffer_address) {
  68. const CipOctet *buffer = *buffer_address;
  69. EipUint16 data = buffer[0] | buffer[1] << 8;
  70. *buffer_address += 2;
  71. return data;
  72. }
  73. /**
  74. * @brief Reads EIP_UINT32 from *buffer and converts little endian to host.
  75. * @param buffer pointer where data should be reed.
  76. * @return EIP_UNÍT32 value
  77. */
  78. CipDint GetDintFromMessage(const EipUint8 **const buffer) {
  79. const unsigned char *p = (unsigned char *) *buffer;
  80. EipUint32 data = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
  81. *buffer += 4;
  82. return data;
  83. }
  84. CipUdint GetUdintFromMessage(const CipOctet **const buffer_address) {
  85. const CipOctet *buffer = *buffer_address;
  86. CipUdint data = buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] <<
  87. 24;
  88. *buffer_address += 4;
  89. return data;
  90. }
  91. CipUdint GetDwordFromMessage(const CipOctet **const buffer_address) {
  92. const CipOctet *buffer = *buffer_address;
  93. CipDword data = buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] <<
  94. 24;
  95. *buffer_address += 4;
  96. return data;
  97. }
  98. /**
  99. * @brief converts UINT8 data from host to little endian an writes it to buffer.
  100. * @param data value to be written
  101. * @param buffer pointer where data should be written.
  102. */
  103. void AddSintToMessage(const EipUint8 data,
  104. ENIPMessage *const outgoing_message) {
  105. outgoing_message->current_message_position[0] = (unsigned char) data;
  106. outgoing_message->current_message_position += 1;
  107. outgoing_message->used_message_length += 1;
  108. }
  109. /**
  110. * @brief converts UINT16 data from host to little endian an writes it to buffer.
  111. * @param data value to be written
  112. * @param buffer pointer where data should be written.
  113. */
  114. void AddIntToMessage(const EipUint16 data,
  115. ENIPMessage *const outgoing_message) {
  116. outgoing_message->current_message_position[0] = (unsigned char) data;
  117. outgoing_message->current_message_position[1] = (unsigned char) (data >> 8);
  118. outgoing_message->current_message_position += 2;
  119. outgoing_message->used_message_length += 2;
  120. }
  121. /**
  122. * @brief Converts UINT32 data from host to little endian and writes it to buffer.
  123. * @param data value to be written
  124. * @param buffer pointer where data should be written.
  125. */
  126. void AddDintToMessage(const EipUint32 data,
  127. ENIPMessage *const outgoing_message) {
  128. outgoing_message->current_message_position[0] = (unsigned char) data;
  129. outgoing_message->current_message_position[1] = (unsigned char) (data >> 8);
  130. outgoing_message->current_message_position[2] = (unsigned char) (data >> 16);
  131. outgoing_message->current_message_position[3] = (unsigned char) (data >> 24);
  132. outgoing_message->current_message_position += 4;
  133. outgoing_message->used_message_length += 4;
  134. }
  135. /**
  136. * @brief Reads EipUint64 from *pa_buf and converts little endian to host.
  137. * @param pa_buf pointer where data should be reed.
  138. * @return EipUint64 value
  139. */
  140. EipUint64 GetLintFromMessage(const EipUint8 **const buffer) {
  141. const EipUint8 *buffer_address = *buffer;
  142. EipUint64 data =
  143. ( ( ( (EipUint64) buffer_address[0] ) << 56 ) & 0xFF00000000000000LL ) +
  144. ( ( ( (EipUint64) buffer_address[1] ) << 48 ) & 0x00FF000000000000LL )
  145. + ( ( ( (EipUint64) buffer_address[2] ) << 40 ) &
  146. 0x0000FF0000000000LL ) +
  147. ( ( ( (EipUint64) buffer_address[3] ) << 32 ) & 0x000000FF00000000LL )
  148. + ( ( ( (EipUint64) buffer_address[4] ) << 24 ) &
  149. 0x00000000FF000000 ) +
  150. ( ( ( (EipUint64) buffer_address[5] ) << 16 ) & 0x0000000000FF0000 )
  151. + ( ( ( (EipUint64) buffer_address[6] ) << 8 ) &
  152. 0x000000000000FF00 ) +
  153. ( ( (EipUint64) buffer_address[7] ) & 0x00000000000000FF );
  154. *buffer += 8;
  155. return data;
  156. }
  157. /**
  158. * @brief Converts EipUint64 data from host to little endian and writes it to buffer.
  159. * @param data value to be written
  160. * @param buffer pointer where data should be written.
  161. */
  162. void AddLintToMessage(const EipUint64 data,
  163. ENIPMessage *const outgoing_message) {
  164. outgoing_message->current_message_position[0] = (EipUint8) (data);
  165. outgoing_message->current_message_position[1] = (EipUint8) (data >> 8);
  166. outgoing_message->current_message_position[2] = (EipUint8) (data >> 16);
  167. outgoing_message->current_message_position[3] = (EipUint8) (data >> 24);
  168. outgoing_message->current_message_position[4] = (EipUint8) (data >> 32);
  169. outgoing_message->current_message_position[5] = (EipUint8) (data >> 40);
  170. outgoing_message->current_message_position[6] = (EipUint8) (data >> 48);
  171. outgoing_message->current_message_position[7] = (EipUint8) (data >> 56);
  172. outgoing_message->current_message_position += 8;
  173. outgoing_message->used_message_length += 8;
  174. }
  175. void EncapsulateIpAddress(EipUint16 port,
  176. EipUint32 address,
  177. ENIPMessage *const outgoing_message) {
  178. if(kOpENerEndianessLittle == g_opener_platform_endianess) {
  179. AddIntToMessage(htons(AF_INET), outgoing_message);
  180. AddIntToMessage(port, outgoing_message);
  181. AddDintToMessage(address, outgoing_message);
  182. } else {
  183. if(kOpENerEndianessBig == g_opener_platform_endianess) {
  184. AddIntToMessage(htons(AF_INET), outgoing_message);
  185. AddSintToMessage( (unsigned char) (port >> 8), outgoing_message );
  186. AddSintToMessage( (unsigned char) port, outgoing_message );
  187. AddSintToMessage( (unsigned char) address, outgoing_message );
  188. AddSintToMessage( (unsigned char) (address >> 8), outgoing_message );
  189. AddSintToMessage( (unsigned char) (address >> 16), outgoing_message );
  190. AddSintToMessage( (unsigned char) (address >> 24), outgoing_message );
  191. } else {
  192. fprintf(stderr,
  193. "No endianess detected! Probably the DetermineEndianess function was not executed!");
  194. exit(EXIT_FAILURE);
  195. }
  196. }
  197. }
  198. /**
  199. * @brief Detects Endianess of the platform and sets global g_nOpENerPlatformEndianess variable accordingly
  200. *
  201. * Detects Endianess of the platform and sets global variable g_nOpENerPlatformEndianess accordingly,
  202. * whereas 0 equals little endian and 1 equals big endian
  203. */
  204. void DetermineEndianess() {
  205. int i = 1;
  206. const char *const p = (char *) &i;
  207. if(p[0] == 1) {
  208. g_opener_platform_endianess = kOpENerEndianessLittle;
  209. } else {
  210. g_opener_platform_endianess = kOpENerEndianessBig;
  211. }
  212. }
  213. /**
  214. * @brief Returns global variable g_nOpENerPlatformEndianess, whereas 0 equals little endian and 1 equals big endian
  215. *
  216. * @return 0 equals little endian and 1 equals big endian
  217. */
  218. int GetEndianess() {
  219. return g_opener_platform_endianess;
  220. }
  221. void MoveMessageNOctets(const int amount_of_bytes_moved,
  222. ENIPMessage *const outgoing_message) {
  223. outgoing_message->current_message_position += amount_of_bytes_moved;
  224. outgoing_message->used_message_length += amount_of_bytes_moved;
  225. }
  226. void FillNextNMessageOctetsWith(CipOctet value,
  227. unsigned int amount_of_bytes_written,
  228. ENIPMessage *const outgoing_message) {
  229. memset(outgoing_message->current_message_position,
  230. value,
  231. amount_of_bytes_written);
  232. }
  233. void FillNextNMessageOctetsWithValueAndMoveToNextPosition(CipOctet value,
  234. unsigned int amount_of_filled_bytes,
  235. ENIPMessage *const outgoing_message)
  236. {
  237. FillNextNMessageOctetsWith(value, amount_of_filled_bytes, outgoing_message);
  238. MoveMessageNOctets(amount_of_filled_bytes, outgoing_message);
  239. }