mbc_serial_master.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  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 response 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 = eMBMasterInit((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. mbm_interface_ptr = NULL;
  131. return ESP_OK;
  132. }
  133. // Set Modbus parameter description table
  134. static esp_err_t mbc_serial_master_set_descriptor(const mb_parameter_descriptor_t* descriptor, const uint16_t num_elements)
  135. {
  136. MB_MASTER_CHECK((descriptor != NULL),
  137. ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
  138. MB_MASTER_CHECK((num_elements >= 1),
  139. ESP_ERR_INVALID_ARG, "mb table size is incorrect.");
  140. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  141. const mb_parameter_descriptor_t *reg_ptr = descriptor;
  142. // Go through all items in the table to check all Modbus registers
  143. for (uint16_t counter = 0; counter < (num_elements); counter++, reg_ptr++)
  144. {
  145. // Below is the code to check consistency of the table format and required fields.
  146. MB_MASTER_CHECK((reg_ptr->cid == counter),
  147. ESP_ERR_INVALID_ARG, "mb descriptor cid field is incorrect.");
  148. MB_MASTER_CHECK((reg_ptr->param_key != NULL),
  149. ESP_ERR_INVALID_ARG, "mb descriptor param key is incorrect.");
  150. MB_MASTER_CHECK((reg_ptr->mb_size > 0),
  151. ESP_ERR_INVALID_ARG, "mb descriptor param size is incorrect.");
  152. }
  153. mbm_opts->mbm_param_descriptor_table = descriptor;
  154. mbm_opts->mbm_param_descriptor_size = num_elements;
  155. return ESP_OK;
  156. }
  157. // Send custom Modbus request defined as mb_param_request_t structure
  158. static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, void* data_ptr)
  159. {
  160. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  161. ESP_ERR_INVALID_STATE,
  162. "Master interface uninitialized.");
  163. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  164. MB_MASTER_CHECK((request != NULL),
  165. ESP_ERR_INVALID_ARG, "mb request structure.");
  166. MB_MASTER_CHECK((data_ptr != NULL),
  167. ESP_ERR_INVALID_ARG, "mb incorrect data pointer.");
  168. eMBMasterReqErrCode mb_error = MB_MRE_NO_REG;
  169. esp_err_t error = ESP_FAIL;
  170. uint8_t mb_slave_addr = request->slave_addr;
  171. uint8_t mb_command = request->command;
  172. uint16_t mb_offset = request->reg_start;
  173. uint16_t mb_size = request->reg_size;
  174. // Set the buffer for callback function processing of received data
  175. mbm_opts->mbm_reg_buffer_ptr = (uint8_t*)data_ptr;
  176. mbm_opts->mbm_reg_buffer_size = mb_size;
  177. // Calls appropriate request function to send request and waits response
  178. switch(mb_command)
  179. {
  180. case MB_FUNC_READ_COILS:
  181. mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
  182. (USHORT)mb_size , (LONG)MB_RESPONSE_TICS );
  183. break;
  184. case MB_FUNC_WRITE_SINGLE_COIL:
  185. mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
  186. *(USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
  187. break;
  188. case MB_FUNC_WRITE_MULTIPLE_COILS:
  189. mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
  190. (USHORT)mb_size, (UCHAR*)data_ptr, (LONG)MB_RESPONSE_TICS);
  191. break;
  192. case MB_FUNC_READ_DISCRETE_INPUTS:
  193. mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
  194. (USHORT)mb_size, (LONG)MB_RESPONSE_TICS );
  195. break;
  196. case MB_FUNC_READ_HOLDING_REGISTER:
  197. mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
  198. (USHORT)mb_size, (LONG)MB_RESPONSE_TICS );
  199. break;
  200. case MB_FUNC_WRITE_REGISTER:
  201. mb_error = eMBMasterReqWriteHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
  202. *(USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
  203. break;
  204. case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
  205. mb_error = eMBMasterReqWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr,
  206. (USHORT)mb_offset, (USHORT)mb_size,
  207. (USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
  208. break;
  209. case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
  210. mb_error = eMBMasterReqReadWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
  211. (USHORT)mb_size, (USHORT*)data_ptr,
  212. (USHORT)mb_offset, (USHORT)mb_size,
  213. (LONG)MB_RESPONSE_TICS );
  214. break;
  215. case MB_FUNC_READ_INPUT_REGISTER:
  216. mb_error = eMBMasterReqReadInputRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
  217. (USHORT)mb_size, (LONG) MB_RESPONSE_TICS );
  218. break;
  219. default:
  220. ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect function in request (%u) ",
  221. __FUNCTION__, mb_command);
  222. mb_error = MB_MRE_NO_REG;
  223. break;
  224. }
  225. // Propagate the Modbus errors to higher level
  226. switch(mb_error)
  227. {
  228. case MB_MRE_NO_ERR:
  229. error = ESP_OK;
  230. break;
  231. case MB_MRE_NO_REG:
  232. error = ESP_ERR_NOT_SUPPORTED; // Invalid register request
  233. break;
  234. case MB_MRE_TIMEDOUT:
  235. error = ESP_ERR_TIMEOUT; // Slave did not send response
  236. break;
  237. case MB_MRE_EXE_FUN:
  238. case MB_MRE_REV_DATA:
  239. error = ESP_ERR_INVALID_RESPONSE; // Invalid response from slave
  240. break;
  241. case MB_MRE_MASTER_BUSY:
  242. error = ESP_ERR_INVALID_STATE; // Master is busy (previous request is pending)
  243. break;
  244. default:
  245. ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ",
  246. __FUNCTION__, mb_error);
  247. error = ESP_FAIL;
  248. break;
  249. }
  250. return error;
  251. }
  252. static esp_err_t mbc_serial_master_get_cid_info(uint16_t cid, const mb_parameter_descriptor_t** param_buffer)
  253. {
  254. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  255. ESP_ERR_INVALID_STATE,
  256. "Master interface uninitialized.");
  257. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  258. MB_MASTER_CHECK((param_buffer != NULL),
  259. ESP_ERR_INVALID_ARG, "mb incorrect data buffer pointer.");
  260. MB_MASTER_CHECK((mbm_opts->mbm_param_descriptor_table != NULL),
  261. ESP_ERR_INVALID_ARG, "mb incorrect descriptor table or not set.");
  262. MB_MASTER_CHECK((cid < mbm_opts->mbm_param_descriptor_size),
  263. ESP_ERR_NOT_FOUND, "mb incorrect cid of characteristic.");
  264. // It is assumed that characteristics cid increased in the table
  265. const mb_parameter_descriptor_t* reg_info = &mbm_opts->mbm_param_descriptor_table[cid];
  266. MB_MASTER_CHECK((reg_info->param_key != NULL),
  267. ESP_ERR_INVALID_ARG, "mb incorrect characteristic key.");
  268. *param_buffer = reg_info;
  269. return ESP_OK;
  270. }
  271. // Helper function to get modbus command for each type of Modbus register area
  272. static uint8_t mbc_serial_master_get_command(mb_param_type_t param_type, mb_param_mode_t mode)
  273. {
  274. uint8_t command = 0;
  275. switch(param_type)
  276. { //
  277. case MB_PARAM_HOLDING:
  278. command = (mode == MB_PARAM_WRITE) ?
  279. MB_FUNC_WRITE_MULTIPLE_REGISTERS :
  280. MB_FUNC_READ_HOLDING_REGISTER;
  281. break;
  282. case MB_PARAM_INPUT:
  283. command = MB_FUNC_READ_INPUT_REGISTER;
  284. break;
  285. case MB_PARAM_COIL:
  286. command = (mode == MB_PARAM_WRITE) ?
  287. MB_FUNC_WRITE_MULTIPLE_COILS :
  288. MB_FUNC_READ_COILS;
  289. break;
  290. case MB_PARAM_DISCRETE:
  291. if (mode != MB_PARAM_WRITE) {
  292. command = MB_FUNC_READ_DISCRETE_INPUTS;
  293. } else {
  294. ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect mode (%u)",
  295. __FUNCTION__, (uint8_t)mode);
  296. }
  297. break;
  298. default:
  299. ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u)",
  300. __FUNCTION__, param_type);
  301. break;
  302. }
  303. return command;
  304. }
  305. // Helper to search parameter by name in the parameter description table
  306. // and fills Modbus request fields accordingly
  307. static esp_err_t mbc_serial_master_set_request(char* name, mb_param_mode_t mode,
  308. mb_param_request_t* request,
  309. mb_parameter_descriptor_t* reg_data)
  310. {
  311. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  312. ESP_ERR_INVALID_STATE,
  313. "Master interface uninitialized.");
  314. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  315. esp_err_t error = ESP_ERR_NOT_FOUND;
  316. MB_MASTER_CHECK((name != NULL),
  317. ESP_ERR_INVALID_ARG, "mb incorrect parameter name.");
  318. MB_MASTER_CHECK((request != NULL),
  319. ESP_ERR_INVALID_ARG, "mb incorrect request parameter.");
  320. MB_MASTER_CHECK((mode <= MB_PARAM_WRITE),
  321. ESP_ERR_INVALID_ARG, "mb incorrect mode.");
  322. MB_MASTER_ASSERT(mbm_opts->mbm_param_descriptor_table != NULL);
  323. const mb_parameter_descriptor_t* reg_ptr = mbm_opts->mbm_param_descriptor_table;
  324. for (uint16_t counter = 0; counter < (mbm_opts->mbm_param_descriptor_size); counter++, reg_ptr++)
  325. {
  326. // Check the cid of the parameter is equal to record number in the table
  327. // Check the length of name and parameter key strings from table
  328. size_t param_key_len = strlen((const char*)reg_ptr->param_key);
  329. if (param_key_len != strlen((const char*)name)) {
  330. continue; // The length of strings is different then check next record in the table
  331. }
  332. // Compare the name of parameter with parameter key from table
  333. uint8_t comp_result = memcmp((const char*)name, (const char*)reg_ptr->param_key, (size_t)param_key_len);
  334. if (comp_result == 0) {
  335. // The correct line is found in the table and reg_ptr points to the found parameter description
  336. request->slave_addr = reg_ptr->mb_slave_addr;
  337. request->reg_start = reg_ptr->mb_reg_start;
  338. request->reg_size = reg_ptr->mb_size;
  339. request->command = mbc_serial_master_get_command(reg_ptr->mb_param_type, mode);
  340. MB_MASTER_CHECK((request->command > 0),
  341. ESP_ERR_INVALID_ARG,
  342. "mb incorrect command or parameter type.");
  343. if (reg_data != NULL) {
  344. *reg_data = *reg_ptr; // Set the cid registered parameter data
  345. }
  346. error = ESP_OK;
  347. break;
  348. }
  349. }
  350. return error;
  351. }
  352. // Get parameter data for corresponding characteristic
  353. static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name,
  354. uint8_t* value_ptr, uint8_t *type)
  355. {
  356. MB_MASTER_CHECK((name != NULL),
  357. ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
  358. MB_MASTER_CHECK((type != NULL),
  359. ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
  360. esp_err_t error = ESP_ERR_INVALID_RESPONSE;
  361. mb_param_request_t request ;
  362. mb_parameter_descriptor_t reg_info = { 0 };
  363. error = mbc_serial_master_set_request(name, MB_PARAM_READ, &request, &reg_info);
  364. if ((error == ESP_OK) && (cid == reg_info.cid)) {
  365. // Send request to read characteristic data
  366. error = mbc_serial_master_send_request(&request, value_ptr);
  367. if (error == ESP_OK) {
  368. ESP_LOGD(MB_MASTER_TAG, "%s: Good response for get cid(%u) = %s",
  369. __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
  370. } else {
  371. ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to get cid(%u) = %s",
  372. __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
  373. }
  374. // Set the type of parameter found in the table
  375. *type = reg_info.param_type;
  376. } else {
  377. ESP_LOGD(MB_MASTER_TAG, "%s: The cid(%u) not found in the data dictionary.",
  378. __FUNCTION__, reg_info.cid);
  379. }
  380. return error;
  381. }
  382. // Set parameter value for characteristic selected by name and cid
  383. static esp_err_t mbc_serial_master_set_parameter(uint16_t cid, char* name,
  384. uint8_t* value_ptr, uint8_t *type)
  385. {
  386. MB_MASTER_CHECK((name != NULL),
  387. ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
  388. MB_MASTER_CHECK((value_ptr != NULL),
  389. ESP_ERR_INVALID_ARG, "value pointer is incorrect.");
  390. MB_MASTER_CHECK((type != NULL),
  391. ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
  392. esp_err_t error = ESP_ERR_INVALID_RESPONSE;
  393. mb_param_request_t request ;
  394. mb_parameter_descriptor_t reg_info = { 0 };
  395. error = mbc_serial_master_set_request(name, MB_PARAM_WRITE, &request, &reg_info);
  396. if ((error == ESP_OK) && (cid == reg_info.cid)) {
  397. // Send request to write characteristic data
  398. error = mbc_serial_master_send_request(&request, value_ptr);
  399. if (error == ESP_OK) {
  400. ESP_LOGD(MB_MASTER_TAG, "%s: Good response for set cid(%u) = %s",
  401. __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
  402. } else {
  403. ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to set cid(%u) = %s",
  404. __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
  405. }
  406. // Set the type of parameter found in the table
  407. *type = reg_info.param_type;
  408. } else {
  409. ESP_LOGE(MB_MASTER_TAG, "%s: The requested cid(%u) not found in the data dictionary.",
  410. __FUNCTION__, reg_info.cid);
  411. }
  412. return error;
  413. }
  414. /* ----------------------- Callback functions for Modbus stack ---------------------------------*/
  415. // These are executed by modbus stack to read appropriate type of registers.
  416. /**
  417. * Modbus master input register callback function.
  418. *
  419. * @param pucRegBuffer input register buffer
  420. * @param usAddress input register address
  421. * @param usNRegs input register number
  422. *
  423. * @return result
  424. */
  425. // Callback function for reading of MB Input Registers
  426. eMBErrorCode eMBRegInputCBSerialMaster(UCHAR * pucRegBuffer, USHORT usAddress,
  427. USHORT usNRegs)
  428. {
  429. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  430. MB_EILLSTATE,
  431. "Master interface uninitialized.");
  432. MB_MASTER_CHECK((pucRegBuffer != NULL), MB_EINVAL,
  433. "Master stack processing error.");
  434. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  435. // Number of input registers to be transferred
  436. USHORT usRegInputNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
  437. UCHAR* pucInputBuffer = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr; // Get instance address
  438. USHORT usRegs = usNRegs;
  439. eMBErrorCode eStatus = MB_ENOERR;
  440. // If input or configuration parameters are incorrect then return an error to stack layer
  441. if ((pucInputBuffer != NULL)
  442. && (usNRegs >= 1)
  443. && (usRegInputNregs == usRegs)) {
  444. while (usRegs > 0) {
  445. _XFER_2_RD(pucInputBuffer, pucRegBuffer);
  446. usRegs -= 1;
  447. }
  448. } else {
  449. eStatus = MB_ENOREG;
  450. }
  451. return eStatus;
  452. }
  453. /**
  454. * Modbus master holding register callback function.
  455. *
  456. * @param pucRegBuffer holding register buffer
  457. * @param usAddress holding register address
  458. * @param usNRegs holding register number
  459. * @param eMode read or write
  460. *
  461. * @return result
  462. */
  463. // Callback function for reading of MB Holding Registers
  464. // Executed by stack when request to read/write holding registers is received
  465. eMBErrorCode eMBRegHoldingCBSerialMaster(UCHAR * pucRegBuffer, USHORT usAddress,
  466. USHORT usNRegs, eMBRegisterMode eMode)
  467. {
  468. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  469. MB_EILLSTATE,
  470. "Master interface uninitialized.");
  471. MB_MASTER_CHECK((pucRegBuffer != NULL), MB_EINVAL,
  472. "Master stack processing error.");
  473. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  474. USHORT usRegHoldingNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
  475. UCHAR* pucHoldingBuffer = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr;
  476. eMBErrorCode eStatus = MB_ENOERR;
  477. USHORT usRegs = usNRegs;
  478. // Check input and configuration parameters for correctness
  479. if ((pucHoldingBuffer != NULL)
  480. && (usRegHoldingNregs == usNRegs)
  481. && (usNRegs >= 1)) {
  482. switch (eMode) {
  483. case MB_REG_WRITE:
  484. while (usRegs > 0) {
  485. _XFER_2_RD(pucRegBuffer, pucHoldingBuffer);
  486. usRegs -= 1;
  487. };
  488. break;
  489. case MB_REG_READ:
  490. while (usRegs > 0) {
  491. _XFER_2_WR(pucHoldingBuffer, pucRegBuffer);
  492. pucHoldingBuffer += 2;
  493. usRegs -= 1;
  494. };
  495. break;
  496. }
  497. } else {
  498. eStatus = MB_ENOREG;
  499. }
  500. return eStatus;
  501. }
  502. /**
  503. * Modbus master coils callback function.
  504. *
  505. * @param pucRegBuffer coils buffer
  506. * @param usAddress coils address
  507. * @param usNCoils coils number
  508. * @param eMode read or write
  509. *
  510. * @return result
  511. */
  512. // Callback function for reading of MB Coils Registers
  513. eMBErrorCode eMBRegCoilsCBSerialMaster(UCHAR* pucRegBuffer, USHORT usAddress,
  514. USHORT usNCoils, eMBRegisterMode eMode)
  515. {
  516. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  517. MB_EILLSTATE, "Master interface uninitialized.");
  518. MB_MASTER_CHECK((pucRegBuffer != NULL),
  519. MB_EINVAL, "Master stack processing error.");
  520. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  521. USHORT usRegCoilNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
  522. UCHAR* pucRegCoilsBuf = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr;
  523. eMBErrorCode eStatus = MB_ENOERR;
  524. USHORT iRegIndex;
  525. USHORT usCoils = usNCoils;
  526. usAddress--; // The address is already + 1
  527. if ((usRegCoilNregs >= 1)
  528. && (pucRegCoilsBuf != NULL)
  529. && (usNCoils == usRegCoilNregs)) {
  530. iRegIndex = (usAddress % 8);
  531. switch (eMode) {
  532. case MB_REG_WRITE:
  533. while (usCoils > 0) {
  534. UCHAR ucResult = xMBUtilGetBits((UCHAR*)pucRegCoilsBuf, iRegIndex, 1);
  535. xMBUtilSetBits(pucRegBuffer, iRegIndex - (usAddress % 8) , 1, ucResult);
  536. iRegIndex++;
  537. usCoils--;
  538. }
  539. break;
  540. case MB_REG_READ:
  541. while (usCoils > 0) {
  542. UCHAR ucResult = xMBUtilGetBits(pucRegBuffer, iRegIndex - (usAddress % 8), 1);
  543. xMBUtilSetBits((uint8_t*)pucRegCoilsBuf, iRegIndex, 1, ucResult);
  544. iRegIndex++;
  545. usCoils--;
  546. }
  547. break;
  548. } // switch ( eMode )
  549. } else {
  550. // If the configuration or input parameters are incorrect then return error to stack
  551. eStatus = MB_ENOREG;
  552. }
  553. return eStatus;
  554. }
  555. /**
  556. * Modbus master discrete callback function.
  557. *
  558. * @param pucRegBuffer discrete buffer
  559. * @param usAddress discrete address
  560. * @param usNDiscrete discrete number
  561. *
  562. * @return result
  563. */
  564. // Callback function for reading of MB Discrete Input Registers
  565. eMBErrorCode eMBRegDiscreteCBSerialMaster(UCHAR * pucRegBuffer, USHORT usAddress,
  566. USHORT usNDiscrete)
  567. {
  568. MB_MASTER_CHECK((mbm_interface_ptr != NULL),
  569. MB_EILLSTATE, "Master interface uninitialized.");
  570. MB_MASTER_CHECK((pucRegBuffer != NULL),
  571. MB_EINVAL, "Master stack processing error.");
  572. mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
  573. USHORT usRegDiscreteNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
  574. UCHAR* pucRegDiscreteBuf = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr;
  575. eMBErrorCode eStatus = MB_ENOERR;
  576. USHORT iRegBitIndex, iNReg;
  577. UCHAR* pucDiscreteInputBuf;
  578. iNReg = usNDiscrete / 8 + 1;
  579. pucDiscreteInputBuf = (UCHAR*) pucRegDiscreteBuf;
  580. // It is already plus one in Modbus function method.
  581. usAddress--;
  582. if ((usRegDiscreteNregs >= 1)
  583. && (pucRegDiscreteBuf != NULL)
  584. && (usNDiscrete >= 1)) {
  585. iRegBitIndex = (USHORT)(usAddress) % 8; // Get bit index
  586. while (iNReg > 1)
  587. {
  588. xMBUtilSetBits(pucDiscreteInputBuf++, iRegBitIndex, 8, *pucRegBuffer++);
  589. iNReg--;
  590. }
  591. // last discrete
  592. usNDiscrete = usNDiscrete % 8;
  593. // xMBUtilSetBits has bug when ucNBits is zero
  594. if (usNDiscrete != 0)
  595. {
  596. xMBUtilSetBits(pucDiscreteInputBuf, iRegBitIndex, usNDiscrete, *pucRegBuffer++);
  597. }
  598. } else {
  599. eStatus = MB_ENOREG;
  600. }
  601. return eStatus;
  602. }
  603. // Initialization of resources for Modbus serial master controller
  604. esp_err_t mbc_serial_master_create(mb_port_type_t port_type, void** handler)
  605. {
  606. MB_MASTER_CHECK((port_type == MB_PORT_SERIAL_MASTER),
  607. ESP_ERR_INVALID_STATE, "mb incorrect port selected = %u.",
  608. (uint32_t)port_type);
  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. mbm_opts->mbm_comm.mode = MB_MODE_RTU;
  618. mbm_opts->mbm_comm.port = MB_UART_PORT;
  619. mbm_opts->mbm_comm.baudrate = MB_DEVICE_SPEED;
  620. mbm_opts->mbm_comm.parity = MB_PARITY_NONE;
  621. // Initialization of active context of the modbus controller
  622. BaseType_t status = 0;
  623. // Parameter change notification queue
  624. mbm_opts->mbm_event_group = xEventGroupCreate();
  625. MB_MASTER_CHECK((mbm_opts->mbm_event_group != NULL),
  626. ESP_ERR_NO_MEM, "mb event group error.");
  627. // Create modbus controller task
  628. status = xTaskCreate((void*)&modbus_master_task,
  629. "modbus_matask",
  630. MB_CONTROLLER_STACK_SIZE,
  631. NULL, // No parameters
  632. MB_CONTROLLER_PRIORITY,
  633. &mbm_opts->mbm_task_handle);
  634. if (status != pdPASS) {
  635. vTaskDelete(mbm_opts->mbm_task_handle);
  636. MB_MASTER_CHECK((status == pdPASS), ESP_ERR_NO_MEM,
  637. "mb controller task creation error, xTaskCreate() returns (0x%x).",
  638. (uint32_t)status);
  639. }
  640. MB_MASTER_ASSERT(mbm_opts->mbm_task_handle != NULL); // The task is created but handle is incorrect
  641. // Initialize public interface methods of the interface
  642. mbm_interface_ptr->init = mbc_serial_master_create;
  643. mbm_interface_ptr->destroy = mbc_serial_master_destroy;
  644. mbm_interface_ptr->setup = mbc_serial_master_setup;
  645. mbm_interface_ptr->start = mbc_serial_master_start;
  646. mbm_interface_ptr->get_cid_info = mbc_serial_master_get_cid_info;
  647. mbm_interface_ptr->get_parameter = mbc_serial_master_get_parameter;
  648. mbm_interface_ptr->send_request = mbc_serial_master_send_request;
  649. mbm_interface_ptr->set_descriptor = mbc_serial_master_set_descriptor;
  650. mbm_interface_ptr->set_parameter = mbc_serial_master_set_parameter;
  651. mbm_interface_ptr->master_reg_cb_discrete = eMBRegDiscreteCBSerialMaster;
  652. mbm_interface_ptr->master_reg_cb_input = eMBRegInputCBSerialMaster;
  653. mbm_interface_ptr->master_reg_cb_holding = eMBRegHoldingCBSerialMaster;
  654. mbm_interface_ptr->master_reg_cb_coils = eMBRegCoilsCBSerialMaster;
  655. *handler = mbm_interface_ptr;
  656. return ESP_OK;
  657. }