Agile Modbus 1.1.4
Lightweight modbus protocol stack.
Loading...
Searching...
No Matches
agile_modbus_slave_util.c
Go to the documentation of this file.
1
14#include "agile_modbus.h"
16#include <string.h>
17
37static 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
58static 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
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
141static 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;
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;
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
244static 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
291static 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
387int 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
#define AGILE_MODBUS_MAX_PDU_LENGTH
#define AGILE_MODBUS_FC_MASK_WRITE_REGISTER
#define AGILE_MODBUS_FC_READ_COILS
#define AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER
#define AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS
#define AGILE_MODBUS_FC_WRITE_SINGLE_COIL
#define AGILE_MODBUS_FC_READ_HOLDING_REGISTERS
#define AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS
#define AGILE_MODBUS_FC_READ_INPUT_REGISTERS
#define AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS
#define AGILE_MODBUS_FC_READ_DISCRETE_INPUTS
int agile_modbus_slave_util_callback(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, const void *data)
Slave callback function.
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 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 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
Agile Modbus slave information structure.
uint8_t * buf
Data fields required for different function codes.
int send_index
Current index of sending buffer.
agile_modbus_sft_t * sft
sft structure pointer
int address
Register address.
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.
uint8_t * send_buf
Send buffer.