Skip to content

Commit 20b3dba

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

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

+845
-542
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

+50-32
Original file line numberDiff line numberDiff line change
@@ -313,38 +313,56 @@ 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 the command `<0x04 - Read Input Registers>` is below. This example allows to perform a custom action and then calls the standard handler, which maps the device data to the command buffer from the actual parameter. This is just recommended behavior for handling functions, but users can change the order of the calls if absolutely required. 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+
// It is the possible place for the custom behavior
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+
// This call overrides the handler for the standard command.
361+
err = mbc_set_handler(master_handle, override_command, my_custom_fc04_handler);
344362
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
345363
"could not override handler, returned (0x%x).", (int)err);
346364
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.
365+
.. 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.
348366

349367
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.
350368

@@ -355,33 +373,29 @@ The example code to handle custom vendor specific command is below. This example
355373
static void *master_handle = NULL; // Pointer to allocated interface structure
356374
357375
// 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.
376+
// Parameters: frame_ptr: is a pointer to incoming frame buffer, plen: is pointer to length including the function code
377+
// In spite of logging showed here, try to use just simple functionality in the handler.
361378
mb_exception_t my_custom_fc_handler(void *pinst, uint8_t *frame_ptr, uint16_t *plen)
362379
{
363-
MB_RETURN_ON_FALSE((frame_ptr && plen && *plen && *plen < (MB_CUST_DATA_LEN - 1)), MB_EX_CRITICAL, TAG,
380+
MB_RETURN_ON_FALSE((frame_ptr && plen && *plen && *plen < (MB_CUST_DATA_LEN - 1)), MB_EX_ILLEGAL_DATA_VALUE, TAG,
364381
"incorrect custom frame buffer");
365-
ESP_LOGW(TAG, "Custom handler, Frame ptr: %p, len: %u", frame_ptr, *plen);
382+
ESP_LOGI(TAG, "Custom handler, Frame ptr: %p, len: %u", frame_ptr, *plen);
366383
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);
384+
ESP_LOG_BUFFER_HEXDUMP("CUSTOM_DATA", &my_custom_data[0], (*plen - 1), ESP_LOG_INFO);
368385
return MB_EX_NONE;
369386
}
370387
....
371388
// The setup of the master object is completed and the master_handle is already actual
372389
373390
// Add custom command handler
374-
uint8_t custom_command = 0x41; // the function code for the request
375-
// Reset the handler for the command if already set
376-
err = mbc_master_set_handler(master_handle, custom_command, NULL);
377-
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_INVALID_STATE), ESP_ERR_INVALID_STATE, TAG,
378-
"could not override handler, returned (0x%x).", (int)err);
379-
err = mbc_master_set_handler(master_handle, custom_command, my_custom_fc_handler);
391+
const uint8_t custom_command = 0x41; // the function code for the request
392+
// Override or add new handler entry.
393+
err = mbc_set_handler(master_handle, custom_command, my_custom_fc_handler);
380394
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
381395
"could not override handler, returned (0x%x).", (int)err);
382396
mb_fn_handler_fp phandler = NULL;
383397
// Make sure the handler is updated correctly
384-
err = mbc_master_get_handler(master_handle, custom_command, &phandler);
398+
err = mbc_get_handler(master_handle, custom_command, &phandler);
385399
MB_RETURN_ON_FALSE((err == ESP_OK && phandler == my_custom_fc_handler), ESP_ERR_INVALID_STATE, TAG,
386400
"could not get handler for command %d, returned (0x%x).", (int)custom_command, (int)err);
387401
@@ -394,14 +408,18 @@ The example code to handle custom vendor specific command is below. This example
394408
};
395409
396410
// Send the request with custom command (vendor speciic)
411+
// This function supports sending of even number of bytes
412+
// as instructed by req.reg_size (Modbus register = 2 bytes)
397413
err = mbc_master_send_request(master_handle, &req, pcustom_string);
398414
if (err != ESP_OK) {
399415
ESP_LOGE("CUSTOM_DATA", "Send custom request fail.");
400416
} else {
401-
// The request is processed correctly and the `my_custom_data[]` contains the sent string with appended slave string
402-
...
417+
// The request is processed correctly and the `my_custom_data[]` contains the sent string with appended slave string
418+
...
403419
}
404420
421+
Refer to :ref:`example Serial master <example_mb_master>` for more information.
422+
405423
.. _modbus_api_master_start_communication:
406424

407425
Master Communication

docs/en/slave_api_overview.rst

+41-21
Original file line numberDiff line numberDiff line change
@@ -167,46 +167,66 @@ 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
{
189-
MB_RETURN_ON_FALSE(frame_ptr && plen, MB_EX_CRITICAL, TAG,
190-
"incorrect frame buffer length");
191-
return MB_EX_CRITICAL;
204+
MB_RETURN_ON_FALSE(frame_ptr && plen, MB_EX_CRITICAL, TAG, "incorrect frame buffer length");
205+
// Place the custom behavior to process the buffer here
206+
if (pstandard_handler) {
207+
exception = pstandard_handler(pinst, frame_ptr, plen); // invoke standard behavior with mapping
208+
}
209+
return exception;
192210
}
193211
...
194-
uint8_t override_command = 0x04;
195-
// Reset the existing handler for the command
196-
esp_err_t err = mbc_slave_set_handler(slave_handle, override_command, NULL);
197-
MB_RETURN_ON_FALSE((err == ESP_OK), ;, TAG,
198-
"could not reset handler, returned (0x%x).", (int)err);
212+
const uint8_t override_command = 0x04;
213+
// Get the standard handler for the command to use it in the handler.
214+
err = mbc_get_handler(master_handle, override_command, &pstandard_handler);
215+
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
216+
"could not get handler for command %d, returned (0x%x).", (int)override_command, (int)err);
199217
// Set the custom handler function for the command
200-
err = mbc_slave_set_handler(slave_handle, override_command, my_custom_fc04_handler);
218+
err = mbc_set_handler(slave_handle, override_command, my_custom_fc04_handler);
201219
MB_RETURN_ON_FALSE((err == ESP_OK), ;, TAG,
202220
"could not override handler, returned (0x%x).", (int)err);
203221
mb_fn_handler_fp phandler = NULL;
204-
// Get the actual handler for the command
205-
err = mbc_slave_get_handler(slave_handle, override_command, &phandler);
222+
// Check the actual handler for the command
223+
err = mbc_get_handler(slave_handle, override_command, &phandler);
206224
MB_RETURN_ON_FALSE((err == ESP_OK && phandler == my_custom_fc04_handler), ;, TAG,
207225
"could not get handler, returned (0x%x).", (int)err);
208226
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.
227+
Refer to :ref:`example Serial slave <example_mb_slave>` for more information.
228+
229+
.. 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.
210230

211231
.. _modbus_api_slave_communication:
212232

0 commit comments

Comments
 (0)