Blame view

stack/modbus.h 9.89 KB
b85a3e4a   Peter M. Groen   Setting up workin...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  
  #pragma once
  
  /* Add this for macros that defined unix flavor */
  #if (defined(__unix__) || defined(unix)) && !defined(USG)
  #include <sys/param.h>
  #endif
  
  #include <stdint.h>
  
  #define MODBUS_API
  
  #define MODBUS_VERSION_STRING "1.0.0"
  
  #ifdef  __cplusplus
  #define MODBUS_BEGIN_DECLS  extern "C" {
  #define MODBUS_END_DECLS }
  #else
  # define MODBUS_BEGIN_DECLS
  # define MODBUS_END_DECLS
  #endif
  
  MODBUS_BEGIN_DECLS
  
  #ifndef FALSE
  #define FALSE 0
  #endif
  
  #ifndef TRUE
  #define TRUE 1
  #endif
  
  #ifndef OFF
  #define OFF 0
  #endif
  
  #ifndef ON
  #define ON 1
  #endif
  
  /* Modbus function codes */
  #define MODBUS_FC_READ_COILS                0x01
  #define MODBUS_FC_READ_DISCRETE_INPUTS      0x02
  #define MODBUS_FC_READ_HOLDING_REGISTERS    0x03
  #define MODBUS_FC_READ_INPUT_REGISTERS      0x04
  #define MODBUS_FC_WRITE_SINGLE_COIL         0x05
  #define MODBUS_FC_WRITE_SINGLE_REGISTER     0x06
  #define MODBUS_FC_READ_EXCEPTION_STATUS     0x07
  #define MODBUS_FC_WRITE_MULTIPLE_COILS      0x0F
  #define MODBUS_FC_WRITE_MULTIPLE_REGISTERS  0x10
  #define MODBUS_FC_REPORT_SLAVE_ID           0x11
  #define MODBUS_FC_MASK_WRITE_REGISTER       0x16
  #define MODBUS_FC_WRITE_AND_READ_REGISTERS  0x17
  
  #define MODBUS_BROADCAST_ADDRESS    0
  
  /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
   * Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0)
   * (chapter 6 section 11 page 29)
   * Quantity of Coils to write (2 bytes): 1 to 1968 (0x7B0)
   */
  #define MODBUS_MAX_READ_BITS              2000
  #define MODBUS_MAX_WRITE_BITS             1968
  
  /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 3 page 15)
   * Quantity of Registers to read (2 bytes): 1 to 125 (0x7D)
   * (chapter 6 section 12 page 31)
   * Quantity of Registers to write (2 bytes) 1 to 123 (0x7B)
   * (chapter 6 section 17 page 38)
   * Quantity of Registers to write in R/W registers (2 bytes) 1 to 121 (0x79)
   */
  #define MODBUS_MAX_READ_REGISTERS          125
  #define MODBUS_MAX_WRITE_REGISTERS         123
  #define MODBUS_MAX_WR_WRITE_REGISTERS      121
  #define MODBUS_MAX_WR_READ_REGISTERS       125
  
  /* The size of the MODBUS PDU is limited by the size constraint inherited from
   * the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256
   * bytes). Therefore, MODBUS PDU for serial line communication = 256 - Server
   * address (1 byte) - CRC (2 bytes) = 253 bytes.
   */
  #define MODBUS_MAX_PDU_LENGTH              253
  
  /* Consequently:
   * - RTU MODBUS ADU = 253 bytes + Server address (1 byte) + CRC (2 bytes) = 256
   *   bytes.
   * - TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes.
   * so the maximum of both backend in 260 bytes. This size can used to allocate
   * an array of bytes to store responses and it will be compatible with the two
   * backends.
   */
  #define MODBUS_MAX_ADU_LENGTH              260
  
  /* Random number to avoid errno conflicts */
  #define MODBUS_ENOBASE 112345678
  
  /* Protocol exceptions */
  enum {
      MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01,
      MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,
      MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
      MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE,
      MODBUS_EXCEPTION_ACKNOWLEDGE,
      MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY,
      MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE,
      MODBUS_EXCEPTION_MEMORY_PARITY,
      MODBUS_EXCEPTION_NOT_DEFINED,
      MODBUS_EXCEPTION_GATEWAY_PATH,
      MODBUS_EXCEPTION_GATEWAY_TARGET,
      MODBUS_EXCEPTION_MAX
  };
  
  #define EMBXILFUN  (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION)
  #define EMBXILADD  (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS)
  #define EMBXILVAL  (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE)
  #define EMBXSFAIL  (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE)
  #define EMBXACK    (MODBUS_ENOBASE + MODBUS_EXCEPTION_ACKNOWLEDGE)
  #define EMBXSBUSY  (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY)
  #define EMBXNACK   (MODBUS_ENOBASE + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE)
  #define EMBXMEMPAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_MEMORY_PARITY)
  #define EMBXGPATH  (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_PATH)
  #define EMBXGTAR   (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET)
  
  /* Native libmodbus error codes */
  #define EMBBADCRC  (EMBXGTAR + 1)
  #define EMBBADDATA (EMBXGTAR + 2)
  #define EMBBADEXC  (EMBXGTAR + 3)
  #define EMBUNKEXC  (EMBXGTAR + 4)
  #define EMBMDATA   (EMBXGTAR + 5)
  #define EMBBADSLAVE (EMBXGTAR + 6)
  
  typedef struct _modbus modbus_t;
  
  typedef struct {
      int nb_bits;
      int start_bits;
      int nb_input_bits;
      int start_input_bits;
      int nb_input_registers;
      int start_input_registers;
      int nb_registers;
      int start_registers;
      uint8_t *tab_bits;
      uint8_t *tab_input_bits;
      uint16_t *tab_input_registers;
      uint16_t *tab_registers;
  } modbus_mapping_t;
  
  typedef enum
  {
      MODBUS_ERROR_RECOVERY_NONE          = 0,
      MODBUS_ERROR_RECOVERY_LINK          = (1<<1),
      MODBUS_ERROR_RECOVERY_PROTOCOL      = (1<<2)
  } modbus_error_recovery_mode;
  
  MODBUS_API int modbus_set_slave(modbus_t* ctx, int slave);
  MODBUS_API int modbus_set_error_recovery(modbus_t *ctx, modbus_error_recovery_mode error_recovery);
  MODBUS_API int modbus_set_socket(modbus_t *ctx, int s);
  MODBUS_API int modbus_get_socket(modbus_t *ctx);
  
  MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
  MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
  
  MODBUS_API int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
  MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
  
  MODBUS_API int modbus_get_header_length(modbus_t *ctx);
  
  MODBUS_API int modbus_connect(modbus_t *ctx);
  MODBUS_API void modbus_close(modbus_t *ctx);
  
  MODBUS_API void modbus_free(modbus_t *ctx);
  
  MODBUS_API int modbus_flush(modbus_t *ctx);
  MODBUS_API int modbus_set_debug(modbus_t *ctx, int flag);
  
  MODBUS_API const char *modbus_strerror(int errnum);
  
  MODBUS_API int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
  MODBUS_API int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
  MODBUS_API int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
  MODBUS_API int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
  MODBUS_API int modbus_write_bit(modbus_t *ctx, int coil_addr, int status);
  MODBUS_API int modbus_write_register(modbus_t *ctx, int reg_addr, int value);
  MODBUS_API int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data);
  MODBUS_API int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data);
  MODBUS_API int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask);
  MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb,const uint16_t *src, int read_addr, int read_nb,uint16_t *dest);
  MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest);
  
  MODBUS_API modbus_mapping_t* modbus_mapping_new_start_address
  (
      unsigned int start_bits, unsigned int nb_bits,
      unsigned int start_input_bits, unsigned int nb_input_bits,
      unsigned int start_registers, unsigned int nb_registers,
      unsigned int start_input_registers, unsigned int nb_input_registers
  );
  
  MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers);
  MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping);
  
  MODBUS_API int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length);
  
  MODBUS_API int modbus_receive(modbus_t *ctx, uint8_t *req);
  
  MODBUS_API int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp);
  
  MODBUS_API int modbus_reply(modbus_t *ctx, const uint8_t *req, int req_length, modbus_mapping_t *mb_mapping);
  MODBUS_API int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, unsigned int exception_code);
  
  /**
   * UTILS FUNCTIONS
   **/
  
  #define MODBUS_GET_HIGH_BYTE(data) (((data) >> 8) & 0xFF)
  #define MODBUS_GET_LOW_BYTE(data) ((data) & 0xFF)
  #define MODBUS_GET_INT64_FROM_INT16(tab_int16, index) \
      (((int64_t)tab_int16[(index)    ] << 48) + \
       ((int64_t)tab_int16[(index) + 1] << 32) + \
       ((int64_t)tab_int16[(index) + 2] << 16) + \
        (int64_t)tab_int16[(index) + 3])
  #define MODBUS_GET_INT32_FROM_INT16(tab_int16, index) ((tab_int16[(index)] << 16) + tab_int16[(index) + 1])
  #define MODBUS_GET_INT16_FROM_INT8(tab_int8, index) ((tab_int8[(index)] << 8) + tab_int8[(index) + 1])
  #define MODBUS_SET_INT16_TO_INT8(tab_int8, index, value) \
      do { \
          tab_int8[(index)] = (value) >> 8;  \
          tab_int8[(index) + 1] = (value) & 0xFF; \
      } while (0)
  #define MODBUS_SET_INT32_TO_INT16(tab_int16, index, value) \
      do { \
          tab_int16[(index)    ] = (value) >> 16; \
          tab_int16[(index) + 1] = (value); \
      } while (0)
  #define MODBUS_SET_INT64_TO_INT16(tab_int16, index, value) \
      do { \
          tab_int16[(index)    ] = (value) >> 48; \
          tab_int16[(index) + 1] = (value) >> 32; \
          tab_int16[(index) + 2] = (value) >> 16; \
          tab_int16[(index) + 3] = (value); \
      } while (0)
  
  MODBUS_API void modbus_set_bits_from_byte(uint8_t *dest, int idx, const uint8_t value);
  MODBUS_API void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int nb_bits,
                                         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"
  
  MODBUS_END_DECLS