Agile Modbus  1.1.4
Lightweight modbus protocol stack.
agile_modbus_slave_util.c
Go to the documentation of this file.
1 
14 #include "agile_modbus.h"
16 #include <string.h>
17 
37 static const agile_modbus_slave_util_map_t *get_map_by_addr(const agile_modbus_slave_util_map_t *maps, int nb_maps, int address)
38 {
39  for (int i = 0; i < nb_maps; i++) {
40  const agile_modbus_slave_util_map_t *map = &maps[i];
41  if (address >= map->start_addr && address <= map->end_addr)
42  return map;
43  }
44 
45  return NULL;
46 }
47 
58 static int read_registers(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const agile_modbus_slave_util_t *slave_util)
59 {
60  uint8_t map_buf[AGILE_MODBUS_MAX_PDU_LENGTH];
61  int function = slave_info->sft->function;
62  int address = slave_info->address;
63  int nb = slave_info->nb;
64  int send_index = slave_info->send_index;
65  const agile_modbus_slave_util_map_t *maps = NULL;
66  int nb_maps = 0;
67 
68  switch (function) {
70  maps = slave_util->tab_bits;
71  nb_maps = slave_util->nb_bits;
72  } break;
73 
75  maps = slave_util->tab_input_bits;
76  nb_maps = slave_util->nb_input_bits;
77  } break;
78 
80  maps = slave_util->tab_registers;
81  nb_maps = slave_util->nb_registers;
82  } break;
83 
85  maps = slave_util->tab_input_registers;
86  nb_maps = slave_util->nb_input_registers;
87  } break;
88 
89  default:
91  }
92 
93  if (maps == NULL)
94  return 0;
95 
96  for (int now_address = address, i = 0; now_address < address + nb; now_address++, i++) {
97  const agile_modbus_slave_util_map_t *map = get_map_by_addr(maps, nb_maps, now_address);
98  if (map == NULL)
99  continue;
100 
101  int map_len = map->end_addr - now_address + 1;
102  if (map->get) {
103  memset(map_buf, 0, sizeof(map_buf));
104  map->get(map_buf, sizeof(map_buf));
105  int index = now_address - map->start_addr;
106  int need_len = address + nb - now_address;
107  if (need_len > map_len) {
108  need_len = map_len;
109  }
110 
111  if (function == AGILE_MODBUS_FC_READ_COILS || function == AGILE_MODBUS_FC_READ_DISCRETE_INPUTS) {
112  uint8_t *ptr = map_buf;
113  for (int j = 0; j < need_len; j++) {
114  agile_modbus_slave_io_set(ctx->send_buf + send_index, i + j, ptr[index + j]);
115  }
116  } else {
117  uint16_t *ptr = (uint16_t *)map_buf;
118  for (int j = 0; j < need_len; j++) {
119  agile_modbus_slave_register_set(ctx->send_buf + send_index, i + j, ptr[index + j]);
120  }
121  }
122  }
123 
124  now_address += map_len - 1;
125  i += map_len - 1;
126  }
127 
128  return 0;
129 }
130 
141 static int write_registers(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const agile_modbus_slave_util_t *slave_util)
142 {
143  uint8_t map_buf[AGILE_MODBUS_MAX_PDU_LENGTH];
144  int function = slave_info->sft->function;
145  int address = slave_info->address;
146  int nb = 0;
147  const agile_modbus_slave_util_map_t *maps = NULL;
148  int nb_maps = 0;
149  (void)ctx;
150  switch (function) {
153  maps = slave_util->tab_bits;
154  nb_maps = slave_util->nb_bits;
155  if (function == AGILE_MODBUS_FC_WRITE_SINGLE_COIL) {
156  nb = 1;
157  } else {
158  nb = slave_info->nb;
159  }
160  } break;
161 
164  maps = slave_util->tab_registers;
165  nb_maps = slave_util->nb_registers;
166  if (function == AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER) {
167  nb = 1;
168  } else {
169  nb = slave_info->nb;
170  }
171  } break;
172 
173  default:
175  }
176 
177  if (maps == NULL)
178  return 0;
179 
180  for (int now_address = address, i = 0; now_address < address + nb; now_address++, i++) {
181  const agile_modbus_slave_util_map_t *map = get_map_by_addr(maps, nb_maps, now_address);
182  if (map == NULL)
183  continue;
184 
185  int map_len = map->end_addr - now_address + 1;
186  if (map->set) {
187  memset(map_buf, 0, sizeof(map_buf));
188  if (map->get) {
189  map->get(map_buf, sizeof(map_buf));
190  }
191 
192  int index = now_address - map->start_addr;
193  int need_len = address + nb - now_address;
194  if (need_len > map_len) {
195  need_len = map_len;
196  }
197 
199  uint8_t *ptr = map_buf;
200  if (function == AGILE_MODBUS_FC_WRITE_SINGLE_COIL) {
201  int data = *((int *)slave_info->buf);
202  ptr[index] = data;
203  } else {
204  for (int j = 0; j < need_len; j++) {
205  uint8_t data = agile_modbus_slave_io_get(slave_info->buf, i + j);
206  ptr[index + j] = data;
207  }
208  }
209  } else {
210  uint16_t *ptr = (uint16_t *)map_buf;
211  if (function == AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER) {
212  int data = *((int *)slave_info->buf);
213  ptr[index] = data;
214  } else {
215  for (int j = 0; j < need_len; j++) {
216  uint16_t data = agile_modbus_slave_register_get(slave_info->buf, i + j);
217  ptr[index + j] = data;
218  }
219  }
220  }
221 
222  int rc = map->set(index, need_len, map_buf, sizeof(map_buf));
223  if (rc != 0)
224  return rc;
225  }
226 
227  now_address += map_len - 1;
228  i += map_len - 1;
229  }
230 
231  return 0;
232 }
233 
244 static int mask_write_register(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const agile_modbus_slave_util_t *slave_util)
245 {
246  uint8_t map_buf[AGILE_MODBUS_MAX_PDU_LENGTH];
247  int address = slave_info->address;
248  const agile_modbus_slave_util_map_t *maps = slave_util->tab_registers;
249  int nb_maps = slave_util->nb_registers;
250  (void)ctx;
251  if (maps == NULL)
252  return 0;
253 
254  const agile_modbus_slave_util_map_t *map = get_map_by_addr(maps, nb_maps, address);
255  if (map == NULL)
256  return 0;
257 
258  if (map->set) {
259  memset(map_buf, 0, sizeof(map_buf));
260  if (map->get) {
261  map->get(map_buf, sizeof(map_buf));
262  }
263 
264  int index = address - map->start_addr;
265  uint16_t *ptr = (uint16_t *)map_buf;
266  uint16_t data = ptr[index];
267  uint16_t and = (slave_info->buf[0] << 8) + slave_info->buf[1];
268  uint16_t or = (slave_info->buf[2] << 8) + slave_info->buf[3];
269 
270  data = (data & and) | (or &(~and));
271  ptr[index] = data;
272 
273  int rc = map->set(index, 1, map_buf, sizeof(map_buf));
274  if (rc != 0)
275  return rc;
276  }
277 
278  return 0;
279 }
280 
291 static int write_read_registers(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const agile_modbus_slave_util_t *slave_util)
292 {
293  uint8_t map_buf[AGILE_MODBUS_MAX_PDU_LENGTH];
294  int address = slave_info->address;
295  int nb = (slave_info->buf[0] << 8) + slave_info->buf[1];
296  int address_write = (slave_info->buf[2] << 8) + slave_info->buf[3];
297  int nb_write = (slave_info->buf[4] << 8) + slave_info->buf[5];
298  int send_index = slave_info->send_index;
299 
300  const agile_modbus_slave_util_map_t *maps = slave_util->tab_registers;
301  int nb_maps = slave_util->nb_registers;
302 
303  if (maps == NULL)
304  return 0;
305 
306  /* Write first. 7 is the offset of the first values to write */
307  for (int now_address = address_write, i = 0; now_address < address_write + nb_write; now_address++, i++) {
308  const agile_modbus_slave_util_map_t *map = get_map_by_addr(maps, nb_maps, now_address);
309  if (map == NULL)
310  continue;
311 
312  int map_len = map->end_addr - now_address + 1;
313  if (map->set) {
314  memset(map_buf, 0, sizeof(map_buf));
315  if (map->get) {
316  map->get(map_buf, sizeof(map_buf));
317  }
318 
319  int index = now_address - map->start_addr;
320  uint16_t *ptr = (uint16_t *)map_buf;
321  int need_len = address_write + nb_write - now_address;
322  if (need_len > map_len) {
323  need_len = map_len;
324  }
325 
326  for (int j = 0; j < need_len; j++) {
327  uint16_t data = agile_modbus_slave_register_get(slave_info->buf + 7, i + j);
328  ptr[index + j] = data;
329  }
330 
331  int rc = map->set(index, need_len, map_buf, sizeof(map_buf));
332  if (rc != 0)
333  return rc;
334  }
335 
336  now_address += map_len - 1;
337  i += map_len - 1;
338  }
339 
340  /* and read the data for the response */
341  for (int now_address = address, i = 0; now_address < address + nb; now_address++, i++) {
342  const agile_modbus_slave_util_map_t *map = get_map_by_addr(maps, nb_maps, now_address);
343  if (map == NULL)
344  continue;
345 
346  int map_len = map->end_addr - now_address + 1;
347  if (map->get) {
348  memset(map_buf, 0, sizeof(map_buf));
349  map->get(map_buf, sizeof(map_buf));
350  int index = now_address - map->start_addr;
351  uint16_t *ptr = (uint16_t *)map_buf;
352  int need_len = address + nb - now_address;
353  if (need_len > map_len) {
354  need_len = map_len;
355  }
356 
357  for (int j = 0; j < need_len; j++) {
358  agile_modbus_slave_register_set(ctx->send_buf + send_index, i + j, ptr[index + j]);
359  }
360  }
361 
362  now_address += map_len - 1;
363  i += map_len - 1;
364  }
365 
366  return 0;
367 }
368 
387 int agile_modbus_slave_util_callback(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const void *data)
388 {
389  int function = slave_info->sft->function;
390  int ret = 0;
391  const agile_modbus_slave_util_t *slave_util = (const agile_modbus_slave_util_t *)data;
392 
393  if (slave_util == NULL)
394  return 0;
395 
396  if (slave_util->addr_check) {
397  ret = slave_util->addr_check(ctx, slave_info);
398  if (ret != 0)
399  return ret;
400  }
401 
402  switch (function) {
407  ret = read_registers(ctx, slave_info, slave_util);
408  break;
409 
414  ret = write_registers(ctx, slave_info, slave_util);
415  break;
416 
418  ret = mask_write_register(ctx, slave_info, slave_util);
419  break;
420 
422  ret = write_read_registers(ctx, slave_info, slave_util);
423  break;
424 
425  default: {
426  if (slave_util->special_function) {
427  ret = slave_util->special_function(ctx, slave_info);
428  } else {
430  }
431  } break;
432  }
433 
434  if (slave_util->done) {
435  slave_util->done(ctx, slave_info, ret);
436  }
437 
438  return ret;
439 }
440 
Agile Modbus software package common header file.
The simple slave access header file provided by the Agile Modbus software package.
@ AGILE_MODBUS_EXCEPTION_ILLEGAL_FUNCTION
Definition: agile_modbus.h:147
#define AGILE_MODBUS_MAX_PDU_LENGTH
Definition: agile_modbus.h:116
#define AGILE_MODBUS_FC_MASK_WRITE_REGISTER
Definition: agile_modbus.h:58
#define AGILE_MODBUS_FC_READ_COILS
Definition: agile_modbus.h:48
#define AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER
Definition: agile_modbus.h:53
#define AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS
Definition: agile_modbus.h:55
#define AGILE_MODBUS_FC_WRITE_SINGLE_COIL
Definition: agile_modbus.h:52
#define AGILE_MODBUS_FC_READ_HOLDING_REGISTERS
Definition: agile_modbus.h:50
#define AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS
Definition: agile_modbus.h:59
#define AGILE_MODBUS_FC_READ_INPUT_REGISTERS
Definition: agile_modbus.h:51
#define AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS
Definition: agile_modbus.h:56
#define AGILE_MODBUS_FC_READ_DISCRETE_INPUTS
Definition: agile_modbus.h:49
int agile_modbus_slave_util_callback(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const void *data)
Slave callback function.
static const agile_modbus_slave_util_map_t * get_map_by_addr(const agile_modbus_slave_util_map_t *maps, int nb_maps, int address)
Get the mapping object from the mapping object array according to the register address.
static int write_registers(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const agile_modbus_slave_util_t *slave_util)
write register
static int read_registers(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const agile_modbus_slave_util_t *slave_util)
read register
static int mask_write_register(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const agile_modbus_slave_util_t *slave_util)
mask write register
static int write_read_registers(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const agile_modbus_slave_util_t *slave_util)
Write and read registers.
uint8_t agile_modbus_slave_io_get(uint8_t *buf, int index)
Read slave IO status.
void agile_modbus_slave_io_set(uint8_t *buf, int index, int status)
slave IO settings
uint16_t agile_modbus_slave_register_get(uint8_t *buf, int index)
Read slave register data.
void agile_modbus_slave_register_set(uint8_t *buf, int index, uint16_t data)
slave register settings
int function
function code
Definition: agile_modbus.h:189
Agile Modbus slave information structure.
Definition: agile_modbus.h:246
uint8_t * buf
Data fields required for different function codes.
Definition: agile_modbus.h:251
int send_index
Current index of sending buffer.
Definition: agile_modbus.h:252
agile_modbus_sft_t * sft
sft structure pointer
Definition: agile_modbus.h:247
int address
Register address.
Definition: agile_modbus.h:249
slave register mapping structure
int(* get)(void *buf, int bufsz)
Get register data interface.
int(* set)(int index, int len, void *buf, int bufsz)
Set register data interface.
slave function structure
int(* addr_check)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info)
Address checking interface.
int nb_input_registers
Input register definition array number.
int nb_bits
The number of coil register definition arrays.
const agile_modbus_slave_util_map_t * tab_input_registers
Input register definition array.
int(* special_function)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info)
Special function code processing interface.
int nb_input_bits
The number of discrete input register definition arrays.
const agile_modbus_slave_util_map_t * tab_input_bits
Discrete input register definition array.
int(* done)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, int ret)
Processing end interface.
int nb_registers
Number of holding register definition arrays.
const agile_modbus_slave_util_map_t * tab_bits
Coil register definition array.
const agile_modbus_slave_util_map_t * tab_registers
Holding register definition array.
Agile Modbus structure.
Definition: agile_modbus.h:217
uint8_t * send_buf
Send buffer.
Definition: agile_modbus.h:219