mbrtumast.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <gfambrtumst.h>
  4. /////////////////////////////////////////////////////////////////////////////
  5. #define MODBUS_MASTER_RX_TIMEOUT_US 500000 // slave to master response timeout
  6. /////////////////////////////////////////////////////////////////////////////
  7. typedef struct _MODBUS_RTU_MASTER
  8. {
  9. HFIFO hFifoRX;
  10. HFIFO hFifoTX;
  11. uint8_t curSlaveID;
  12. uint8_t curFunc;
  13. uint32_t nTID;
  14. int nRxErr;
  15. GFA_MODBUS_RTU_MST_STATES state;
  16. GFA_MODBUS_RTU_MST_STATES oldstate;
  17. MODBUS_RTU_ADU adu;
  18. PFN_GFA_RAW_REQUEST_COMPLETE pfnRawReqComplete;
  19. void *pParam;
  20. size_t nCbDataExpected;
  21. size_t nCbRx;
  22. uint64_t nRxTimeoutUs;
  23. uint64_t nTimerUs;
  24. GFA_MODBUS_MASTER_APP_INTERFACE appItf;
  25. GFA_MODBUS_PROTOCOL_TIMEOUTS mpt;
  26. }MODBUS_RTU_MASTER, *LPMODBUS_RTU_MASTER;
  27. typedef const MODBUS_RTU_MASTER *LPCMODBUS_RTU_MASTER;
  28. /////////////////////////////////////////////////////////////////////////////
  29. static MODBUS_RTU_MASTER g_mbMast = {0};
  30. /////////////////////////////////////////////////////////////////////////////
  31. static bool _ValidateADU(LPMODBUS_RTU_MASTER pMst)
  32. {
  33. if(pMst->nRxErr)
  34. {
  35. if(pMst->nRxErr != GFA_MB_MST_ERROR_SLAVE_ERROR)
  36. return false;
  37. }
  38. if(!GfaBufVerifyCRC(&pMst->adu, pMst->nCbDataExpected + 2, &pMst->adu.pdu.b[pMst->nCbDataExpected]))
  39. {
  40. pMst->nRxErr = GFA_MB_MST_ERROR_SLAVE_INVALID_CRC;
  41. return false;
  42. }
  43. return true;
  44. }
  45. /////////////////////////////////////////////////////////////////////////////
  46. static bool _TimerElapsed(LPMODBUS_RTU_MASTER pMst)
  47. {
  48. struct timeval tv;
  49. return pMst->nTimerUs < GfaSystickTimeval2Us(GfaSystickGetUsClock(&tv));
  50. }
  51. /////////////////////////////////////////////////////////////////////////////
  52. static void _RespTimerTrigger(LPMODBUS_RTU_MASTER pMst)
  53. {
  54. struct timeval tv;
  55. pMst->nTimerUs = GfaSystickTimeval2Us(GfaSystickGetUsClock(&tv)) + pMst->nRxTimeoutUs;
  56. }
  57. /////////////////////////////////////////////////////////////////////////////
  58. static void _CharTimerTrigger(LPMODBUS_RTU_MASTER pMst)
  59. {
  60. struct timeval tv;
  61. pMst->nTimerUs = GfaSystickTimeval2Us(GfaSystickGetUsClock(&tv)) + pMst->mpt.nCharTimeoutUs;
  62. }
  63. /////////////////////////////////////////////////////////////////////////////
  64. static void _FrameTimerTrigger(LPMODBUS_RTU_MASTER pMst)
  65. {
  66. struct timeval tv;
  67. pMst->nTimerUs = GfaSystickTimeval2Us(GfaSystickGetUsClock(&tv)) + pMst->mpt.nFrameTimeoutUs;
  68. }
  69. /////////////////////////////////////////////////////////////////////////////
  70. static bool _PeekStateChange(LPMODBUS_RTU_MASTER pMst)
  71. {
  72. if(pMst->oldstate != pMst->state)
  73. {
  74. if(pMst->appItf.pfnStateChanged)
  75. (*pMst->appItf.pfnStateChanged)(pMst->state, pMst->oldstate);
  76. pMst->oldstate = pMst->state;
  77. return true;
  78. }
  79. return false;
  80. }
  81. /////////////////////////////////////////////////////////////////////////////
  82. /////////////////////////////////////////////////////////////////////////////
  83. /////////////////////////////////////////////////////////////////////////////
  84. HMBRTUMST GfaModbusRTUMstCreate(LPCGFA_MODBUS_RTU_MASTER_PARAMETERS pmap)
  85. {
  86. if(!pmap || !pmap->hFifoRX || !pmap->hFifoTX)
  87. return NULL;
  88. LPMODBUS_RTU_MASTER pMst = &g_mbMast;
  89. memset(pMst, 0, sizeof(MODBUS_RTU_MASTER));
  90. memcpy(&pMst->mpt, &pmap->mpt, sizeof(GFA_MODBUS_PROTOCOL_TIMEOUTS));
  91. memcpy(&pMst->appItf, &pmap->appItf, sizeof(GFA_MODBUS_MASTER_APP_INTERFACE));
  92. pMst->oldstate = MB_RTU_MST_Void;
  93. pMst->hFifoRX = pmap->hFifoRX;
  94. pMst->hFifoTX = pmap->hFifoTX;
  95. pMst->nRxTimeoutUs = pmap->nRxTimeoutUs;
  96. return (HMBRTUMST)pMst;
  97. }
  98. /////////////////////////////////////////////////////////////////////////////
  99. void GfaModbusRTUMstRelease(HMBRTUMST hMbMst)
  100. {
  101. }
  102. /////////////////////////////////////////////////////////////////////////////
  103. bool GfaModbusRTUMstStateMachine(HMBRTUMST hMbMst)
  104. {
  105. uint8_t b;
  106. LPMODBUS_RTU_MASTER pMst = (LPMODBUS_RTU_MASTER)hMbMst;
  107. switch(pMst->state)
  108. {
  109. case MB_RTU_MST_Idle:
  110. _PeekStateChange(pMst);
  111. break;
  112. case MB_RTU_MST_TxStart:
  113. _PeekStateChange(pMst);
  114. if( _TimerElapsed(pMst) &&
  115. GfaMbFifoTxPrepare(pMst->hFifoTX, false))
  116. {
  117. if(pMst->appItf.pfnPreTx)
  118. (*pMst->appItf.pfnPreTx)(pMst->nTID, pMst->curSlaveID);
  119. GfaMbFifoClearFlags(pMst->hFifoRX, MB_RTU_FLAG_FRAME_GAP_DETECT, true);
  120. GfaMbFifoSetFlags(pMst->hFifoTX, MB_RTU_FLAG_TRANSMIT_IN_PROGRESS, false);
  121. GfaMbFifoTxStart(pMst->hFifoTX, true);
  122. pMst->state = MB_RTU_MST_TxWaitEnd;
  123. // fall through to next state
  124. }
  125. else
  126. break;
  127. case MB_RTU_MST_TxWaitEnd:
  128. _PeekStateChange(pMst);
  129. if(!GfaMbFifoMatchFlags(pMst->hFifoTX, MB_RTU_FLAG_TRANSMIT_IN_PROGRESS, true))
  130. {
  131. pMst->state = MB_RTU_MST_TxDone;
  132. // fall through to next state
  133. }
  134. else
  135. break;
  136. case MB_RTU_MST_TxDone:
  137. _PeekStateChange(pMst);
  138. pMst->state = MB_RTU_MST_WaitRxFifo;
  139. _RespTimerTrigger(pMst);
  140. if(pMst->appItf.pfnPostTx)
  141. (*pMst->appItf.pfnPostTx)(pMst->nTID, pMst->curSlaveID);
  142. // fall through to next state
  143. case MB_RTU_MST_WaitRxFifo:
  144. _PeekStateChange(pMst);
  145. if(GfaMbFifoPeek(pMst->hFifoRX, true))
  146. {
  147. GfaMbFifoClearFlags(pMst->hFifoRX, MB_RTU_FLAG_FRAME_GAP_DETECT, true);
  148. pMst->state = MB_RTU_MST_RxSlvID;
  149. if(pMst->appItf.pfnRxStart)
  150. (*pMst->appItf.pfnRxStart)(pMst->nTID);
  151. // fall through to next state
  152. }
  153. else
  154. {
  155. if(_TimerElapsed(pMst))
  156. {
  157. pMst->nRxErr = GFA_MB_MST_ERROR_SLAVE_RESPONSE_TIMEOUT;
  158. pMst->state = MB_RTU_MST_ReportError;
  159. }
  160. break;
  161. }
  162. case MB_RTU_MST_RxSlvID:
  163. _PeekStateChange(pMst);
  164. if(!GfaMbFifoPop(pMst->hFifoRX, &b, true))
  165. {
  166. pMst->nRxErr = GFA_MB_MST_ERROR_SLAVE_RESPONSE_TIMEOUT;
  167. pMst->state = MB_RTU_MST_ReportError;
  168. break;
  169. }
  170. else if(pMst->curSlaveID != b)
  171. {
  172. GfaMbFifoSetFlags(pMst->hFifoRX, MB_RTU_FLAG_IGNORE_FRAME, true);
  173. GfaMbFifoReset(pMst->hFifoRX, true);
  174. pMst->nRxErr = GFA_MB_MST_ERROR_INVALID_SLAVE_ID;
  175. pMst->state = MB_RTU_MST_ReportError;
  176. break;
  177. }
  178. pMst->adu.slaveID = b;
  179. pMst->state = MB_RTU_MST_RxFunc;
  180. _CharTimerTrigger(pMst);
  181. // fall through to next state
  182. case MB_RTU_MST_RxFunc:
  183. _PeekStateChange(pMst);
  184. if(!GfaMbFifoPop(pMst->hFifoRX, &b, true))
  185. {
  186. if( GfaMbFifoMatchFlags(pMst->hFifoRX, MB_RTU_FLAG_FRAME_GAP_DETECT, true) ||
  187. _TimerElapsed(pMst))
  188. {
  189. pMst->nRxErr = GFA_MB_MST_ERROR_SLAVE_CHAR_TIMEOUT;
  190. pMst->state = MB_RTU_MST_ReportError;
  191. }
  192. break;
  193. }
  194. else if(b & MB_FUNC_ERROR_FLAG)
  195. {
  196. pMst->nRxErr = GFA_MB_MST_ERROR_SLAVE_ERROR;
  197. pMst->adu.pdu.func = b;
  198. pMst->state = MB_RTU_MST_RxError;
  199. break;
  200. }
  201. else if(b != pMst->curFunc)
  202. {
  203. pMst->nRxErr = GFA_MB_MST_ERROR_INVALID_FUNCTION;
  204. pMst->state = MB_RTU_MST_ReportError;
  205. break;
  206. }
  207. else
  208. {
  209. pMst->adu.pdu.func = b;
  210. pMst->nCbRx = 0;
  211. pMst->state = MB_RTU_MST_RxData;
  212. _CharTimerTrigger(pMst);
  213. // fall through to next state
  214. }
  215. case MB_RTU_MST_RxData:
  216. _PeekStateChange(pMst);
  217. while(pMst->nCbRx < pMst->nCbDataExpected)
  218. {
  219. if(GfaMbFifoPop(pMst->hFifoRX, &b, true))
  220. {
  221. pMst->adu.pdu.b[pMst->nCbRx++] = b;
  222. _CharTimerTrigger(pMst);
  223. }
  224. else
  225. {
  226. if( GfaMbFifoMatchFlags(pMst->hFifoRX, MB_RTU_FLAG_FRAME_GAP_DETECT, true) ||
  227. _TimerElapsed(pMst))
  228. {
  229. pMst->nRxErr = GFA_MB_MST_ERROR_SLAVE_CHAR_TIMEOUT;
  230. pMst->state = MB_RTU_MST_ReportError;
  231. }
  232. break;
  233. }
  234. }
  235. if(pMst->nCbRx == pMst->nCbDataExpected)
  236. {
  237. pMst->nCbRx = 0;
  238. pMst->state = MB_RTU_MST_RxCRC;
  239. _CharTimerTrigger(pMst);
  240. // fall through to next state
  241. }
  242. else
  243. break;
  244. case MB_RTU_MST_RxCRC:
  245. _PeekStateChange(pMst);
  246. while(pMst->nCbRx < sizeof(uint16_t))
  247. {
  248. if(GfaMbFifoPop(pMst->hFifoRX, &b, true))
  249. {
  250. pMst->adu.pdu.b[pMst->nCbDataExpected + pMst->nCbRx++] = b;
  251. _CharTimerTrigger(pMst);
  252. }
  253. else
  254. {
  255. if( GfaMbFifoMatchFlags(pMst->hFifoRX, MB_RTU_FLAG_FRAME_GAP_DETECT, true) ||
  256. _TimerElapsed(pMst))
  257. {
  258. pMst->nRxErr = GFA_MB_MST_ERROR_SLAVE_CHAR_TIMEOUT;
  259. pMst->state = MB_RTU_MST_ReportError;
  260. }
  261. break;
  262. }
  263. }
  264. if(pMst->nCbRx == sizeof(uint16_t))
  265. {
  266. pMst->nCbRx = 0;
  267. pMst->state = MB_RTU_MST_RxFinalize;
  268. // fall through to next state
  269. }
  270. else
  271. break;
  272. case MB_RTU_MST_RxFinalize:
  273. _PeekStateChange(pMst);
  274. _FrameTimerTrigger(pMst);
  275. if(_ValidateADU(pMst))
  276. {
  277. if(pMst->appItf.pfnRxEnd)
  278. (*pMst->appItf.pfnRxEnd)(pMst->nTID);
  279. (*pMst->pfnRawReqComplete)(pMst->nTID, pMst->curSlaveID, pMst->nRxErr, &pMst->adu, pMst->nCbDataExpected, pMst->pParam);
  280. pMst->state = MB_RTU_MST_Idle;
  281. break;
  282. }
  283. pMst->state = MB_RTU_MST_ReportError;
  284. break;
  285. case MB_RTU_MST_RxError:
  286. _PeekStateChange(pMst);
  287. if(!GfaMbFifoPop(pMst->hFifoRX, &b, true))
  288. {
  289. if( GfaMbFifoMatchFlags(pMst->hFifoRX, MB_RTU_FLAG_FRAME_GAP_DETECT, true) ||
  290. _TimerElapsed(pMst))
  291. {
  292. pMst->nRxErr = GFA_MB_MST_ERROR_SLAVE_CHAR_TIMEOUT;
  293. pMst->state = MB_RTU_MST_ReportError;
  294. }
  295. break;
  296. }
  297. pMst->adu.pdu.b[0] = b;
  298. pMst->nCbDataExpected = 1;
  299. pMst->state = MB_RTU_MST_RxCRC;
  300. _CharTimerTrigger(pMst);
  301. break;
  302. case MB_RTU_MST_ReportError:
  303. _PeekStateChange(pMst);
  304. _FrameTimerTrigger(pMst);
  305. if(pMst->appItf.pfnRxEnd)
  306. (*pMst->appItf.pfnRxEnd)(pMst->nTID);
  307. (*pMst->pfnRawReqComplete)(pMst->nTID, pMst->curSlaveID, pMst->nRxErr, NULL, 0, pMst->pParam);
  308. pMst->state = MB_RTU_MST_Idle;
  309. break;
  310. }
  311. return true;
  312. }
  313. /////////////////////////////////////////////////////////////////////////////
  314. /////////////////////////////////////////////////////////////////////////////
  315. /////////////////////////////////////////////////////////////////////////////
  316. static void _OnRawReadRegistersComplete(uint32_t nTID, uint8_t nSlvID, uint16_t err, LPCMODBUS_RTU_ADU padu, size_t nCbData, void *pParam)
  317. {
  318. if(pParam)
  319. {
  320. PFN_GFA_READ_REGISTERS_COMPLETE pfnReadRegsComplete = (PFN_GFA_READ_REGISTERS_COMPLETE)pParam;
  321. uint16_t regs[MODBUS_MAX_READ_REGISTERS];
  322. const void *pRegs = NULL;
  323. size_t nCntRegs = 0;
  324. if(err)
  325. {
  326. if(err == GFA_MB_MST_ERROR_SLAVE_ERROR && padu)
  327. err |= ((uint16_t)padu->pdu.b[0] << 8);
  328. }
  329. else
  330. {
  331. if((nCntRegs = (size_t)padu->pdu.b[0] / sizeof(uint16_t)) <= MODBUS_MAX_READ_REGISTERS)
  332. {
  333. GfaBufCpyUnaligned_uint16(regs, &padu->pdu.b[1], nCntRegs);
  334. pRegs = regs;
  335. }
  336. else
  337. {
  338. pRegs = NULL;
  339. nCntRegs = 0;
  340. err = GFA_MB_MST_ERROR_SLAVE_INVALID_DATA;
  341. }
  342. }
  343. (*pfnReadRegsComplete)(nTID, nSlvID, err, pRegs, nCntRegs);
  344. }
  345. }
  346. /////////////////////////////////////////////////////////////////////////////
  347. static void _OnRawWriteRegistersComplete(uint32_t nTID, uint8_t nSlvID, uint16_t err, LPCMODBUS_RTU_ADU padu, size_t nCbData, void *pParam)
  348. {
  349. if(pParam)
  350. {
  351. PFN_GFA_WRITE_REGISTERS_COMPLETE pfnWriteRegsComplete = (PFN_GFA_WRITE_REGISTERS_COMPLETE)pParam;
  352. uint16_t nStart = 0, nWritten = 0;
  353. if(err)
  354. {
  355. if(err == GFA_MB_MST_ERROR_SLAVE_ERROR && padu)
  356. err |= ((uint16_t)padu->pdu.b[0] << 8);
  357. }
  358. else
  359. {
  360. nStart = GfaBufGetUnaligned_uint16(padu->pdu.b);
  361. nWritten = GfaBufGetUnaligned_uint16(&padu->pdu.b[2]);
  362. }
  363. (*pfnWriteRegsComplete)(nTID, nSlvID, err, nStart, nWritten);
  364. }
  365. }
  366. /////////////////////////////////////////////////////////////////////////////
  367. static void _OnRawPresetSingleRegisterComplete(uint32_t nTID, uint8_t nSlvID, uint16_t err, LPCMODBUS_RTU_ADU padu, size_t nCbData, void *pParam)
  368. {
  369. if(pParam)
  370. {
  371. PFN_GFA_PRESET_SINGLE_REGISTER_COMPLETE pfnPresetRegComplete = (PFN_GFA_PRESET_SINGLE_REGISTER_COMPLETE)pParam;
  372. if(err)
  373. {
  374. if(err == GFA_MB_MST_ERROR_SLAVE_ERROR && padu)
  375. err |= ((uint16_t)padu->pdu.b[0] << 8);
  376. }
  377. (*pfnPresetRegComplete)(nTID, nSlvID, err);
  378. }
  379. }
  380. /////////////////////////////////////////////////////////////////////////////
  381. static void _OnRawDiagnosisComplete(uint32_t nTID, uint8_t nSlvID, uint16_t err, LPCMODBUS_RTU_ADU padu, size_t nCbData, void *pParam)
  382. {
  383. if(pParam)
  384. {
  385. PFN_GFA_DIAGNOSIS_COMPLETE pfnDiagComplete = (PFN_GFA_DIAGNOSIS_COMPLETE)pParam;
  386. uint16_t nSubFunc = 0, nData = 0;
  387. if(err)
  388. {
  389. if(err == GFA_MB_MST_ERROR_SLAVE_ERROR && padu)
  390. err |= ((uint16_t)padu->pdu.b[0] << 8);
  391. }
  392. else
  393. {
  394. nSubFunc = GfaBufGetUnaligned_uint16(padu->pdu.b);
  395. nData = GfaBufGetUnaligned_uint16(&padu->pdu.b[2]);
  396. }
  397. (*pfnDiagComplete)(nTID, nSlvID, err, nSubFunc, nData);
  398. }
  399. }
  400. /////////////////////////////////////////////////////////////////////////////
  401. static void _OnRawReportSlaveIDComplete(uint32_t nTID, uint8_t nSlvID, uint16_t err, LPCMODBUS_RTU_ADU padu, size_t nCbData, void *pParam)
  402. {
  403. if(pParam)
  404. {
  405. PFN_GFA_REPORT_SLAVE_ID_COMPLETE pfnRepSlvIDComplete = (PFN_GFA_REPORT_SLAVE_ID_COMPLETE)pParam;
  406. const void *pData = NULL;
  407. size_t nData = 0;
  408. if(err)
  409. {
  410. if(err == GFA_MB_MST_ERROR_SLAVE_ERROR && padu)
  411. err |= ((uint16_t)padu->pdu.b[0] << 8);
  412. }
  413. else
  414. {
  415. pData = &padu->pdu.b[1];
  416. nData = padu->pdu.b[0];
  417. }
  418. (*pfnRepSlvIDComplete)(nTID, nSlvID, err, pData, nData);
  419. }
  420. }
  421. /////////////////////////////////////////////////////////////////////////////
  422. static size_t _SubFunctionResponseLength(uint16_t nSubFunc)
  423. {
  424. size_t nRet = 0;
  425. switch(nSubFunc)
  426. {
  427. case MB_SUBFUNC_RETURN_QUERY_DATA:
  428. case MB_SUBFUNC_RESTART_COMM_OPTION:
  429. case MB_SUBFUNC_RETURN_DIAGNOSTIC_REGISTER:
  430. case MB_SUBFUNC_CLEAR_CTRS_AND_DIAGNOSTIC_REG:
  431. case MB_SUBFUNC_RETURN_BUS_MESSAGE_COUNT:
  432. case MB_SUBFUNC_RETURN_BUS_COMM_ERROR_COUNT:
  433. case MB_SUBFUNC_RETURN_BUS_EXCEPTION_ERROR_COUNT:
  434. case MB_SUBFUNC_RETURN_SLAVE_MESSAGE_COUNT:
  435. case MB_SUBFUNC_RETURN_SLAVE_NO_RESPONSE_COUNT:
  436. case MB_SUBFUNC_RETURN_SLAVE_NAK_COUNT:
  437. case MB_SUBFUNC_RETURN_SLAVE_BUSY_COUNT:
  438. case MB_SUBFUNC_RETURN_BUS_CHAR_OVERRUN_COUNT:
  439. case MB_SUBFUNC_RETURN_OVERRUN_ERROR_COUNT:
  440. case MB_SUBFUNC_CLEAR_OVERRUN_COUNTER_AND_FLAG:
  441. nRet = 4;
  442. break;
  443. // case MB_SUBFUNC_FORCE_LISTEN_ONLY_MODE:
  444. default:
  445. nRet = (size_t)-1;
  446. break;
  447. }
  448. return nRet;
  449. }
  450. /////////////////////////////////////////////////////////////////////////////
  451. /////////////////////////////////////////////////////////////////////////////
  452. /////////////////////////////////////////////////////////////////////////////
  453. bool GfaModbusRTUMstSendRawRequest(HMBRTUMST hMbMst, uint32_t nTID, uint8_t nSlvID, uint8_t nFunc, const void *pData, size_t nCbData, size_t nCbDataExpected, PFN_GFA_RAW_REQUEST_COMPLETE pfnRawReqComplete, void *pParam)
  454. {
  455. uint16_t nCRC;
  456. LPMODBUS_RTU_MASTER pMst = (LPMODBUS_RTU_MASTER)hMbMst;
  457. if(!pMst || nCbData > MODBUS_MAX_DATA_PAYLOAD || nCbDataExpected > MODBUS_MAX_DATA_PAYLOAD || !pfnRawReqComplete)
  458. return false;
  459. if(!nSlvID || nSlvID > MODBUS_MAX_SLAVE_ID)
  460. return false;
  461. if(pMst->state != MB_RTU_MST_Idle)
  462. return false;
  463. pMst->nTID = nTID;
  464. pMst->curSlaveID = nSlvID;
  465. pMst->curFunc = nFunc;
  466. pMst->nCbDataExpected = nCbDataExpected;
  467. pMst->pfnRawReqComplete = pfnRawReqComplete;
  468. pMst->pParam = pParam;
  469. pMst->nRxErr = 0;
  470. GfaMbFifoReset(pMst->hFifoTX, false);
  471. GfaMbFifoReset(pMst->hFifoRX, false);
  472. GfaMbFifoPush(pMst->hFifoTX, nSlvID, false);
  473. GfaMbFifoPush(pMst->hFifoTX, nFunc, false);
  474. if(pData && nCbData)
  475. GfaMbFifoWrite(pMst->hFifoTX, pData, nCbData, false);
  476. nCRC = GfaMbFifoCalcCRC(pMst->hFifoTX, false);
  477. GfaMbFifoWrite(pMst->hFifoTX, &nCRC, sizeof(nCRC), false);
  478. pMst->state = MB_RTU_MST_TxStart;
  479. return true;
  480. }
  481. bool GfaModbusRTUMstReadHoldingRegisters(HMBRTUMST hMbMst, uint32_t nTID, uint8_t nSlvID, uint16_t nRegStart, uint16_t nRegCount, PFN_GFA_READ_REGISTERS_COMPLETE pfnReadRegsComplete)
  482. {
  483. uint8_t buf[4];
  484. if(!pfnReadRegsComplete)
  485. return false;
  486. GfaBufSetUnaligned_uint16(buf, nRegStart);
  487. GfaBufSetUnaligned_uint16(&buf[2], nRegCount);
  488. return GfaModbusRTUMstSendRawRequest(hMbMst, nTID, nSlvID, MB_FUNC_READ_HOLDING_REGISTERS, buf, sizeof(buf), 1 + nRegCount * sizeof(uint16_t), _OnRawReadRegistersComplete, pfnReadRegsComplete);
  489. }
  490. /////////////////////////////////////////////////////////////////////////////
  491. bool GfaModbusRTUMstReadInputRegisters(HMBRTUMST hMbMst, uint32_t nTID, uint8_t nSlvID, uint16_t nRegStart, uint16_t nRegCount, PFN_GFA_READ_REGISTERS_COMPLETE pfnReadRegsComplete)
  492. {
  493. uint8_t buf[4];
  494. if(!pfnReadRegsComplete)
  495. return false;
  496. GfaBufSetUnaligned_uint16(buf, nRegStart);
  497. GfaBufSetUnaligned_uint16(&buf[2], nRegCount);
  498. return GfaModbusRTUMstSendRawRequest(hMbMst, nTID, nSlvID, MB_FUNC_READ_INPUT_REGISTERS, buf, sizeof(buf), 1 + nRegCount * sizeof(uint16_t), _OnRawReadRegistersComplete, pfnReadRegsComplete);
  499. }
  500. /////////////////////////////////////////////////////////////////////////////
  501. bool GfaModbusRTUMstWriteMultipleRegisters(HMBRTUMST hMbMst, uint32_t nTID, uint8_t nSlvID, uint16_t nRegStart, uint16_t nRegCount, const void *pRegData, PFN_GFA_WRITE_REGISTERS_COMPLETE pfnWriteRegsComplete)
  502. {
  503. uint8_t buf[MODBUS_MAX_WRITE_REGISTERS * sizeof(uint16_t)];
  504. const uint8_t *pData = (const uint8_t*)pRegData;
  505. size_t nCbData = 0;
  506. if(!pfnWriteRegsComplete)
  507. return false;
  508. if(nRegCount > MODBUS_MAX_WRITE_REGISTERS)
  509. return false;
  510. GfaBufSetUnaligned_uint16(&buf[nCbData], nRegStart);
  511. nCbData += 2;
  512. GfaBufSetUnaligned_uint16(&buf[nCbData], nRegCount);
  513. nCbData += 2;
  514. buf[nCbData++] = (uint8_t)(nRegCount * sizeof(uint16_t));
  515. GfaBufCpyUnaligned_uint16(&buf[nCbData], pData, nRegCount);
  516. nCbData += nRegCount * sizeof(uint16_t);
  517. return GfaModbusRTUMstSendRawRequest(hMbMst, nTID, nSlvID, MB_FUNC_WRITE_MULTIPLE_REGISTERS, buf, nCbData, 2 * sizeof(uint16_t), _OnRawWriteRegistersComplete, pfnWriteRegsComplete);
  518. }
  519. /////////////////////////////////////////////////////////////////////////////
  520. bool GfaModbusRTUMstPresetSingleRegister(HMBRTUMST hMbMst, uint32_t nTID, uint8_t nSlvID, uint16_t nRegAddr, uint16_t nRegVal, PFN_GFA_PRESET_SINGLE_REGISTER_COMPLETE pfnPresetRegComplete)
  521. {
  522. uint8_t buf[4];
  523. if(!pfnPresetRegComplete)
  524. return false;
  525. GfaBufSetUnaligned_uint16(buf, nRegAddr);
  526. GfaBufSetUnaligned_uint16(&buf[2], nRegVal);
  527. return GfaModbusRTUMstSendRawRequest(hMbMst, nTID, nSlvID, MB_FUNC_PRESET_SINGLE_REGISTER, buf, sizeof(buf), 4, _OnRawPresetSingleRegisterComplete, pfnPresetRegComplete);
  528. }
  529. bool GfaModbusRTUMstDiagnosis(HMBRTUMST hMbMst, uint32_t nTID, uint8_t nSlvID, uint16_t nSubFunc, uint16_t nData, PFN_GFA_DIAGNOSIS_COMPLETE pfnDiagComplete)
  530. {
  531. uint8_t buf[4];
  532. if(!pfnDiagComplete)
  533. return false;
  534. GfaBufSetUnaligned_uint16(buf, nSubFunc);
  535. GfaBufSetUnaligned_uint16(&buf[2], nData);
  536. size_t nResponseLength = _SubFunctionResponseLength(nSubFunc);
  537. if(nResponseLength == (size_t)-1)
  538. return false;
  539. return GfaModbusRTUMstSendRawRequest(hMbMst, nTID, nSlvID, MB_FUNC_DIAGNOSTIC, buf, sizeof(buf), nResponseLength, _OnRawDiagnosisComplete, pfnDiagComplete);
  540. }
  541. /////////////////////////////////////////////////////////////////////////////
  542. bool GfaModbusRTUMstReportSlaveID(HMBRTUMST hMbMst, uint32_t nTID, uint8_t nSlvID, size_t nCbDataExpected, PFN_GFA_REPORT_SLAVE_ID_COMPLETE pfnRepSlvIDComplete)
  543. {
  544. if(!pfnRepSlvIDComplete)
  545. return false;
  546. return GfaModbusRTUMstSendRawRequest(hMbMst, nTID, nSlvID, MB_FUNC_REPORT_SLAVE_ID, NULL, 0, nCbDataExpected, _OnRawReportSlaveIDComplete, pfnRepSlvIDComplete);
  547. }