Skip to content

Commit 2df9d0e

Browse files
committed
independent instance command handling using lists, fixes as per review and test
1 parent ddb7315 commit 2df9d0e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+823
-506
lines changed

CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# The following five lines of boilerplate have to be in your project's
22
# CMakeLists in this exact order for cmake to work correctly
33
set(srcs
4+
"mb_controller/common/esp_modbus_common.c"
45
"mb_controller/common/esp_modbus_master.c"
56
"mb_controller/common/esp_modbus_slave.c"
67
"mb_controller/common/esp_modbus_master_serial.c"
@@ -13,6 +14,7 @@ set(srcs
1314
"mb_controller/tcp/mbc_tcp_slave.c"
1415
"mb_objects/mb_master.c"
1516
"mb_objects/mb_slave.c"
17+
"mb_objects/functions/mbfunc_handling.c"
1618
"mb_objects/functions/mbfunccoils_master.c"
1719
"mb_objects/functions/mbfunccoils.c"
1820
"mb_objects/functions/mbfuncdiag.c"

Kconfig

+1-10
Original file line numberDiff line numberDiff line change
@@ -224,18 +224,9 @@ menu "Modbus configuration"
224224
otherwise the only legacy types are supported. The extended types include
225225
integer, float, double types with different endianness and size.
226226

227-
config FMB_CONTROLLER_SLAVE_ID_MAX_SIZE
228-
int "Modbus Slave ID maximum buffer size (bytes)"
229-
range 4 255
230-
default 32
231-
depends on FMB_CONTROLLER_SLAVE_ID_SUPPORT
232-
help
233-
Modbus slave ID buffer size used to store vendor specific ID information
234-
for the <Report Slave ID> command.
235-
236227
config FMB_FUNC_HANDLERS_MAX
237228
int "Maximum number of Modbus function handlers"
238-
range 16 64
229+
range 16 255
239230
default 16
240231
help
241232
This option defines the maximum number of Modbus command handlers for Modbus master and slave.

docs/en/applications_and_references.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,11 @@ The examples below demonstrate the library port for serial, TCP slave and master
4848

4949
.. _example_mb_tcp_master:
5050

51-
- `Modbus TCP master example <https://github.com/espressif/esp-modbus/tree/main/examples/tcp/mb_tcp_slave>`__
51+
- `Modbus TCP master example <https://github.com/espressif/esp-modbus/tree/main/examples/tcp/mb_tcp_master>`__
5252

5353
.. _example_mb_tcp_slave:
5454

55-
- `Modbus TCP slave example <https://github.com/espressif/esp-modbus/tree/main/examples/tcp/mb_tcp_master>`__
55+
- `Modbus TCP slave example <https://github.com/espressif/esp-modbus/tree/main/examples/tcp/mb_tcp_slave>`__
5656

5757
Please refer to the specific example README.md for details.
5858

docs/en/master_api_overview.rst

+51-28
Original file line numberDiff line numberDiff line change
@@ -313,38 +313,60 @@ Master Customize Function Handlers
313313

314314
The Master object contains the command handling tables to define the specific handling functionality for each supported Modbus command. The default handling functions in this table support most common Modbus commands. However, the list of commands can be extended by adding the new command into handling table with its custom handling behavior. It is also possible overriding the function handler for the specific command. The below described API functions allow using this behavior for master objects.
315315

316-
:cpp:func:`mbc_master_set_handler`
316+
:cpp:func:`mbc_set_handler`
317317

318-
:cpp:func:`mbc_master_get_handler`
318+
The function adds new handler for the function or overrides the existing handler for the function.
319319

320-
The example code to overide the handler routine for command `0x04 - Read Input Registers`:
320+
:cpp:func:`mbc_get_handler`
321+
322+
The function returns the handler for the specified function code from handling table. Allows to keep and use the predefined handlers for standard functions.
323+
324+
:cpp:func:`mbc_delete_handler`
325+
326+
The function allows to delete the handler for specified command and free the handler table entry for this.
327+
328+
:cpp:func:`mbc_get_handler_count`
329+
330+
The function returns the actual number of command handlers registered for the object reffered by parameter.
331+
332+
The example code to override the handler routine for command `0x04 - Read Input Registers` is below. Please refer to the existing handler :cpp:func:`mbm_fn_read_inp_reg` for more information.
321333

322334
.. code:: c
323335
324336
static void *master_handle = NULL; // Pointer to allocated interface structure
325-
uint8_t override_command = 0x04;
337+
const uint8_t override_command = 0x04;
338+
mb_fn_handler_fp pstandard_handler = NULL;
326339
....
327-
// Define the custom function handler for the command.
328-
// The handler body must be short and don't use any unpredictable logic. The handler
329-
// is executed in the context of modbus controller event task.
340+
// This is the custom function handler for the command.
341+
// The handler is executed from the context of modbus controller event task and should be as simple as possible.
342+
// Parameters: frame_ptr - the pointer to the incoming ADU frame from slave starting from function code,
343+
// plen - the pointer to length of the frame. After return from the handler the modbus object will
344+
// handle the end of transaction according to the exception returned.
330345
mb_exception_t my_custom_fc04_handler(void *pinst, uint8_t *frame_ptr, uint16_t *plen)
331346
{
332-
MB_RETURN_ON_FALSE(frame_ptr && plen, MB_EX_CRITICAL, TAG,
333-
"incorrect frame buffer length");
334-
// This error handler will be executed to check the request for the command 0x04
335-
// See the default handler in the file `esp-modbus//modbus/mb_objects/functions/mbfuncinput_master.c` for more information.
336-
// The pframe is pointer to command buffer, plen - is pointer to length of the buffer
337-
return MB_EX_CRITICAL;
347+
mb_exception_t exception = MB_EX_CRITICAL;
348+
MB_RETURN_ON_FALSE(frame_ptr && plen, exception, TAG, "incorrect frame buffer length");
349+
// Place the custom behavior here
350+
if (pstandard_handler) {
351+
exception = pstandard_handler(pinst, frame_ptr, plen); // invoke standard behavior with mapping
352+
}
353+
return exception;
338354
}
339355
....
340-
err = mbc_master_set_handler(master_handle, override_command, NULL);
356+
// Get the standard handler for the command to use it in the handler.
357+
err = mbc_get_handler(master_handle, custom_command, &pstandard_handler);
341358
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
342-
"could not override handler, returned (0x%x).", (int)err);
343-
err = mbc_master_set_handler(master_handle, override_command, my_custom_fc04_handler);
359+
"could not get handler for command %d, returned (0x%x).", (int)custom_command, (int)err);
360+
// The second parameter = NULL, means reset the handler for specified command.
361+
err = mbc_delete_handler(master_handle, override_command);
362+
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
363+
"could not reset handler, returned (0x%x).", (int)err);
364+
// Set the new handler for the standard command
365+
err = mbc_set_handler(master_handle, override_command, my_custom_fc04_handler);
344366
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
345367
"could not override handler, returned (0x%x).", (int)err);
346368
347-
.. note:: The custom handler set by the function :cpp:func:`mbc_master_set_handler` should be as short as possible and should contain simple and safe logic to not break the normal functionality of the stack. This is user application responsibility to handle the command appropriately.
369+
.. note:: The custom handler set by the function :cpp:func:`mbc_set_handler` should be as short as possible and should contain simple and safe logic to not break the normal functionality of the stack. This is user application responsibility to handle the command appropriately.
348370

349371
The example code to handle custom vendor specific command is below. This example sends the 'Master' string to slave and gets the response from slave with the string being appended from slave. It is just a simple echo example to demonstrate the approach.
350372

@@ -355,16 +377,15 @@ The example code to handle custom vendor specific command is below. This example
355377
static void *master_handle = NULL; // Pointer to allocated interface structure
356378
357379
// This is the custom function handler to process incoming slave response.
358-
// Refer the function handler examples in `esp-modbus/modbus/mb_objects/functions/mbfuncinput_master.c` for more information.
359-
// Parameters: pframe: is pointer to incoming frame buffer, plen: is pointer to length including the function code
360-
// In spite of logging showed here, try to use just simple functionality here.
380+
// Parameters: frame_ptr: is a pointer to incoming frame buffer, plen: is pointer to length including the function code
381+
// In spite of logging showed here, try to use just simple functionality in the handler.
361382
mb_exception_t my_custom_fc_handler(void *pinst, uint8_t *frame_ptr, uint16_t *plen)
362383
{
363-
MB_RETURN_ON_FALSE((frame_ptr && plen && *plen && *plen < (MB_CUST_DATA_LEN - 1)), MB_EX_CRITICAL, TAG,
384+
MB_RETURN_ON_FALSE((frame_ptr && plen && *plen && *plen < (MB_CUST_DATA_LEN - 1)), MB_EX_ILLEGAL_DATA_VALUE, TAG,
364385
"incorrect custom frame buffer");
365-
ESP_LOGW(TAG, "Custom handler, Frame ptr: %p, len: %u", frame_ptr, *plen);
386+
ESP_LOGI(TAG, "Custom handler, Frame ptr: %p, len: %u", frame_ptr, *plen);
366387
strncpy((char *)&my_custom_data[0], (char *)&frame_ptr[1], MB_CUST_DATA_LEN);
367-
ESP_LOG_BUFFER_HEXDUMP("CUSTOM_DATA", &my_custom_data[0], (*plen - 1), ESP_LOG_WARN);
388+
ESP_LOG_BUFFER_HEXDUMP("CUSTOM_DATA", &my_custom_data[0], (*plen - 1), ESP_LOG_INFO);
368389
return MB_EX_NONE;
369390
}
370391
....
@@ -373,15 +394,15 @@ The example code to handle custom vendor specific command is below. This example
373394
// Add custom command handler
374395
uint8_t custom_command = 0x41; // the function code for the request
375396
// Reset the handler for the command if already set
376-
err = mbc_master_set_handler(master_handle, custom_command, NULL);
397+
err = mbc_delete_handler(master_handle, custom_command);
377398
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_INVALID_STATE), ESP_ERR_INVALID_STATE, TAG,
378399
"could not override handler, returned (0x%x).", (int)err);
379-
err = mbc_master_set_handler(master_handle, custom_command, my_custom_fc_handler);
400+
err = mbc_set_handler(master_handle, custom_command, my_custom_fc_handler);
380401
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
381402
"could not override handler, returned (0x%x).", (int)err);
382403
mb_fn_handler_fp phandler = NULL;
383404
// Make sure the handler is updated correctly
384-
err = mbc_master_get_handler(master_handle, custom_command, &phandler);
405+
err = mbc_get_handler(master_handle, custom_command, &phandler);
385406
MB_RETURN_ON_FALSE((err == ESP_OK && phandler == my_custom_fc_handler), ESP_ERR_INVALID_STATE, TAG,
386407
"could not get handler for command %d, returned (0x%x).", (int)custom_command, (int)err);
387408
@@ -398,10 +419,12 @@ The example code to handle custom vendor specific command is below. This example
398419
if (err != ESP_OK) {
399420
ESP_LOGE("CUSTOM_DATA", "Send custom request fail.");
400421
} else {
401-
// The request is processed correctly and the `my_custom_data[]` contains the sent string with appended slave string
402-
...
422+
// The request is processed correctly and the `my_custom_data[]` contains the sent string with appended slave string
423+
...
403424
}
404425
426+
Refer to :ref:`example TCP master <example_mb_tcp_master>` for more information.
427+
405428
.. _modbus_api_master_start_communication:
406429

407430
Master Communication

docs/en/slave_api_overview.rst

+40-15
Original file line numberDiff line numberDiff line change
@@ -167,46 +167,71 @@ Example to get the actual slave identificator:
167167
Slave Customize Function Handlers
168168
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
169169

170-
The Slave object contains the command handling tables to define the specific handling functionality for each supported Modbus command. The default handling functions in this table support most useful Modbus commands. However, the list of commands can be extended by adding the new command into handling table with its custom handling behavior. It is also possible overriding the function handler for the specific command. The below described API functions allow using this behavior slave objects.
170+
The Slave object contains the command handling tables to define the specific handling functionality for each supported Modbus command. The default handling functions in this table support most useful Modbus commands. However, the list of commands can be extended by adding the new command into handling table with its custom handling behavior. It is also possible overriding the function handler for the specific command. The below described API functions allow using this behavior for slave objects.
171171

172-
:cpp:func:`mbc_slave_set_handler`
172+
:cpp:func:`mbc_set_handler`
173173

174-
:cpp:func:`mbc_slave_get_handler`
174+
The function adds new handler for the function or overrides the existing handler for the function.
175175

176-
The following example allows to override the standard command to read input registers. Refer to examples for more information on how to handle custom commands.
176+
:cpp:func:`mbc_get_handler`
177+
178+
The function returns the handler for the specified function code from handling table. Allows to keep and use the predefined handlers for standard functions.
179+
180+
:cpp:func:`mbc_delete_handler`
181+
182+
The function allows to delete the handler for specified command and free the handler table entry for this.
183+
184+
:cpp:func:`mbc_get_handler_count`
185+
186+
The function returns the actual number of command handlers registered for the object reffered by parameter.
187+
188+
The following example allows to override the standard command to read input registers. Refer to standard handler function :cpp:func:`mbs_fn_read_input_reg` for more information on how to handle custom commands.
177189

178190
.. code:: c
179191
180192
static void *slave_handle = NULL; // Pointer to allocated interface structure (must be actual)
193+
mb_fn_handler_fp pstandard_handler = NULL;
181194
....
182-
// The custom function handler for the function returns exception code for now
183-
// Please place your custom handling behavior here.
184-
// This error handler will be executed to check the request for the command 0x04
185-
// See the default handler in the file `esp-modbus//modbus/mb_objects/functions/mbfuncinput_slave.c` for more information.
186-
// The pframe is pointer to command buffer, plen - is pointer to the variable with the length of the buffer
195+
// This is the custom function handler for the command.
196+
// The handler is executed from the context of modbus controller event task and should be as simple as possible.
197+
// Parameters: frame_ptr - the pointer to the incoming ADU request frame from master starting from function code,
198+
// plen - the pointer to length of the frame. The handler body can override the buffer and return the length of data.
199+
// After return from the handler the modbus object will handle the end of transaction according to the exception returned,
200+
// then builds the response frame and send it back to the master. If the whole transaction time including the response
201+
// latency exceeds the configured slave response time set in the master configuration the master will ignore the transaction.
187202
mb_exception_t my_custom_fc04_handler(void *pinst, uint8_t *frame_ptr, uint16_t *plen)
188203
{
189204
MB_RETURN_ON_FALSE(frame_ptr && plen, MB_EX_CRITICAL, TAG,
190205
"incorrect frame buffer length");
191-
return MB_EX_CRITICAL;
206+
// Place the custom behavior to process the buffer here
207+
if (pstandard_handler) {
208+
exception = pstandard_handler(pinst, frame_ptr, plen); // invoke standard behavior with mapping
209+
}
210+
return exception;
192211
}
193212
...
194-
uint8_t override_command = 0x04;
213+
const uint8_t override_command = 0x04;
214+
// Get the standard handler for the command to use it in the handler.
215+
err = mbc_get_handler(master_handle, override_command, &pstandard_handler);
216+
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
217+
"could not get handler for command %d, returned (0x%x).", (int)override_command, (int)err);
195218
// Reset the existing handler for the command
196-
esp_err_t err = mbc_slave_set_handler(slave_handle, override_command, NULL);
219+
esp_err_t err = mbc_delete_handler(slave_handle, override_command);
197220
MB_RETURN_ON_FALSE((err == ESP_OK), ;, TAG,
198221
"could not reset handler, returned (0x%x).", (int)err);
199222
// Set the custom handler function for the command
200-
err = mbc_slave_set_handler(slave_handle, override_command, my_custom_fc04_handler);
223+
err = mbc_set_handler(slave_handle, override_command, my_custom_fc04_handler);
201224
MB_RETURN_ON_FALSE((err == ESP_OK), ;, TAG,
202225
"could not override handler, returned (0x%x).", (int)err);
203226
mb_fn_handler_fp phandler = NULL;
204227
// Get the actual handler for the command
205-
err = mbc_slave_get_handler(slave_handle, override_command, &phandler);
228+
err = mbc_get_handler(slave_handle, override_command, &phandler);
206229
MB_RETURN_ON_FALSE((err == ESP_OK && phandler == my_custom_fc04_handler), ;, TAG,
207230
"could not get handler, returned (0x%x).", (int)err);
208231
209-
.. note:: The custom handlers set by the function :cpp:func:`mbc_slave_set_handler` should be as short as possible and should contain simple logic to not break the normal functionality of the stack. This is user application responsibility to handle the command appropriately.
232+
Refer to :ref:`example TCP slave <example_mb_tcp_slave>` for more information.
233+
234+
.. note:: The custom handlers set by the function :cpp:func:`mbc_set_handler` should be as short as possible, contain simple and safe logic and avoid blocking calls to not break the normal functionality of the stack. The possible latency in this handler may prevent to respond properly to the master request which waits for response during the slave response time configured in the configuration structure. If the slave does not respond to the master during the slave response time the master will report timeout failure and ignores the late response. This is user application responsibility to handle the command appropriately.
210235

211236
.. _modbus_api_slave_communication:
212237

0 commit comments

Comments
 (0)