mbc_serial_master.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. /* Copyright 2018 Espressif Systems (Shanghai) PTE LTD
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. // mbc_serial_master.c
  16. // Serial master implementation of the Modbus controller
  17. #include <sys/time.h> // for calculation of time stamp in milliseconds
  18. #include "esp_log.h" // for log_write
  19. #include <string.h> // for memcpy
  20. #include "freertos/FreeRTOS.h" // for task creation and queue access
  21. #include "freertos/task.h" // for task api access
  22. #include "freertos/event_groups.h" // for event groups
  23. #include "freertos/queue.h" // for queue api access
  24. #include "mb_m.h" // for modbus stack master types definition
  25. #include "port.h" // for port callback functions
  26. #include "mbutils.h" // for mbutils functions definition for stack callback
  27. #include "sdkconfig.h" // for KConfig values
  28. #include "esp_modbus_common.h" // for common types
  29. #include "esp_modbus_master.h" // for public master types
  30. #include "mbc_master.h" // for private master types
  31. #include "mbc_serial_master.h" // for serial master create function and types
  32. // The Modbus Transmit Poll function defined in port
  33. extern BOOL xMBMasterPortSerialTxPoll(void);
  34. /*-----------------------Master mode use these variables----------------------*/
  35. #define MB_RESPONSE_TICS pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND + 10)
  36. static mb_master_interface_t* mbm_interface_ptr = NULL; //&default_interface_inst;
  37. // Modbus event processing task
  38. static void modbus_master_task(void *pvParameters)
  39. {
  40. // The interface must be initialized before start of state machine
  41. MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
  42. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  43. // Main Modbus stack processing cycle
  44. for (;;) {
  45. // Wait for poll events
  46. BaseType_t status = xEventGroupWaitBits(mbm_opts->mbm_event_group,
  47. (BaseType_t)(MB_EVENT_STACK_STARTED),
  48. pdFALSE, // do not clear bits
  49. pdFALSE,
  50. portMAX_DELAY);
  51. // Check if stack started then poll for data
  52. if (status & MB_EVENT_STACK_STARTED) {
  53. (void)eMBMasterPoll(); // Allow stack to process data
  54. // Send response buffer if ready to be sent
  55. BOOL xSentState = xMBMasterPortSerialTxPoll();
  56. if (xSentState) {
  57. // Let state machine know that request frame was transmitted out
  58. (void)xMBMasterPortEventPost(EV_MASTER_FRAME_SENT);
  59. }
  60. }
  61. }
  62. }
  63. // Setup Modbus controller parameters
  64. static esp_err_t mbc_serial_master_setup(void* comm_info)
  65. {
  66. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  67. ESP_ERR_INVALID_STATE,
  68. "Master interface uninitialized.");
  69. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  70. const mb_master_comm_info_t* comm_info_ptr = (mb_master_comm_info_t*)comm_info;
  71. // Check communication options
  72. MB_MASTER_CHECK(((comm_info_ptr->mode == MB_MODE_RTU) || (comm_info_ptr->mode == MB_MODE_ASCII)),
  73. ESP_ERR_INVALID_ARG, "mb incorrect mode = (0x%x).",
  74. (uint32_t)comm_info_ptr->mode);
  75. MB_MASTER_CHECK((comm_info_ptr->port <= UART_NUM_MAX), ESP_ERR_INVALID_ARG,
  76. "mb wrong port to set = (0x%x).", (uint32_t)comm_info_ptr->port);
  77. MB_MASTER_CHECK((comm_info_ptr->parity <= UART_PARITY_ODD), ESP_ERR_INVALID_ARG,
  78. "mb wrong parity option = (0x%x).", (uint32_t)comm_info_ptr->parity);
  79. // Save the communication options
  80. mbm_opts->mbm_comm = *(mb_communication_info_t*)comm_info_ptr;
  81. return ESP_OK;
  82. }
  83. // Modbus controller stack start function
  84. static esp_err_t mbc_serial_master_start(void)
  85. {
  86. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  87. ESP_ERR_INVALID_STATE,
  88. "Master interface uninitialized.");
  89. eMBErrorCode status = MB_EIO;
  90. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  91. const mb_communication_info_t* comm_info = (mb_communication_info_t*)&mbm_opts->mbm_comm;
  92. // Initialize Modbus stack using mbcontroller parameters
  93. status = eMBMasterSerialInit((eMBMode)comm_info->mode, (UCHAR)comm_info->port,
  94. (ULONG)comm_info->baudrate,
  95. MB_PORT_PARITY_GET(comm_info->parity));
  96. MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
  97. "mb stack initialization failure, eMBInit() returns (0x%x).", status);
  98. status = eMBMasterEnable();
  99. MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
  100. "mb stack set slave ID failure, eMBEnable() returned (0x%x).", (uint32_t)status);
  101. // Set the mbcontroller start flag
  102. EventBits_t flag = xEventGroupSetBits(mbm_opts->mbm_event_group,
  103. (EventBits_t)MB_EVENT_STACK_STARTED);
  104. MB_MASTER_CHECK((flag & MB_EVENT_STACK_STARTED),
  105. ESP_ERR_INVALID_STATE, "mb stack start event set error.");
  106. return ESP_OK;
  107. }
  108. // Modbus controller destroy function
  109. static esp_err_t mbc_serial_master_destroy(void)
  110. {
  111. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  112. ESP_ERR_INVALID_STATE,
  113. "Master interface uninitialized.");
  114. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  115. eMBErrorCode mb_error = MB_ENOERR;
  116. // Stop polling by clearing correspondent bit in the event group
  117. EventBits_t flag = xEventGroupClearBits(mbm_opts->mbm_event_group,
  118. (EventBits_t)MB_EVENT_STACK_STARTED);
  119. MB_MASTER_CHECK((flag & MB_EVENT_STACK_STARTED),
  120. ESP_ERR_INVALID_STATE, "mb stack stop event failure.");
  121. // Desable and then destroy the Modbus stack
  122. mb_error = eMBMasterDisable();
  123. MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, "mb stack disable failure.");
  124. (void)vTaskDelete(mbm_opts->mbm_task_handle);
  125. (void)vEventGroupDelete(mbm_opts->mbm_event_group);
  126. mb_error = eMBMasterClose();
  127. MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
  128. "mb stack close failure returned (0x%x).", (uint32_t)mb_error);
  129. free(mbm_interface_ptr); // free the memory allocated for options
  130. vMBPortSetMode((UCHAR)MB_PORT_INACTIVE);
  131. mbm_interface_ptr = NULL;
  132. return ESP_OK;
  133. }
  134. // Set Modbus parameter description table
  135. static esp_err_t mbc_serial_master_set_descriptor(const mb_parameter_descriptor_t* descriptor, const uint16_t num_elements)
  136. {
  137. MB_MASTER_CHECK((descriptor != NULL),
  138. ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
  139. MB_MASTER_CHECK((num_elements >= 1),
  140. ESP_ERR_INVALID_ARG, "mb table size is incorrect.");
  141. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  142. const mb_parameter_descriptor_t *reg_ptr = descriptor;
  143. // Go through all items in the table to check all Modbus registers
  144. for (uint16_t counter = 0; counter < (num_elements); counter++, reg_ptr++)
  145. {
  146. // Below is the code to check consistency of the table format and required fields.
  147. MB_MASTER_CHECK((reg_ptr->cid == counter),
  148. ESP_ERR_INVALID_ARG, "mb descriptor cid field is incorrect.");
  149. MB_MASTER_CHECK((reg_ptr->param_key != NULL),
  150. ESP_ERR_INVALID_ARG, "mb descriptor param key is incorrect.");
  151. MB_MASTER_CHECK((reg_ptr->mb_size > 0),
  152. ESP_ERR_INVALID_ARG, "mb descriptor param size is incorrect.");
  153. }
  154. mbm_opts->mbm_param_descriptor_table = descriptor;
  155. mbm_opts->mbm_param_descriptor_size = num_elements;
  156. return ESP_OK;
  157. }
  158. // Send custom Modbus request defined as mb_param_request_t structure
  159. static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, void* data_ptr)
  160. {
  161. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  162. ESP_ERR_INVALID_STATE,
  163. "Master interface uninitialized.");
  164. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  165. MB_MASTER_CHECK((request != NULL),
  166. ESP_ERR_INVALID_ARG, "mb request structure.");
  167. MB_MASTER_CHECK((data_ptr != NULL),
  168. ESP_ERR_INVALID_ARG, "mb incorrect data pointer.");
  169. eMBMasterReqErrCode mb_error = MB_MRE_NO_REG;
  170. esp_err_t error = ESP_FAIL;
  171. uint8_t mb_slave_addr = request->slave_addr;
  172. uint8_t mb_command = request->command;
  173. uint16_t mb_offset = request->reg_start;
  174. uint16_t mb_size = request->reg_size;
  175. // Set the buffer for callback function processing of received data
  176. mbm_opts->mbm_reg_buffer_ptr = (uint8_t*)data_ptr;
  177. mbm_opts->mbm_reg_buffer_size = mb_size;
  178. // Calls appropriate request function to send request and waits response
  179. switch(mb_command)
  180. {
  181. case MB_FUNC_READ_COILS:
  182. mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
  183. (USHORT)mb_size , (LONG)MB_RESPONSE_TICS );
  184. break;
  185. case MB_FUNC_WRITE_SINGLE_COIL:
  186. mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
  187. *(USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
  188. break;
  189. case MB_FUNC_WRITE_MULTIPLE_COILS:
  190. mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
  191. (USHORT)mb_size, (UCHAR*)data_ptr, (LONG)MB_RESPONSE_TICS);
  192. break;
  193. case MB_FUNC_READ_DISCRETE_INPUTS:
  194. mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
  195. (USHORT)mb_size, (LONG)MB_RESPONSE_TICS );
  196. break;
  197. case MB_FUNC_READ_HOLDING_REGISTER:
  198. mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
  199. (USHORT)mb_size, (LONG)MB_RESPONSE_TICS );
  200. break;
  201. case MB_FUNC_WRITE_REGISTER:
  202. mb_error = eMBMasterReqWriteHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
  203. *(USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
  204. break;
  205. case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
  206. mb_error = eMBMasterReqWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr,
  207. (USHORT)mb_offset, (USHORT)mb_size,
  208. (USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
  209. break;
  210. case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
  211. mb_error = eMBMasterReqReadWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
  212. (USHORT)mb_size, (USHORT*)data_ptr,
  213. (USHORT)mb_offset, (USHORT)mb_size,
  214. (LONG)MB_RESPONSE_TICS );
  215. break;
  216. case MB_FUNC_READ_INPUT_REGISTER:
  217. mb_error = eMBMasterReqReadInputRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
  218. (USHORT)mb_size, (LONG) MB_RESPONSE_TICS );
  219. break;
  220. default:
  221. ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect function in request (%u) ",
  222. __FUNCTION__, mb_command);
  223. mb_error = MB_MRE_NO_REG;
  224. break;
  225. }
  226. // Propagate the Modbus errors to higher level
  227. switch(mb_error)
  228. {
  229. case MB_MRE_NO_ERR:
  230. error = ESP_OK;
  231. break;
  232. case MB_MRE_NO_REG:
  233. error = ESP_ERR_NOT_SUPPORTED; // Invalid register request
  234. break;
  235. case MB_MRE_TIMEDOUT:
  236. error = ESP_ERR_TIMEOUT; // Slave did not send response
  237. break;
  238. case MB_MRE_EXE_FUN:
  239. case MB_MRE_REV_DATA:
  240. error = ESP_ERR_INVALID_RESPONSE; // Invalid response from slave
  241. break;
  242. case MB_MRE_MASTER_BUSY:
  243. error = ESP_ERR_INVALID_STATE; // Master is busy (previous request is pending)
  244. break;
  245. default:
  246. ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ",
  247. __FUNCTION__, mb_error);
  248. error = ESP_FAIL;
  249. break;
  250. }
  251. return error;
  252. }
  253. static esp_err_t mbc_serial_master_get_cid_info(uint16_t cid, const mb_parameter_descriptor_t** param_buffer)
  254. {
  255. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  256. ESP_ERR_INVALID_STATE,
  257. "Master interface uninitialized.");
  258. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  259. MB_MASTER_CHECK((param_buffer != NULL),
  260. ESP_ERR_INVALID_ARG, "mb incorrect data buffer pointer.");
  261. MB_MASTER_CHECK((mbm_opts->mbm_param_descriptor_table != NULL),
  262. ESP_ERR_INVALID_ARG, "mb incorrect descriptor table or not set.");
  263. MB_MASTER_CHECK((cid < mbm_opts->mbm_param_descriptor_size),
  264. ESP_ERR_NOT_FOUND, "mb incorrect cid of characteristic.");
  265. // It is assumed that characteristics cid increased in the table
  266. const mb_parameter_descriptor_t* reg_info = &mbm_opts->mbm_param_descriptor_table[cid];
  267. MB_MASTER_CHECK((reg_info->param_key != NULL),
  268. ESP_ERR_INVALID_ARG, "mb incorrect characteristic key.");
  269. *param_buffer = reg_info;
  270. return ESP_OK;
  271. }
  272. // Helper function to get modbus command for each type of Modbus register area
  273. static uint8_t mbc_serial_master_get_command(mb_param_type_t param_type, mb_param_mode_t mode)
  274. {
  275. uint8_t command = 0;
  276. switch(param_type)
  277. { //
  278. case MB_PARAM_HOLDING:
  279. command = (mode == MB_PARAM_WRITE) ?
  280. MB_FUNC_WRITE_MULTIPLE_REGISTERS :
  281. MB_FUNC_READ_HOLDING_REGISTER;
  282. break;
  283. case MB_PARAM_INPUT:
  284. command = MB_FUNC_READ_INPUT_REGISTER;
  285. break;
  286. case MB_PARAM_COIL:
  287. command = (mode == MB_PARAM_WRITE) ?
  288. MB_FUNC_WRITE_MULTIPLE_COILS :
  289. MB_FUNC_READ_COILS;
  290. break;
  291. case MB_PARAM_DISCRETE:
  292. if (mode != MB_PARAM_WRITE) {
  293. command = MB_FUNC_READ_DISCRETE_INPUTS;
  294. } else {
  295. ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect mode (%u)",
  296. __FUNCTION__, (uint8_t)mode);
  297. }
  298. break;
  299. default:
  300. ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u)",
  301. __FUNCTION__, param_type);
  302. break;
  303. }
  304. return command;
  305. }
  306. // Helper to search parameter by name in the parameter description table
  307. // and fills Modbus request fields accordingly
  308. static esp_err_t mbc_serial_master_set_request(char* name, mb_param_mode_t mode,
  309. mb_param_request_t* request,
  310. mb_parameter_descriptor_t* reg_data)
  311. {
  312. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  313. ESP_ERR_INVALID_STATE,
  314. "Master interface uninitialized.");
  315. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  316. esp_err_t error = ESP_ERR_NOT_FOUND;
  317. MB_MASTER_CHECK((name != NULL),
  318. ESP_ERR_INVALID_ARG, "mb incorrect parameter name.");
  319. MB_MASTER_CHECK((request != NULL),
  320. ESP_ERR_INVALID_ARG, "mb incorrect request parameter.");
  321. MB_MASTER_CHECK((mode <= MB_PARAM_WRITE),
  322. ESP_ERR_INVALID_ARG, "mb incorrect mode.");
  323. MB_MASTER_ASSERT(mbm_opts->mbm_param_descriptor_table != NULL);
  324. const mb_parameter_descriptor_t* reg_ptr = mbm_opts->mbm_param_descriptor_table;
  325. for (uint16_t counter = 0; counter < (mbm_opts->mbm_param_descriptor_size); counter++, reg_ptr++)
  326. {
  327. // Check the cid of the parameter is equal to record number in the table
  328. // Check the length of name and parameter key strings from table
  329. size_t param_key_len = strlen((const char*)reg_ptr->param_key);
  330. if (param_key_len != strlen((const char*)name)) {
  331. continue; // The length of strings is different then check next record in the table
  332. }
  333. // Compare the name of parameter with parameter key from table
  334. int comp_result = memcmp((const void*)name, (const void*)reg_ptr->param_key, (size_t)param_key_len);
  335. if (comp_result == 0) {
  336. // The correct line is found in the table and reg_ptr points to the found parameter description
  337. request->slave_addr = reg_ptr->mb_slave_addr;
  338. request->reg_start = reg_ptr->mb_reg_start;
  339. request->reg_size = reg_ptr->mb_size;
  340. request->command = mbc_serial_master_get_command(reg_ptr->mb_param_type, mode);
  341. MB_MASTER_CHECK((request->command > 0),
  342. ESP_ERR_INVALID_ARG,
  343. "mb incorrect command or parameter type.");
  344. if (reg_data != NULL) {
  345. *reg_data = *reg_ptr; // Set the cid registered parameter data
  346. }
  347. error = ESP_OK;
  348. break;
  349. }
  350. }
  351. return error;
  352. }
  353. // Get parameter data for corresponding characteristic
  354. static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name,
  355. uint8_t* value_ptr, uint8_t *type)
  356. {
  357. MB_MASTER_CHECK((name != NULL),
  358. ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
  359. MB_MASTER_CHECK((type != NULL),
  360. ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
  361. esp_err_t error = ESP_ERR_INVALID_RESPONSE;
  362. mb_param_request_t request ;
  363. mb_parameter_descriptor_t reg_info = { 0 };
  364. error = mbc_serial_master_set_request(name, MB_PARAM_READ, &request, &reg_info);
  365. if ((error == ESP_OK) && (cid == reg_info.cid)) {
  366. // Send request to read characteristic data
  367. error = mbc_serial_master_send_request(&request, value_ptr);
  368. if (error == ESP_OK) {
  369. ESP_LOGD(MB_MASTER_TAG, "%s: Good response for get cid(%u) = %s",
  370. __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
  371. } else {
  372. ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to get cid(%u) = %s",
  373. __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
  374. }
  375. // Set the type of parameter found in the table
  376. *type = reg_info.param_type;
  377. } else {
  378. ESP_LOGE(MB_MASTER_TAG, "%s: The cid(%u) not found in the data dictionary.",
  379. __FUNCTION__, reg_info.cid);
  380. error = ESP_ERR_INVALID_ARG;
  381. }
  382. return error;
  383. }
  384. // Set parameter value for characteristic selected by name and cid
  385. static esp_err_t mbc_serial_master_set_parameter(uint16_t cid, char* name,
  386. uint8_t* value_ptr, uint8_t *type)
  387. {
  388. MB_MASTER_CHECK((name != NULL),
  389. ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
  390. MB_MASTER_CHECK((value_ptr != NULL),
  391. ESP_ERR_INVALID_ARG, "value pointer is incorrect.");
  392. MB_MASTER_CHECK((type != NULL),
  393. ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
  394. esp_err_t error = ESP_ERR_INVALID_RESPONSE;
  395. mb_param_request_t request ;
  396. mb_parameter_descriptor_t reg_info = { 0 };
  397. error = mbc_serial_master_set_request(name, MB_PARAM_WRITE, &request, &reg_info);
  398. if ((error == ESP_OK) && (cid == reg_info.cid)) {
  399. // Send request to write characteristic data
  400. error = mbc_serial_master_send_request(&request, value_ptr);
  401. if (error == ESP_OK) {
  402. ESP_LOGD(MB_MASTER_TAG, "%s: Good response for set cid(%u) = %s",
  403. __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
  404. } else {
  405. ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to set cid(%u) = %s",
  406. __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
  407. }
  408. // Set the type of parameter found in the table
  409. *type = reg_info.param_type;
  410. } else {
  411. ESP_LOGE(MB_MASTER_TAG, "%s: The requested cid(%u) not found in the data dictionary.",
  412. __FUNCTION__, reg_info.cid);
  413. error = ESP_ERR_INVALID_ARG;
  414. }
  415. return error;
  416. }
  417. /* ----------------------- Callback functions for Modbus stack ---------------------------------*/
  418. // These are executed by modbus stack to read appropriate type of registers.
  419. /**
  420. * Modbus master input register callback function.
  421. *
  422. * @param pucRegBuffer input register buffer
  423. * @param usAddress input register address
  424. * @param usNRegs input register number
  425. *
  426. * @return result
  427. */
  428. // Callback function for reading of MB Input Registers
  429. eMBErrorCode eMBRegInputCBSerialMaster(UCHAR * pucRegBuffer, USHORT usAddress,
  430. USHORT usNRegs)
  431. {
  432. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  433. MB_EILLSTATE,
  434. "Master interface uninitialized.");
  435. MB_MASTER_CHECK((pucRegBuffer != NULL), MB_EINVAL,
  436. "Master stack processing error.");
  437. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  438. // Number of input registers to be transferred
  439. USHORT usRegInputNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
  440. UCHAR* pucInputBuffer = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr; // Get instance address
  441. USHORT usRegs = usNRegs;
  442. eMBErrorCode eStatus = MB_ENOERR;
  443. // If input or configuration parameters are incorrect then return an error to stack layer
  444. if ((pucInputBuffer != NULL)
  445. && (usNRegs >= 1)
  446. && (usRegInputNregs == usRegs)) {
  447. while (usRegs > 0) {
  448. _XFER_2_RD(pucInputBuffer, pucRegBuffer);
  449. usRegs -= 1;
  450. }
  451. } else {
  452. eStatus = MB_ENOREG;
  453. }
  454. return eStatus;
  455. }
  456. /**
  457. * Modbus master holding register callback function.
  458. *
  459. * @param pucRegBuffer holding register buffer
  460. * @param usAddress holding register address
  461. * @param usNRegs holding register number
  462. * @param eMode read or write
  463. *
  464. * @return result
  465. */
  466. // Callback function for reading of MB Holding Registers
  467. // Executed by stack when request to read/write holding registers is received
  468. eMBErrorCode eMBRegHoldingCBSerialMaster(UCHAR * pucRegBuffer, USHORT usAddress,
  469. USHORT usNRegs, eMBRegisterMode eMode)
  470. {
  471. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  472. MB_EILLSTATE,
  473. "Master interface uninitialized.");
  474. MB_MASTER_CHECK((pucRegBuffer != NULL), MB_EINVAL,
  475. "Master stack processing error.");
  476. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  477. USHORT usRegHoldingNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
  478. UCHAR* pucHoldingBuffer = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr;
  479. eMBErrorCode eStatus = MB_ENOERR;
  480. USHORT usRegs = usNRegs;
  481. // Check input and configuration parameters for correctness
  482. if ((pucHoldingBuffer != NULL)
  483. && (usRegHoldingNregs == usNRegs)
  484. && (usNRegs >= 1)) {
  485. switch (eMode) {
  486. case MB_REG_WRITE:
  487. while (usRegs > 0) {
  488. _XFER_2_RD(pucRegBuffer, pucHoldingBuffer);
  489. usRegs -= 1;
  490. };
  491. break;
  492. case MB_REG_READ:
  493. while (usRegs > 0) {
  494. _XFER_2_WR(pucHoldingBuffer, pucRegBuffer);
  495. pucHoldingBuffer += 2;
  496. usRegs -= 1;
  497. };
  498. break;
  499. }
  500. } else {
  501. eStatus = MB_ENOREG;
  502. }
  503. return eStatus;
  504. }
  505. /**
  506. * Modbus master coils callback function.
  507. *
  508. * @param pucRegBuffer coils buffer
  509. * @param usAddress coils address
  510. * @param usNCoils coils number
  511. * @param eMode read or write
  512. *
  513. * @return result
  514. */
  515. // Callback function for reading of MB Coils Registers
  516. eMBErrorCode eMBRegCoilsCBSerialMaster(UCHAR* pucRegBuffer, USHORT usAddress,
  517. USHORT usNCoils, eMBRegisterMode eMode)
  518. {
  519. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  520. MB_EILLSTATE, "Master interface uninitialized.");
  521. MB_MASTER_CHECK((pucRegBuffer != NULL),
  522. MB_EINVAL, "Master stack processing error.");
  523. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  524. USHORT usRegCoilNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
  525. UCHAR* pucRegCoilsBuf = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr;
  526. eMBErrorCode eStatus = MB_ENOERR;
  527. USHORT iRegIndex;
  528. USHORT usCoils = usNCoils;
  529. usAddress--; // The address is already + 1
  530. if ((usRegCoilNregs >= 1)
  531. && (pucRegCoilsBuf != NULL)
  532. && (usNCoils == usRegCoilNregs)) {
  533. iRegIndex = (usAddress % 8);
  534. switch (eMode) {
  535. case MB_REG_WRITE:
  536. while (usCoils > 0) {
  537. UCHAR ucResult = xMBUtilGetBits((UCHAR*)pucRegCoilsBuf, iRegIndex, 1);
  538. xMBUtilSetBits(pucRegBuffer, iRegIndex - (usAddress % 8) , 1, ucResult);
  539. iRegIndex++;
  540. usCoils--;
  541. }
  542. break;
  543. case MB_REG_READ:
  544. while (usCoils > 0) {
  545. UCHAR ucResult = xMBUtilGetBits(pucRegBuffer, iRegIndex - (usAddress % 8), 1);
  546. xMBUtilSetBits((uint8_t*)pucRegCoilsBuf, iRegIndex, 1, ucResult);
  547. iRegIndex++;
  548. usCoils--;
  549. }
  550. break;
  551. } // switch ( eMode )
  552. } else {
  553. // If the configuration or input parameters are incorrect then return error to stack
  554. eStatus = MB_ENOREG;
  555. }
  556. return eStatus;
  557. }
  558. /**
  559. * Modbus master discrete callback function.
  560. *
  561. * @param pucRegBuffer discrete buffer
  562. * @param usAddress discrete address
  563. * @param usNDiscrete discrete number
  564. *
  565. * @return result
  566. */
  567. // Callback function for reading of MB Discrete Input Registers
  568. eMBErrorCode eMBRegDiscreteCBSerialMaster(UCHAR * pucRegBuffer, USHORT usAddress,
  569. USHORT usNDiscrete)
  570. {
  571. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  572. MB_EILLSTATE, "Master interface uninitialized.");
  573. MB_MASTER_CHECK((pucRegBuffer != NULL),
  574. MB_EINVAL, "Master stack processing error.");
  575. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  576. USHORT usRegDiscreteNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
  577. UCHAR* pucRegDiscreteBuf = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr;
  578. eMBErrorCode eStatus = MB_ENOERR;
  579. USHORT iRegBitIndex, iNReg;
  580. UCHAR* pucDiscreteInputBuf;
  581. iNReg = usNDiscrete / 8 + 1;
  582. pucDiscreteInputBuf = (UCHAR*) pucRegDiscreteBuf;
  583. // It is already plus one in Modbus function method.
  584. usAddress--;
  585. if ((usRegDiscreteNregs >= 1)
  586. && (pucRegDiscreteBuf != NULL)
  587. && (usNDiscrete >= 1)) {
  588. iRegBitIndex = (USHORT)(usAddress) % 8; // Get bit index
  589. while (iNReg > 1)
  590. {
  591. xMBUtilSetBits(pucDiscreteInputBuf++, iRegBitIndex, 8, *pucRegBuffer++);
  592. iNReg--;
  593. }
  594. // last discrete
  595. usNDiscrete = usNDiscrete % 8;
  596. // xMBUtilSetBits has bug when ucNBits is zero
  597. if (usNDiscrete != 0)
  598. {
  599. xMBUtilSetBits(pucDiscreteInputBuf, iRegBitIndex, usNDiscrete, *pucRegBuffer++);
  600. }
  601. } else {
  602. eStatus = MB_ENOREG;
  603. }
  604. return eStatus;
  605. }
  606. // Initialization of resources for Modbus serial master controller
  607. esp_err_t mbc_serial_master_create(void** handler)
  608. {
  609. // Allocate space for master interface structure
  610. if (mbm_interface_ptr == NULL) {
  611. mbm_interface_ptr = malloc(sizeof(mb_master_interface_t));
  612. }
  613. MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
  614. // Initialize interface properties
  615. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  616. mbm_opts->port_type = MB_PORT_SERIAL_MASTER;
  617. vMBPortSetMode((UCHAR)MB_PORT_SERIAL_MASTER);
  618. mbm_opts->mbm_comm.mode = MB_MODE_RTU;
  619. mbm_opts->mbm_comm.port = MB_UART_PORT;
  620. mbm_opts->mbm_comm.baudrate = MB_DEVICE_SPEED;
  621. mbm_opts->mbm_comm.parity = MB_PARITY_NONE;
  622. // Initialization of active context of the modbus controller
  623. BaseType_t status = 0;
  624. // Parameter change notification queue
  625. mbm_opts->mbm_event_group = xEventGroupCreate();
  626. MB_MASTER_CHECK((mbm_opts->mbm_event_group != NULL),
  627. ESP_ERR_NO_MEM, "mb event group error.");
  628. // Create modbus controller task
  629. status = xTaskCreatePinnedToCore((void*)&modbus_master_task,
  630. "modbus_matask",
  631. MB_CONTROLLER_STACK_SIZE,
  632. NULL, // No parameters
  633. MB_CONTROLLER_PRIORITY,
  634. &mbm_opts->mbm_task_handle,
  635. MB_PORT_TASK_AFFINITY);
  636. if (status != pdPASS) {
  637. vTaskDelete(mbm_opts->mbm_task_handle);
  638. MB_MASTER_CHECK((status == pdPASS), ESP_ERR_NO_MEM,
  639. "mb controller task creation error, xTaskCreate() returns (0x%x).",
  640. (uint32_t)status);
  641. }
  642. MB_MASTER_ASSERT(mbm_opts->mbm_task_handle != NULL); // The task is created but handle is incorrect
  643. // Initialize public interface methods of the interface
  644. mbm_interface_ptr->init = mbc_serial_master_create;
  645. mbm_interface_ptr->destroy = mbc_serial_master_destroy;
  646. mbm_interface_ptr->setup = mbc_serial_master_setup;
  647. mbm_interface_ptr->start = mbc_serial_master_start;
  648. mbm_interface_ptr->get_cid_info = mbc_serial_master_get_cid_info;
  649. mbm_interface_ptr->get_parameter = mbc_serial_master_get_parameter;
  650. mbm_interface_ptr->send_request = mbc_serial_master_send_request;
  651. mbm_interface_ptr->set_descriptor = mbc_serial_master_set_descriptor;
  652. mbm_interface_ptr->set_parameter = mbc_serial_master_set_parameter;
  653. mbm_interface_ptr->master_reg_cb_discrete = eMBRegDiscreteCBSerialMaster;
  654. mbm_interface_ptr->master_reg_cb_input = eMBRegInputCBSerialMaster;
  655. mbm_interface_ptr->master_reg_cb_holding = eMBRegHoldingCBSerialMaster;
  656. mbm_interface_ptr->master_reg_cb_coils = eMBRegCoilsCBSerialMaster;
  657. *handler = mbm_interface_ptr;
  658. return ESP_OK;
  659. }