mbs_core.c 85 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889
  1. /*
  2. *********************************************************************************************************
  3. * uC/Modbus
  4. * The Embedded Modbus Stack
  5. *
  6. * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com
  7. *
  8. * SPDX-License-Identifier: APACHE-2.0
  9. *
  10. * This software is subject to an open source license and is distributed by
  11. * Silicon Laboratories Inc. pursuant to the terms of the Apache License,
  12. * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
  13. *
  14. *********************************************************************************************************
  15. */
  16. /*
  17. *********************************************************************************************************
  18. * uC/MODBUS SLAVE COMMAND PROCESSOR
  19. *
  20. * Filename : mbs_core.c
  21. * Version : V2.14.00
  22. *********************************************************************************************************
  23. */
  24. /*
  25. *********************************************************************************************************
  26. * INCLUDE FILES
  27. *********************************************************************************************************
  28. */
  29. #define MBS_MODULE
  30. #include "mb.h"
  31. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  32. /*
  33. *********************************************************************************************************
  34. * LOCAL DEFINES
  35. *********************************************************************************************************
  36. */
  37. /*
  38. *********************************************************************************************************
  39. * LOCAL CONSTANTS
  40. *********************************************************************************************************
  41. */
  42. /*
  43. *********************************************************************************************************
  44. * LOCAL DATA TYPES
  45. *********************************************************************************************************
  46. */
  47. /*
  48. *********************************************************************************************************
  49. * LOCAL TABLES
  50. *********************************************************************************************************
  51. */
  52. /*
  53. *********************************************************************************************************
  54. * LOCAL GLOBAL VARIABLES
  55. *********************************************************************************************************
  56. */
  57. /*
  58. *********************************************************************************************************
  59. * LOCAL MACRO'S
  60. *********************************************************************************************************
  61. */
  62. #define MBS_RX_DATA_START (((CPU_INT16U)pch->RxFrameData[2] << 8) + (CPU_INT16U)pch->RxFrameData[3])
  63. #define MBS_RX_DATA_START_H (pch->RxFrameData[2])
  64. #define MBS_RX_DATA_START_L (pch->RxFrameData[3])
  65. #define MBS_RX_DATA_POINTS (((CPU_INT16U)pch->RxFrameData[4] << 8) + (CPU_INT16U)pch->RxFrameData[5])
  66. #define MBS_RX_DATA_POINTS_H (pch->RxFrameData[4])
  67. #define MBS_RX_DATA_POINTS_L (pch->RxFrameData[5])
  68. #define MBS_RX_DATA_BYTES (pch->RxFrameData[6])
  69. #define MBS_RX_DATA_COIL (((CPU_INT16U)pch->RxFrameData[4] << 8) + (CPU_INT16U)pch->RxFrameData[5])
  70. #define MBS_RX_DATA_COIL_H (pch->RxFrameData[4])
  71. #define MBS_RX_DATA_COIL_L (pch->RxFrameData[5])
  72. #define MBS_RX_DATA_REG (((CPU_INT16U)pch->RxFrameData[4] << 8) + (CPU_INT16U)pch->RxFrameData[5])
  73. #define MBS_RX_DATA_REG_H (pch->RxFrameData[4])
  74. #define MBS_RX_DATA_REG_L (pch->RxFrameData[5])
  75. #define MBS_RX_DIAG_CODE (((CPU_INT16U)pch->RxFrameData[2] << 8) + (CPU_INT16U)pch->RxFrameData[3])
  76. #define MBS_RX_DIAG_CODE_H (pch->RxFrameData[2])
  77. #define MBS_RX_DIAG_CODE_L (pch->RxFrameData[3])
  78. #define MBS_RX_DIAG_DATA (((CPU_INT16U)pch->RxFrameData[4] << 8) + (CPU_INT16U)pch->RxFrameData[5])
  79. #define MBS_RX_DIAG_DATA_H (pch->RxFrameData[4])
  80. #define MBS_RX_DIAG_DATA_L (pch->RxFrameData[5])
  81. #define MBS_RX_FRAME (&pch->RxFrame)
  82. #define MBS_RX_FRAME_ADDR (pch->RxFrameData[0])
  83. #define MBS_RX_FRAME_FC (pch->RxFrameData[1])
  84. #define MBS_RX_FRAME_DATA (pch->RxFrameData[2])
  85. #define MBS_RX_FRAME_NBYTES (pch->RxFrameNDataBytes)
  86. #define MBS_TX_DATA_START_H (pch->TxFrameData[2])
  87. #define MBS_TX_DATA_START_L (pch->TxFrameData[3])
  88. #define MBS_TX_DATA_POINTS_H (pch->TxFrameData[4])
  89. #define MBS_TX_DATA_POINTS_L (pch->TxFrameData[5])
  90. #define MBS_TX_DATA_COIL_H (pch->TxFrameData[4])
  91. #define MBS_TX_DATA_COIL_L (pch->TxFrameData[5])
  92. #define MBS_TX_DATA_REG_H (pch->TxFrameData[4])
  93. #define MBS_TX_DATA_REG_L (pch->TxFrameData[5])
  94. #define MBS_TX_DIAG_CODE_H (pch->TxFrameData[2])
  95. #define MBS_TX_DIAG_CODE_L (pch->TxFrameData[3])
  96. #define MBS_TX_DIAG_DATA_H (pch->TxFrameData[4])
  97. #define MBS_TX_DIAG_DATA_L (pch->TxFrameData[5])
  98. #define MBS_TX_FRAME (&pch->TxFrame)
  99. #define MBS_TX_FRAME_ADDR (pch->TxFrameData[0])
  100. #define MBS_TX_FRAME_FC (pch->TxFrameData[1])
  101. #define MBS_TX_FRAME_DATA (pch->TxFrameData[2])
  102. #define MBS_TX_FRAME_NBYTES (pch->TxFrameNDataBytes)
  103. /*
  104. *********************************************************************************************************
  105. * LOCAL FUNCTION PROTOTYPES
  106. *********************************************************************************************************
  107. */
  108. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  109. static void MBS_ErrRespSet (MODBUS_CH *pch,
  110. CPU_INT08U errcode);
  111. #if (MODBUS_CFG_FC01_EN == DEF_ENABLED)
  112. static CPU_BOOLEAN MBS_FC01_CoilRd (MODBUS_CH *pch);
  113. #endif
  114. #if (MODBUS_CFG_FC02_EN == DEF_ENABLED)
  115. static CPU_BOOLEAN MBS_FC02_DIRd (MODBUS_CH *pch);
  116. #endif
  117. #if (MODBUS_CFG_FC03_EN == DEF_ENABLED)
  118. static CPU_BOOLEAN MBS_FC03_HoldingRegRd (MODBUS_CH *pch);
  119. #endif
  120. #if (MODBUS_CFG_FC04_EN == DEF_ENABLED)
  121. static CPU_BOOLEAN MBS_FC04_InRegRd (MODBUS_CH *pch);
  122. #endif
  123. #if (MODBUS_CFG_FC05_EN == DEF_ENABLED)
  124. static CPU_BOOLEAN MBS_FC05_CoilWr (MODBUS_CH *pch);
  125. #endif
  126. #if (MODBUS_CFG_FC06_EN == DEF_ENABLED)
  127. static CPU_BOOLEAN MBS_FC06_HoldingRegWr (MODBUS_CH *pch);
  128. #endif
  129. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  130. static CPU_BOOLEAN MBS_FC08_Loopback (MODBUS_CH *pch);
  131. #endif
  132. #if (MODBUS_CFG_FC15_EN == DEF_ENABLED)
  133. static CPU_BOOLEAN MBS_FC15_CoilWrMultiple (MODBUS_CH *pch);
  134. #endif
  135. #if (MODBUS_CFG_FC16_EN == DEF_ENABLED)
  136. static CPU_BOOLEAN MBS_FC16_HoldingRegWrMultiple(MODBUS_CH *pch);
  137. #endif
  138. #if (MODBUS_CFG_FC20_EN == DEF_ENABLED)
  139. static CPU_BOOLEAN MBS_FC20_FileRd (MODBUS_CH *pch);
  140. #endif
  141. #if (MODBUS_CFG_FC21_EN == DEF_ENABLED)
  142. static CPU_BOOLEAN MBS_FC21_FileWr (MODBUS_CH *pch);
  143. #endif
  144. #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED)
  145. static void MBS_ASCII_Task (MODBUS_CH *pch);
  146. #endif
  147. #if (MODBUS_CFG_RTU_EN == DEF_ENABLED)
  148. static void MBS_RTU_Task (MODBUS_CH *pch);
  149. #endif
  150. #endif
  151. /*
  152. *********************************************************************************************************
  153. * LOCAL CONFIGURATION ERRORS
  154. *********************************************************************************************************
  155. */
  156. /*
  157. *********************************************************************************************************
  158. * MBS_ErrRespSet()
  159. *
  160. * Description : This function sets the indicated error response code into the response frame. Then the
  161. * routine is called to calculate the error check value.
  162. *
  163. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  164. *
  165. * errcode An unsigned byte value containing the error code that is to be placed in the
  166. * response frame.
  167. *
  168. * Return(s) : none.
  169. *
  170. * Caller(s) : MBS_FCxx_Handler(),
  171. * Modbus Slave functions.
  172. *
  173. * Note(s) : none.
  174. *********************************************************************************************************
  175. */
  176. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  177. static void MBS_ErrRespSet (MODBUS_CH *pch,
  178. CPU_INT08U err_code)
  179. {
  180. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  181. pch->StatExceptCtr++;
  182. #endif
  183. MBS_TX_FRAME_ADDR = MBS_RX_FRAME_ADDR;
  184. MBS_TX_FRAME_FC = MBS_RX_FRAME_FC | 0x80; /* Set the high order bit of the function code. */
  185. MBS_TX_FRAME_DATA = err_code; /* Set the high order bit of the function code. */
  186. MBS_TX_FRAME_NBYTES = 1; /* Nbr of data bytes in exception response is 1. */
  187. }
  188. #endif
  189. /*
  190. *********************************************************************************************************
  191. * MBS_FCxx_Handler()
  192. *
  193. * Description : This is the main processing function for MODBUS commands. The message integrity is
  194. * verified, and if valid, the function requested is processed. Unimplemented functions
  195. * will generate an Illegal Function Exception Response code (01).
  196. *
  197. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  198. *
  199. * Return(s) : none.
  200. *
  201. * Caller(s) : MBS_ASCII_Task(),
  202. * MBS_RTU_Task().
  203. *
  204. * Note(s) : none.
  205. *********************************************************************************************************
  206. */
  207. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  208. CPU_BOOLEAN MBS_FCxx_Handler (MODBUS_CH *pch)
  209. {
  210. CPU_BOOLEAN send_reply;
  211. send_reply = DEF_FALSE;
  212. if ((MBS_RX_FRAME_ADDR == pch->NodeAddr) || /* Proper node address? (i.e. Is this message for us?) */
  213. (MBS_RX_FRAME_ADDR == 0)) { /* ... or a 'broadcast' address? */
  214. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  215. pch->StatSlaveMsgCtr++;
  216. #endif
  217. switch (MBS_RX_FRAME_FC) { /* Handle the function requested in the frame. */
  218. #if (MODBUS_CFG_FC01_EN == DEF_ENABLED)
  219. case MODBUS_FC01_COIL_RD:
  220. send_reply = MBS_FC01_CoilRd(pch);
  221. break;
  222. #endif
  223. #if (MODBUS_CFG_FC02_EN == DEF_ENABLED)
  224. case MODBUS_FC02_DI_RD:
  225. send_reply = MBS_FC02_DIRd(pch);
  226. break;
  227. #endif
  228. #if (MODBUS_CFG_FC03_EN == DEF_ENABLED)
  229. case MODBUS_FC03_HOLDING_REG_RD: /* Process read output registers command. */
  230. send_reply = MBS_FC03_HoldingRegRd(pch);
  231. break;
  232. #endif
  233. #if (MODBUS_CFG_FC04_EN == DEF_ENABLED)
  234. case MODBUS_FC04_IN_REG_RD:
  235. send_reply = MBS_FC04_InRegRd(pch);
  236. break;
  237. #endif
  238. #if (MODBUS_CFG_FC05_EN == DEF_ENABLED)
  239. case MODBUS_FC05_COIL_WR:
  240. if (pch->WrEn == DEF_TRUE) {
  241. send_reply = MBS_FC05_CoilWr(pch);
  242. } else {
  243. send_reply = DEF_FALSE;
  244. }
  245. break;
  246. #endif
  247. #if (MODBUS_CFG_FC06_EN == DEF_ENABLED)
  248. case MODBUS_FC06_HOLDING_REG_WR:
  249. if (pch->WrEn == DEF_TRUE) {
  250. send_reply = MBS_FC06_HoldingRegWr(pch);
  251. } else {
  252. send_reply = DEF_FALSE;
  253. }
  254. break;
  255. #endif
  256. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  257. case MODBUS_FC08_LOOPBACK:
  258. send_reply = MBS_FC08_Loopback(pch); /* Process loopback command. */
  259. break;
  260. #endif
  261. #if (MODBUS_CFG_FC15_EN == DEF_ENABLED)
  262. case MODBUS_FC15_COIL_WR_MULTIPLE:
  263. if (pch->WrEn == DEF_TRUE) {
  264. send_reply = MBS_FC15_CoilWrMultiple(pch);
  265. } else {
  266. send_reply = DEF_FALSE;
  267. }
  268. break;
  269. #endif
  270. #if (MODBUS_CFG_FC16_EN == DEF_ENABLED)
  271. case MODBUS_FC16_HOLDING_REG_WR_MULTIPLE:
  272. if (pch->WrEn == DEF_TRUE) {
  273. send_reply = MBS_FC16_HoldingRegWrMultiple(pch);
  274. } else {
  275. send_reply = DEF_FALSE;
  276. }
  277. break;
  278. #endif
  279. #if (MODBUS_CFG_FC20_EN == DEF_ENABLED)
  280. case MODBUS_FC20_FILE_RD:
  281. send_reply = MBS_FC20_FileRd(pch);
  282. break;
  283. #endif
  284. #if (MODBUS_CFG_FC21_EN == DEF_ENABLED)
  285. case MODBUS_FC21_FILE_WR:
  286. if (pch->WrEn == DEF_TRUE) {
  287. send_reply = MBS_FC21_FileWr(pch);
  288. } else {
  289. send_reply = DEF_FALSE;
  290. }
  291. break;
  292. #endif
  293. default: /* Function code not implemented, set error response. */
  294. pch->Err = MODBUS_ERR_ILLEGAL_FC;
  295. MBS_ErrRespSet(pch,
  296. MODBUS_ERR_ILLEGAL_FC);
  297. send_reply = DEF_TRUE;
  298. break;
  299. }
  300. }
  301. if (MBS_RX_FRAME_ADDR == 0) { /* Was the command received a 'broadcast'? */
  302. return (DEF_FALSE); /* Yes, don't reply */
  303. } else {
  304. return (send_reply); /* No, reply according to the outcome of the command */
  305. }
  306. }
  307. #endif
  308. /*
  309. *********************************************************************************************************
  310. * MBS_FC01_CoilRd()
  311. *
  312. * Description : Responds to a request to read the status of any number of coils.
  313. *
  314. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  315. *
  316. * Return(s) : DEF_TRUE If a response needs to be sent
  317. * DEF_FALSE If not
  318. *
  319. * Caller(s) : MBS_FCxx_Handler().
  320. *
  321. * Note(s) : 1) RX command format: Example:
  322. * <slave address> 0x11
  323. * <function code> 0x01
  324. * <start address HI> 0x00
  325. * <start address LO> 0x13
  326. * <# coils HI> 0x00
  327. * <# coils LO> 0x25
  328. * <Error Check (LRC or CRC)> 0x??
  329. *
  330. * 2) TX reply format: Example:
  331. * <slave address> 0x11
  332. * <function code> 0x01
  333. * <byte count> 0x05
  334. * <Data Coils> 0xCD (Bit set to 1 means ON, Bit cleared means == OFF)
  335. * <Data Coils> 0x6B (Bit set to 1 means ON, Bit cleared means == OFF)
  336. * <Data Coils> 0xB2 (Bit set to 1 means ON, Bit cleared means == OFF)
  337. * <Data Coils> 0x0E (Bit set to 1 means ON, Bit cleared means == OFF)
  338. * <Data Coils> 0x1B (Bit set to 1 means ON, Bit cleared means == OFF)
  339. * <Error Check (LRC or CRC)> 0x??
  340. *********************************************************************************************************
  341. */
  342. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  343. #if (MODBUS_CFG_FC01_EN == DEF_ENABLED)
  344. static CPU_BOOLEAN MBS_FC01_CoilRd (MODBUS_CH *pch)
  345. {
  346. CPU_INT08U *presp;
  347. CPU_INT16U coil;
  348. CPU_BOOLEAN coil_val;
  349. CPU_INT16U err;
  350. CPU_INT16U nbr_coils;
  351. CPU_INT16U nbr_bytes;
  352. CPU_INT08U bit_mask;
  353. CPU_INT16U ix;
  354. if (pch->RxFrameNDataBytes != 4) { /* 4 data bytes for this message. */
  355. return (DEF_FALSE); /* Tell caller that we DON'T need to send a response */
  356. }
  357. coil = MBS_RX_DATA_START; /* Get the starting address of the desired coils */
  358. nbr_coils = MBS_RX_DATA_POINTS; /* Find out how many coils */
  359. if (nbr_coils == 0 || nbr_coils > 2000) { /* Make sure we don't exceed the allowed limit per request */
  360. pch->Err = MODBUS_ERR_FC01_01;
  361. MBS_ErrRespSet(pch,
  362. MODBUS_ERR_ILLEGAL_DATA_QTY);
  363. return (DEF_TRUE); /* Tell caller that we need to send a response */
  364. }
  365. nbr_bytes = ((nbr_coils - 1) / 8) + 1; /* Find #bytes needed for response. */
  366. pch->TxFrameNDataBytes = nbr_bytes + 1; /* Number of data bytes + byte count. */
  367. presp = &pch->TxFrameData[0]; /* Clear bytes in response */
  368. for (ix = 0; ix < (nbr_bytes + 3); ix++) {
  369. *presp++ = 0x00;
  370. }
  371. bit_mask = 0x01; /* Start with bit 0 in response byte data mask. */
  372. ix = 0; /* Initialize loop counter. */
  373. presp = &pch->TxFrameData[0]; /* Reset the pointer to the start of the response */
  374. *presp++ = MBS_RX_FRAME_ADDR; /* Prepare response packet */
  375. *presp++ = MBS_RX_FRAME_FC;
  376. *presp++ = (CPU_INT08U)nbr_bytes; /* Set number of data bytes in response message. */
  377. while (ix < nbr_coils) { /* Loop through each COIL requested. */
  378. coil_val = MB_CoilRd(coil, /* Get the current value of the coil */
  379. &err);
  380. switch (err) {
  381. case MODBUS_ERR_NONE:
  382. if (coil_val == MODBUS_COIL_ON) { /* Only set data response bit if COIL is on. */
  383. *presp |= bit_mask;
  384. }
  385. coil++;
  386. ix++; /* Increment COIL counter. */
  387. if ((ix % 8) == 0) { /* Determine if 8 data bits have been filled. */
  388. bit_mask = 0x01; /* Reset the data mask. */
  389. presp++; /* Increment data frame index. */
  390. } else { /* Still in same data byte, so */
  391. bit_mask <<= 1; /* Shift the data mask to the next higher bit position. */
  392. }
  393. break;
  394. case MODBUS_ERR_RANGE:
  395. default:
  396. pch->Err = MODBUS_ERR_FC01_02;
  397. MBS_ErrRespSet(pch,
  398. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  399. return (DEF_TRUE); /* Tell caller that we need to send a response */
  400. }
  401. }
  402. pch->Err = MODBUS_ERR_NONE;
  403. return (DEF_TRUE); /* Tell caller that we need to send a response */
  404. }
  405. #endif
  406. #endif
  407. /*
  408. *********************************************************************************************************
  409. * MBS_FC02_DIRd()
  410. *
  411. * Description : Responds to a request to read the status of any number of Discrete Inputs (DIs).
  412. *
  413. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  414. *
  415. * Return(s) : DEF_TRUE If a response needs to be sent
  416. * DEF_FALSE If not
  417. *
  418. * Caller(s) : MBS_FCxx_Handler().
  419. *
  420. * Note(s) : 1) RX command format: Example:
  421. * <slave address> 0x11
  422. * <function code> 0x02
  423. * <start address HI> 0x00
  424. * <start address LO> 0xC4
  425. * <# input statuses HI> 0x00
  426. * <# input statuses LO> 0x16
  427. * <Error Check (LRC or CRC)> 0x??
  428. *
  429. * 2) TX reply format: Example:
  430. * <slave address> 0x11
  431. * <function code> 0x02
  432. * <byte count> 0x03
  433. * <Data Inputs> 0xAC (Bit set to 1 means ON, Bit cleared means == OFF)
  434. * <Data Inputs> 0xDB (Bit set to 1 means ON, Bit cleared means == OFF)
  435. * <Data Inputs> 0x35 (Bit set to 1 means ON, Bit cleared means == OFF)
  436. * <Error Check (LRC or CRC)> 0x??
  437. *********************************************************************************************************
  438. */
  439. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  440. #if (MODBUS_CFG_FC02_EN == DEF_ENABLED)
  441. static CPU_BOOLEAN MBS_FC02_DIRd (MODBUS_CH *pch)
  442. {
  443. CPU_INT08U *presp;
  444. CPU_INT16U di;
  445. CPU_BOOLEAN di_val;
  446. CPU_INT16U err;
  447. CPU_INT16U nbr_di;
  448. CPU_INT16U nbr_bytes;
  449. CPU_INT08U bit_mask;
  450. CPU_INT16U ix;
  451. if (pch->RxFrameNDataBytes != 4) { /* 4 data bytes for this message. */
  452. return (DEF_FALSE); /* Tell caller that we DON'T need to send a response */
  453. }
  454. di = MBS_RX_DATA_START; /* Get the starting address of the desired DIs */
  455. nbr_di = MBS_RX_DATA_POINTS; /* Find out how many DIs */
  456. if (nbr_di == 0 || nbr_di > 2000) { /* Make sure we don't exceed the allowed limit per request */
  457. pch->Err = MODBUS_ERR_FC02_01;
  458. MBS_ErrRespSet(pch,
  459. MODBUS_ERR_ILLEGAL_DATA_QTY);
  460. return (DEF_TRUE); /* Tell caller that we need to send a response */
  461. }
  462. nbr_bytes = ((nbr_di - 1) / 8) + 1; /* Find #bytes needed for response. */
  463. pch->TxFrameNDataBytes = nbr_bytes + 1; /* Number of data bytes + byte count. */
  464. presp = &pch->TxFrameData[0]; /* Clear bytes in response */
  465. for (ix = 0; ix < (nbr_bytes + 3); ix++) {
  466. *presp++ = 0x00;
  467. }
  468. bit_mask = 0x01; /* Start with bit 0 in response byte data mask. */
  469. ix = 0; /* Initialize loop counter. */
  470. presp = &pch->TxFrameData[0]; /* Reset the pointer to the start of the response */
  471. *presp++ = MBS_RX_FRAME_ADDR; /* Prepare response packet */
  472. *presp++ = MBS_RX_FRAME_FC;
  473. *presp++ = (CPU_INT08U)nbr_bytes; /* Set number of data bytes in response message. */
  474. while (ix < nbr_di) { /* Loop through each DI requested. */
  475. di_val = MB_DIRd(di, /* Get the current value of the DI */
  476. &err);
  477. switch (err) {
  478. case MODBUS_ERR_NONE:
  479. if (di_val == MODBUS_COIL_ON) { /* Only set data response bit if DI is on. */
  480. *presp |= bit_mask;
  481. }
  482. di++;
  483. ix++; /* Increment DI counter. */
  484. if ((ix % 8) == 0) { /* Determine if 8 data bits have been filled. */
  485. bit_mask = 0x01; /* Reset the data mask. */
  486. presp++; /* Increment data frame index. */
  487. } else { /* Still in same data byte, so */
  488. bit_mask <<= 1; /* Shift the data mask to the next higher bit position. */
  489. }
  490. break;
  491. case MODBUS_ERR_RANGE:
  492. default:
  493. pch->Err = MODBUS_ERR_FC02_02;
  494. MBS_ErrRespSet(pch,
  495. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  496. return (DEF_TRUE); /* Tell caller that we need to send a response */
  497. }
  498. }
  499. pch->Err = MODBUS_ERR_NONE;
  500. return (DEF_TRUE); /* Tell caller that we need to send a response */
  501. }
  502. #endif
  503. #endif
  504. /*
  505. *********************************************************************************************************
  506. * MBS_FC03_HoldingRegRd()
  507. *
  508. * Description : Obtains the contents of the specified holding registers.
  509. *
  510. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  511. *
  512. * Return(s) : DEF_TRUE If a response needs to be sent
  513. * DEF_FALSE If not
  514. *
  515. * Caller(s) : MBS_FCxx_Handler().
  516. *
  517. * Note(s) : 1) RX command format: Example:
  518. * <slave address> 0x11
  519. * <function code> 0x03
  520. * <start address HI> 0x00
  521. * <start address LO> 0x6B
  522. * <# registers HI> 0x00
  523. * <# registers LO> 0x03
  524. * <Error Check (LRC or CRC)> 0x??
  525. *
  526. * 2) TX reply format: Example:
  527. * <slave address> 0x11
  528. * <function code> 0x03
  529. * <byte count> 0x06
  530. * <Data HI register> 0x02
  531. * <Data LO register> 0x2B
  532. * <Data HI register> 0x00
  533. * <Data LO register> 0x00
  534. * <Data HI register> 0x00
  535. * <Data LO register> 0x64
  536. * <Error Check (LRC or CRC)> 0x??
  537. *********************************************************************************************************
  538. */
  539. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  540. #if (MODBUS_CFG_FC03_EN == DEF_ENABLED)
  541. static CPU_BOOLEAN MBS_FC03_HoldingRegRd (MODBUS_CH *pch)
  542. {
  543. CPU_INT08U *presp;
  544. CPU_INT16U err;
  545. CPU_INT16U reg;
  546. CPU_INT16U nbr_regs;
  547. CPU_INT16U nbr_bytes;
  548. CPU_INT16U reg_val_16;
  549. #if (MODBUS_CFG_FP_EN == DEF_ENABLED)
  550. CPU_INT08U ix;
  551. CPU_FP32 reg_val_fp;
  552. CPU_INT08U *pfp;
  553. #endif
  554. if (pch->RxFrameNDataBytes != 4) { /* Nbr of data bytes must be 4. */
  555. return (DEF_FALSE); /* Tell caller that we DON'T need to send a response */
  556. }
  557. reg = MBS_RX_DATA_START;
  558. nbr_regs = MBS_RX_DATA_POINTS;
  559. #if (MODBUS_CFG_FP_EN == DEF_ENABLED)
  560. if (reg < MODBUS_CFG_FP_START_IX) { /* See if we want integer registers */
  561. if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */
  562. pch->Err = MODBUS_ERR_FC03_03;
  563. MBS_ErrRespSet(pch,
  564. MODBUS_ERR_ILLEGAL_DATA_QTY);
  565. return (DEF_TRUE); /* Tell caller that we need to send a response */
  566. }
  567. nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_INT16U)); /* Find #bytes needed for response. */
  568. } else {
  569. if (nbr_regs == 0 || nbr_regs > 62) { /* Make sure we don't exceed the allowed limit per request */
  570. pch->Err = MODBUS_ERR_FC03_04;
  571. MBS_ErrRespSet(pch,
  572. MODBUS_ERR_ILLEGAL_DATA_QTY);
  573. return (DEF_TRUE); /* Tell caller that we need to send a response */
  574. }
  575. nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_FP32)); /* Find #bytes needed for response. */
  576. }
  577. #else
  578. if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */
  579. pch->Err = MODBUS_ERR_FC03_03;
  580. MBS_ErrRespSet(pch,
  581. MODBUS_ERR_ILLEGAL_DATA_QTY);
  582. return (DEF_TRUE); /* Tell caller that we need to send a response */
  583. }
  584. nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_INT16U)); /* Find #bytes needed for response. */
  585. #endif
  586. pch->TxFrameNDataBytes = nbr_bytes + 1; /* Number of data bytes + byte count. */
  587. presp = &pch->TxFrameData[0]; /* Reset the pointer to the start of the response */
  588. *presp++ = MBS_RX_FRAME_ADDR;
  589. *presp++ = MBS_RX_FRAME_FC;
  590. *presp++ = (CPU_INT08U)nbr_bytes; /* Set number of data bytes in response message */
  591. while (nbr_regs > 0) { /* Loop through each register requested. */
  592. if (reg < MODBUS_CFG_FP_START_IX) { /* See if we want an integer register */
  593. reg_val_16 = MB_HoldingRegRd(reg, /* Yes, get its value */
  594. &err);
  595. switch (err) {
  596. case MODBUS_ERR_NONE:
  597. *presp++ = (CPU_INT08U)((reg_val_16 >> 8) & 0x00FF); /* Get MSB first. */
  598. *presp++ = (CPU_INT08U)(reg_val_16 & 0x00FF); /* Get LSB next. */
  599. break;
  600. case MODBUS_ERR_RANGE:
  601. default:
  602. pch->Err = MODBUS_ERR_FC03_01;
  603. MBS_ErrRespSet(pch,
  604. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  605. return (DEF_TRUE);
  606. }
  607. } else {
  608. #if (MODBUS_CFG_FP_EN == DEF_ENABLED)
  609. reg_val_fp = MB_HoldingRegRdFP(reg, /* No, get the value of the FP register */
  610. &err);
  611. switch (err) {
  612. case MODBUS_ERR_NONE:
  613. pfp = (CPU_INT08U *)&reg_val_fp; /* Point to the FP register */
  614. #if (CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG)
  615. for (ix = 0; ix < sizeof(CPU_FP32); ix++) { /* Copy value to response buffer */
  616. *presp++ = *pfp++;
  617. }
  618. #else
  619. pfp += sizeof(CPU_FP32) - 1;
  620. for (ix = 0; ix < sizeof(CPU_FP32); ix++) {
  621. *presp++ = *pfp--;
  622. }
  623. #endif
  624. break;
  625. case MODBUS_ERR_RANGE:
  626. default:
  627. pch->Err = MODBUS_ERR_FC03_02;
  628. MBS_ErrRespSet(pch,
  629. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  630. return (DEF_TRUE);
  631. }
  632. #endif
  633. }
  634. reg++; /* Increment current register number */
  635. nbr_regs--;
  636. }
  637. pch->Err = MODBUS_ERR_NONE;
  638. return (DEF_TRUE); /* Tell caller that we need to send a response */
  639. }
  640. #endif
  641. #endif
  642. /*
  643. *********************************************************************************************************
  644. * MBS_FC04_InRegRd()
  645. *
  646. * Description : Obtains the contents of the specified input registers.
  647. *
  648. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  649. *
  650. * Return(s) : DEF_TRUE If a response needs to be sent
  651. * DEF_FALSE If not
  652. *
  653. * Caller(s) : MBS_FCxx_Handler().
  654. *
  655. * Note(s) : 1) RX command format: Example:
  656. * <slave address> 0x11
  657. * <function code> 0x04
  658. * <start address HI> 0x00
  659. * <start address LO> 0x08
  660. * <# registers HI> 0x00
  661. * <# registers LO> 0x01
  662. * <Error Check (LRC or CRC)> 0x??
  663. *
  664. * 2) TX reply format: Example:
  665. * <slave address> 0x11
  666. * <function code> 0x04
  667. * <byte count> 0x02
  668. * <Data HI register value> 0x00
  669. * <Data LO register value> 0x0A
  670. * <Error Check (LRC or CRC)> 0x??
  671. *********************************************************************************************************
  672. */
  673. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  674. #if (MODBUS_CFG_FC04_EN == DEF_ENABLED)
  675. static CPU_BOOLEAN MBS_FC04_InRegRd (MODBUS_CH *pch)
  676. {
  677. CPU_INT08U *presp;
  678. CPU_INT16U err;
  679. CPU_INT16U reg;
  680. CPU_INT16U nbr_regs;
  681. CPU_INT16U nbr_bytes;
  682. CPU_INT16U reg_val_16;
  683. #if (MODBUS_CFG_FP_EN == DEF_ENABLED)
  684. CPU_INT08U ix;
  685. CPU_FP32 reg_val_fp;
  686. CPU_INT08U *pfp;
  687. #endif
  688. if (pch->RxFrameNDataBytes != 4) { /* Nbr of data bytes must be 4. */
  689. return (DEF_FALSE); /* Tell caller that we DON'T need to send a response */
  690. }
  691. reg = MBS_RX_DATA_START;
  692. nbr_regs = MBS_RX_DATA_POINTS;
  693. #if (MODBUS_CFG_FP_EN == DEF_ENABLED)
  694. if (reg < MODBUS_CFG_FP_START_IX) { /* See if we want integer registers */
  695. if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */
  696. pch->Err = MODBUS_ERR_FC04_03;
  697. MBS_ErrRespSet(pch,
  698. MODBUS_ERR_ILLEGAL_DATA_QTY);
  699. return (DEF_TRUE); /* Tell caller that we need to send a response */
  700. }
  701. nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_INT16U)); /* Find #bytes needed for response. */
  702. } else {
  703. if (nbr_regs == 0 || nbr_regs > 62) { /* Make sure we don't exceed the allowed limit per request */
  704. pch->Err = MODBUS_ERR_FC04_04;
  705. MBS_ErrRespSet(pch,
  706. MODBUS_ERR_ILLEGAL_DATA_QTY);
  707. return (DEF_TRUE); /* Tell caller that we need to send a response */
  708. }
  709. nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_FP32)); /* Find #bytes needed for response. */
  710. }
  711. #else
  712. if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */
  713. pch->Err = MODBUS_ERR_FC04_03;
  714. MBS_ErrRespSet(pch,
  715. MODBUS_ERR_ILLEGAL_DATA_QTY);
  716. return (DEF_TRUE); /* Tell caller that we need to send a response */
  717. }
  718. nbr_bytes = (CPU_INT08U)(nbr_regs * sizeof(CPU_INT16U)); /* Find #bytes needed for response. */
  719. #endif
  720. pch->TxFrameNDataBytes = nbr_bytes + 1; /* Number of data bytes + byte count. */
  721. presp = &pch->TxFrameData[0]; /* Reset the pointer to the start of the response */
  722. *presp++ = MBS_RX_FRAME_ADDR; /* Prepare response packet */
  723. *presp++ = MBS_RX_FRAME_FC;
  724. *presp++ = (CPU_INT08U)nbr_bytes; /* Set number of data bytes in response message */
  725. while (nbr_regs > 0) { /* Loop through each register requested. */
  726. if (reg < MODBUS_CFG_FP_START_IX) { /* See if we want an integer register */
  727. reg_val_16 = MB_InRegRd(reg, /* Yes, get its value */
  728. &err);
  729. switch (err) {
  730. case MODBUS_ERR_NONE:
  731. *presp++ = (CPU_INT08U)((reg_val_16 >> 8) & 0x00FF); /* Get MSB first. */
  732. *presp++ = (CPU_INT08U)(reg_val_16 & 0x00FF); /* Get LSB next. */
  733. break;
  734. case MODBUS_ERR_RANGE:
  735. default:
  736. pch->Err = MODBUS_ERR_FC04_01;
  737. MBS_ErrRespSet(pch,
  738. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  739. return (DEF_TRUE);
  740. }
  741. } else {
  742. #if (MODBUS_CFG_FP_EN == DEF_ENABLED)
  743. reg_val_fp = MB_InRegRdFP(reg, /* No, get the value of the FP register */
  744. &err);
  745. switch (err) {
  746. case MODBUS_ERR_NONE:
  747. pfp = (CPU_INT08U *)&reg_val_fp; /* Point to the FP register */
  748. #if CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG
  749. for (ix = 0; ix < sizeof(CPU_FP32); ix++) { /* Copy value to response buffer */
  750. *presp++ = *pfp++;
  751. }
  752. #else
  753. pfp += sizeof(CPU_FP32) - 1;
  754. for (ix = 0; ix < sizeof(CPU_FP32); ix++) {
  755. *presp++ = *pfp--;
  756. }
  757. #endif
  758. break;
  759. case MODBUS_ERR_RANGE:
  760. default:
  761. pch->Err = MODBUS_ERR_FC04_02;
  762. MBS_ErrRespSet(pch,
  763. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  764. return (DEF_TRUE);
  765. }
  766. #endif
  767. }
  768. reg++; /* Increment current register number */
  769. nbr_regs--;
  770. }
  771. pch->Err = MODBUS_ERR_NONE;
  772. return (DEF_TRUE); /* Tell caller that we need to send a response */
  773. }
  774. #endif
  775. #endif
  776. /*
  777. *********************************************************************************************************
  778. * MBS_FC05_CoilWr()
  779. *
  780. * Description : Responds to a request to force a coil to a specified state.
  781. *
  782. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  783. *
  784. * Return(s) : DEF_TRUE If a response needs to be sent
  785. * DEF_FALSE If not
  786. *
  787. * Caller(s) : MBS_FCxx_Handler().
  788. *
  789. * Note(s) : 1) A value of 0xFF00 forces a coil ON and 0x0000 to OFF
  790. *
  791. * 2) RX command format: Example:
  792. * <slave address> 0x11
  793. * <function code> 0x05
  794. * <Coil address HI> 0x00
  795. * <Coil address LO> 0xAC
  796. * <Force coil value HI> 0xFF
  797. * <Force coil value LO> 0x00
  798. * <Error Check (LRC or CRC)> 0x??
  799. *
  800. * 3) TX reply format: Example:
  801. * <slave address> 0x11
  802. * <function code> 0x05
  803. * <Coil address HI> 0x00
  804. * <Coil address LO> 0xAC
  805. * <Force coil value HI> 0xFF
  806. * <Force coil value LO> 0x00
  807. * <Error Check (LRC or CRC)> 0x??
  808. *********************************************************************************************************
  809. */
  810. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  811. #if (MODBUS_CFG_FC05_EN == DEF_ENABLED)
  812. static CPU_BOOLEAN MBS_FC05_CoilWr (MODBUS_CH *pch)
  813. {
  814. CPU_INT08U *prx_data;
  815. CPU_INT08U *ptx_data;
  816. CPU_INT08U i;
  817. CPU_INT16U coil;
  818. CPU_BOOLEAN coil_val;
  819. CPU_INT16U temp;
  820. CPU_INT16U err;
  821. if (pch->RxFrameNDataBytes != 4) { /* Nbr of data bytes must be 4. */
  822. return (DEF_FALSE); /* Tell caller that we DON'T need to send a response */
  823. }
  824. coil = MBS_RX_DATA_START; /* Get the desired coil number */
  825. temp = MBS_RX_DATA_COIL;
  826. if (pch->WrEn == DEF_TRUE) {
  827. if (temp == MODBUS_COIL_OFF_CODE) { /* See if coil needs to be OFF? */
  828. coil_val = 0; /* Yes, Turn coil OFF */
  829. } else {
  830. coil_val = 1; /* No, Turn coil ON */
  831. }
  832. MB_CoilWr(coil, /* Force coil */
  833. coil_val,
  834. &err);
  835. } else {
  836. pch->Err = MODBUS_ERR_FC05_02;
  837. MBS_ErrRespSet(pch, /* Writes are not enabled */
  838. MODBUS_ERR_ILLEGAL_DATA_VAL);
  839. return (DEF_TRUE); /* Tell caller that we need to send a response */
  840. }
  841. pch->TxFrameNDataBytes = 4;
  842. MBS_TX_FRAME_ADDR = MBS_RX_FRAME_ADDR; /* Prepare response packet */
  843. MBS_TX_FRAME_FC = MBS_RX_FRAME_FC;
  844. prx_data = &pch->RxFrameData[2]; /* Copy four data bytes from the receive packet */
  845. ptx_data = &pch->TxFrameData[2];
  846. for (i = 0; i < 4; i++) {
  847. *ptx_data++ = *prx_data++;
  848. }
  849. switch (err) {
  850. case MODBUS_ERR_NONE: /* We simply echoe back with the command received */
  851. pch->Err = MODBUS_ERR_NONE;
  852. pch->WrCtr++;
  853. break;
  854. case MODBUS_ERR_RANGE:
  855. default:
  856. pch->Err = MODBUS_ERR_FC05_01;
  857. MBS_ErrRespSet(pch,
  858. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  859. break;
  860. }
  861. return (DEF_TRUE); /* Tell caller that we need to send a response */
  862. }
  863. #endif
  864. #endif
  865. /*
  866. *********************************************************************************************************
  867. * MBS_FC06_HoldingRegWr()
  868. *
  869. * Description : Change the value of a single register.
  870. *
  871. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  872. *
  873. * Return(s) : DEF_TRUE If a response needs to be sent
  874. * DEF_FALSE If not
  875. *
  876. * Caller(s) : MBS_FCxx_Handler().
  877. *
  878. * Note(s) : 1) RX command format: Example:
  879. * <slave address> 0x11
  880. * <function code> 0x06
  881. * <start address HI> 0x00
  882. * <start address LO> 0x01
  883. * <Register value HI> 0x00
  884. * <Register value LO> 0x03
  885. * <Error Check (LRC or CRC)> 0x??
  886. *
  887. * 2) TX reply format: Example:
  888. * <slave address> 0x11
  889. * <function code> 0x06
  890. * <start address HI> 0x00
  891. * <start address LO> 0x01
  892. * <Register value HI> 0x00
  893. * <Register value LO> 0x03
  894. * <Error Check (LRC or CRC)> 0x??
  895. *********************************************************************************************************
  896. */
  897. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  898. #if (MODBUS_CFG_FC06_EN == DEF_ENABLED)
  899. static CPU_BOOLEAN MBS_FC06_HoldingRegWr (MODBUS_CH *pch)
  900. {
  901. CPU_INT08U *prx_data;
  902. CPU_INT08U *ptx_data;
  903. CPU_INT08U i;
  904. CPU_INT08U max;
  905. CPU_INT16U err;
  906. CPU_INT16U reg;
  907. CPU_INT16U reg_val_16;
  908. #if (MODBUS_CFG_FP_EN == DEF_ENABLED)
  909. CPU_FP32 reg_val_fp;
  910. CPU_INT08U *pfp;
  911. #endif
  912. if (pch->RxFrameNDataBytes != 4) { /* Nbr of data bytes must be 4. */
  913. return (DEF_FALSE);
  914. }
  915. reg = MBS_RX_DATA_START;
  916. #if (MODBUS_CFG_FP_EN == DEF_ENABLED)
  917. if (reg < MODBUS_CFG_FP_START_IX) {
  918. reg_val_16 = MBS_RX_DATA_REG;
  919. MB_HoldingRegWr(reg, /* Write to integer register */
  920. reg_val_16,
  921. &err);
  922. } else {
  923. prx_data = &pch->RxFrameData[4]; /* Point to data in the received frame. */
  924. pfp = (CPU_INT08U *)&reg_val_fp;
  925. #if CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG
  926. for (i = 0; i < sizeof(CPU_FP32); i++) {
  927. *pfp++ = *prx_data++;
  928. }
  929. #else
  930. prx_data += sizeof(CPU_FP32) - 1;
  931. for (i = 0; i < sizeof(CPU_FP32); i++) {
  932. *pfp++ = *prx_data--;
  933. }
  934. #endif
  935. MB_HoldingRegWrFP(reg, /* Write to floating point register */
  936. reg_val_fp,
  937. &err);
  938. }
  939. #else
  940. reg_val_16 = MBS_RX_DATA_REG;
  941. MB_HoldingRegWr(reg, /* Write to integer register */
  942. reg_val_16,
  943. &err);
  944. #endif
  945. pch->TxFrameNDataBytes = 4;
  946. MBS_TX_FRAME_ADDR = MBS_RX_FRAME_ADDR; /* Prepare response packet (duplicate Rx frame) */
  947. MBS_TX_FRAME_FC = MBS_RX_FRAME_FC;
  948. prx_data = &pch->RxFrameData[2]; /* Copy received register address and data to response */
  949. ptx_data = &pch->TxFrameData[2];
  950. if (reg < MODBUS_CFG_FP_START_IX) {
  951. max = sizeof(CPU_INT16U) + 2;
  952. } else {
  953. max = sizeof(CPU_FP32) + 2;
  954. }
  955. for (i = 0; i < max; i++) {
  956. *ptx_data++ = *prx_data++;
  957. }
  958. switch (err) {
  959. case MODBUS_ERR_NONE: /* Reply with echoe of command received */
  960. pch->Err = MODBUS_ERR_NONE;
  961. pch->WrCtr++;
  962. break;
  963. case MODBUS_ERR_RANGE:
  964. default:
  965. pch->Err = MODBUS_ERR_FC06_01;
  966. MBS_ErrRespSet(pch,
  967. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  968. break;
  969. }
  970. return (DEF_TRUE);
  971. }
  972. #endif
  973. #endif
  974. /*
  975. *********************************************************************************************************
  976. * MBS_FC08_Loopback()
  977. *
  978. * Description : The LOOPBACK function contains various diagnostic codes that perform specific actions.
  979. * This function processes individual diagnostic requests and formats the response message
  980. * frame accordingly. Unimplemented diagnostic codes will return an Illegal Data Value
  981. * Exception Response Code (03).
  982. *
  983. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  984. *
  985. * Return(s) : DEF_TRUE If a response needs to be sent
  986. * DEF_FALSE If not
  987. *
  988. * Caller(s) : MBS_FCxx_Handler().
  989. *
  990. * Note(s) : none.
  991. *********************************************************************************************************
  992. */
  993. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  994. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  995. static CPU_BOOLEAN MBS_FC08_Loopback (MODBUS_CH *pch)
  996. {
  997. CPU_INT16U diagcode;
  998. if (pch->RxFrameNDataBytes != 4) { /* Nbr of data bytes must be 4. */
  999. return (DEF_FALSE);
  1000. }
  1001. diagcode = MBS_RX_DIAG_CODE;
  1002. MBS_TX_FRAME_ADDR = MBS_RX_FRAME_ADDR; /* Prepare response packet */
  1003. MBS_TX_FRAME_FC = MBS_RX_FRAME_FC;
  1004. MBS_TX_DIAG_CODE_H = MBS_RX_DIAG_CODE_H;
  1005. MBS_TX_DIAG_CODE_L = MBS_RX_DIAG_CODE_L;
  1006. switch (diagcode) {
  1007. case MODBUS_FC08_LOOPBACK_QUERY: /* Return Query function code - no need to do anything. */
  1008. MBS_TX_DIAG_DATA_H = MBS_RX_DIAG_DATA_H;
  1009. MBS_TX_DIAG_DATA_L = MBS_RX_DIAG_DATA_L;
  1010. pch->Err = MODBUS_ERR_NONE;
  1011. break;
  1012. case MODBUS_FC08_LOOPBACK_CLR_CTR:
  1013. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) && \
  1014. (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  1015. MBS_StatInit(pch); /* Initialize the system counters, echo response back. */
  1016. #endif
  1017. pch->Err = MODBUS_ERR_NONE;
  1018. break;
  1019. case MODBUS_FC08_LOOPBACK_BUS_MSG_CTR: /* Return the message count in diag information field. */
  1020. MBS_TX_DIAG_DATA_H = (CPU_INT08U)((pch->StatMsgCtr & 0xFF00) >> 8);
  1021. MBS_TX_DIAG_DATA_L = (CPU_INT08U) (pch->StatMsgCtr & 0x00FF);
  1022. pch->Err = MODBUS_ERR_NONE;
  1023. break;
  1024. case MODBUS_FC08_LOOPBACK_BUS_CRC_CTR: /* Return the CRC error count in diag information field. */
  1025. MBS_TX_DIAG_DATA_H = (CPU_INT08U)((pch->StatCRCErrCtr & 0xFF00) >> 8);
  1026. MBS_TX_DIAG_DATA_L = (CPU_INT08U) (pch->StatCRCErrCtr & 0x00FF);
  1027. pch->Err = MODBUS_ERR_NONE;
  1028. break;
  1029. case MODBUS_FC08_LOOPBACK_BUS_EXCEPT_CTR: /* Return exception count in diag information field. */
  1030. MBS_TX_DIAG_DATA_H = (CPU_INT08U)((pch->StatExceptCtr & 0xFF00) >> 8);
  1031. MBS_TX_DIAG_DATA_L = (CPU_INT08U) (pch->StatExceptCtr & 0x00FF);
  1032. pch->Err = MODBUS_ERR_NONE;
  1033. break;
  1034. case MODBUS_FC08_LOOPBACK_SLAVE_MSG_CTR: /* Return slave message count in diag information field. */
  1035. MBS_TX_DIAG_DATA_H = (CPU_INT08U)((pch->StatSlaveMsgCtr & 0xFF00) >> 8);
  1036. MBS_TX_DIAG_DATA_L = (CPU_INT08U) (pch->StatSlaveMsgCtr & 0x00FF);
  1037. pch->Err = MODBUS_ERR_NONE;
  1038. break;
  1039. case MODBUS_FC08_LOOPBACK_SLAVE_NO_RESP_CTR: /* Return no response count in diag information field. */
  1040. MBS_TX_DIAG_DATA_H = (CPU_INT08U)((pch->StatNoRespCtr & 0xFF00) >> 8);
  1041. MBS_TX_DIAG_DATA_L = (CPU_INT08U) (pch->StatNoRespCtr & 0x00FF);
  1042. pch->Err = MODBUS_ERR_NONE;
  1043. break;
  1044. default:
  1045. pch->Err = MODBUS_ERR_FC08_01;
  1046. MBS_ErrRespSet(pch,
  1047. MODBUS_ERR_ILLEGAL_DATA_VAL);
  1048. break;
  1049. }
  1050. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1051. }
  1052. #endif
  1053. #endif
  1054. /*
  1055. *********************************************************************************************************
  1056. * MBS_FC15_CoilWrMultiple()
  1057. *
  1058. * Description : Processes the MODBUS "Force Multiple COILS" command and writes the COIL states.
  1059. *
  1060. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  1061. *
  1062. * Return(s) : DEF_TRUE If a response needs to be sent
  1063. * DEF_FALSE If not
  1064. *
  1065. * Caller(s) : MBS_FCxx_Handler().
  1066. *
  1067. * Note(s) : 1) RX command format: Example:
  1068. * <slave address> 0x11
  1069. * <function code> 0x0F
  1070. * <Coil address HI> 0x00
  1071. * <Coil address LO> 0x13
  1072. * <# coils HI> 0x00
  1073. * <# coils LO> 0x0A
  1074. * <byte count> 0x02
  1075. * <Force Data HI> 0xCD
  1076. * <Force Data LO> 0x01
  1077. * <Error Check (LRC or CRC)> 0x??
  1078. *
  1079. * 2) TX reply format: Example:
  1080. * <slave address> 0x11
  1081. * <function code> 0x0F
  1082. * <Coil address HI> 0x00
  1083. * <Coil address LO> 0x13
  1084. * <# coils HI> 0x00
  1085. * <# coils LO> 0x0A
  1086. * <Error Check (LRC or CRC)> 0x??
  1087. *********************************************************************************************************
  1088. */
  1089. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  1090. #if (MODBUS_CFG_FC15_EN == DEF_ENABLED)
  1091. static CPU_BOOLEAN MBS_FC15_CoilWrMultiple (MODBUS_CH *pch)
  1092. {
  1093. CPU_INT16U ix;
  1094. CPU_INT16U coil;
  1095. CPU_INT16U nbr_coils;
  1096. CPU_INT16U nbr_bytes;
  1097. CPU_INT08U data_ix;
  1098. CPU_BOOLEAN coil_val;
  1099. CPU_INT08U temp;
  1100. CPU_INT16U err;
  1101. if (pch->WrEn == DEF_TRUE) {
  1102. if (pch->RxFrameNDataBytes < 6) { /* Minimum Nbr of data bytes must be 6. */
  1103. return (DEF_FALSE); /* Tell caller that we DON'T need to send a response */
  1104. }
  1105. coil = MBS_RX_DATA_START;
  1106. nbr_coils = MBS_RX_DATA_POINTS;
  1107. nbr_bytes = MBS_RX_DATA_BYTES; /* Get the byte count for the data. */
  1108. if (((((nbr_coils - 1) / 8) + 1) == nbr_bytes) && /* Be sure #bytes valid for number COILS. */
  1109. (pch->RxFrameNDataBytes == (nbr_bytes + 5))) {
  1110. ix = 0; /* Initialize COIL/loop counter variable. */
  1111. data_ix = 7; /* The 1st COIL data byte is 5th element in data frame. */
  1112. while (ix < nbr_coils) { /* Loop through each COIL to be forced. */
  1113. if ((ix % 8) == 0) { /* Move to the next data byte after every eight bits. */
  1114. temp = pch->RxFrameData[data_ix++];
  1115. }
  1116. if (temp & 0x01) { /* Get LSBit */
  1117. coil_val = MODBUS_COIL_ON;
  1118. } else {
  1119. coil_val = MODBUS_COIL_OFF;
  1120. }
  1121. MB_CoilWr(coil + ix,
  1122. coil_val,
  1123. &err);
  1124. switch (err) {
  1125. case MODBUS_ERR_NONE:
  1126. break; /* Continue with the next coil if no error */
  1127. case MODBUS_ERR_RANGE:
  1128. default:
  1129. pch->Err = MODBUS_ERR_FC15_01;
  1130. MBS_ErrRespSet(pch,
  1131. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  1132. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1133. }
  1134. temp >>= 1; /* Shift the data one bit position to the right. */
  1135. ix++; /* Increment the COIL counter. */
  1136. }
  1137. } else {
  1138. pch->Err = MODBUS_ERR_FC15_02;
  1139. MBS_ErrRespSet(pch,
  1140. MODBUS_ERR_ILLEGAL_DATA_VAL);
  1141. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1142. }
  1143. pch->TxFrameNDataBytes = 4; /* Don't echo the whole message back! */
  1144. MBS_TX_FRAME_ADDR = MBS_RX_FRAME_ADDR; /* Prepare response packet */
  1145. MBS_TX_FRAME_FC = MBS_RX_FRAME_FC;
  1146. MBS_TX_DATA_START_H = MBS_RX_DATA_START_H;
  1147. MBS_TX_DATA_START_L = MBS_RX_DATA_START_L;
  1148. MBS_TX_DATA_POINTS_H = MBS_RX_DATA_POINTS_H;
  1149. MBS_TX_DATA_POINTS_L = MBS_RX_DATA_POINTS_L;
  1150. pch->Err = MODBUS_ERR_NONE;
  1151. } else {
  1152. pch->Err = MODBUS_ERR_FC15_03; /* Number of bytes incorrect for number of COILS. */
  1153. MBS_ErrRespSet(pch,
  1154. MODBUS_ERR_ILLEGAL_DATA_VAL);
  1155. }
  1156. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1157. }
  1158. #endif
  1159. #endif
  1160. /*
  1161. *********************************************************************************************************
  1162. * MBS_FC16_HoldingRegWrMultiple()
  1163. *
  1164. * Description : This function is called to write to multiple holding registers. If the address of the
  1165. * rquest exceeds or is equal to MODBUS_CFG_FP_START_IX, then the command would write to
  1166. * multiple 'floating-point' according to the 'Daniels Flow Meter' extensions. This means
  1167. * that each register requested is considered as a 32-bit IEEE-754 floating-point format.
  1168. *
  1169. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  1170. *
  1171. * Return(s) : DEF_TRUE If a response needs to be sent
  1172. * DEF_FALSE If not
  1173. *
  1174. * Caller(s) : MBS_FCxx_Handler().
  1175. *
  1176. * Note(s) : 1) RX command format: Example:
  1177. * <slave address> 0x11
  1178. * <function code> 0x10
  1179. * <start address HI> 0x00
  1180. * <start address LO> 0x01
  1181. * <# registers HI> 0x00
  1182. * <# registers LO> 0x02
  1183. * <byte count> 0x04
  1184. * <Register value HI> 0x00
  1185. * <Register value LO> 0x0A
  1186. * <Register value HI> 0x01
  1187. * <Register value LO> 0x02
  1188. * <Error Check (LRC or CRC)> 0x??
  1189. *
  1190. * 2) TX reply format: Example:
  1191. * <slave address> 0x11
  1192. * <function code> 0x10
  1193. * <start address HI> 0x00
  1194. * <start address LO> 0x01
  1195. * <# registers HI> 0x00
  1196. * <# registers LO> 0x02
  1197. * <Error Check (LRC or CRC)> 0x??
  1198. *********************************************************************************************************
  1199. */
  1200. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  1201. #if (MODBUS_CFG_FC16_EN == DEF_ENABLED)
  1202. static CPU_BOOLEAN MBS_FC16_HoldingRegWrMultiple (MODBUS_CH *pch)
  1203. {
  1204. CPU_INT08U *prx_data;
  1205. CPU_INT16U err;
  1206. CPU_INT16U reg;
  1207. CPU_INT16U reg_val_16;
  1208. CPU_INT16U nbr_regs;
  1209. CPU_INT16U nbr_bytes;
  1210. CPU_INT08U data_size;
  1211. #if (MODBUS_CFG_FP_EN == DEF_ENABLED)
  1212. CPU_INT08U i;
  1213. CPU_FP32 reg_val_fp;
  1214. CPU_INT08U *pfp;
  1215. #endif
  1216. reg = MBS_RX_DATA_START;
  1217. nbr_regs = MBS_RX_DATA_POINTS;
  1218. #if (MODBUS_CFG_FP_EN == DEF_ENABLED)
  1219. if (reg < MODBUS_CFG_FP_START_IX) {
  1220. if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */
  1221. pch->Err = MODBUS_ERR_FC16_04;
  1222. MBS_ErrRespSet(pch,
  1223. MODBUS_ERR_ILLEGAL_DATA_QTY);
  1224. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1225. }
  1226. data_size = sizeof(CPU_INT16U);
  1227. } else {
  1228. if (nbr_regs == 0 || nbr_regs > 62) { /* Make sure we don't exceed the allowed limit per request */
  1229. pch->Err = MODBUS_ERR_FC16_05;
  1230. MBS_ErrRespSet(pch,
  1231. MODBUS_ERR_ILLEGAL_DATA_QTY);
  1232. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1233. }
  1234. data_size = sizeof(CPU_FP32);
  1235. }
  1236. #else
  1237. if (nbr_regs == 0 || nbr_regs > 125) { /* Make sure we don't exceed the allowed limit per request */
  1238. pch->Err = MODBUS_ERR_FC16_04;
  1239. MBS_ErrRespSet(pch,
  1240. MODBUS_ERR_ILLEGAL_DATA_QTY);
  1241. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1242. }
  1243. data_size = sizeof(CPU_INT16U);
  1244. #endif
  1245. prx_data = &pch->RxFrameData[6]; /* Point to number of bytes in request frame */
  1246. nbr_bytes = (CPU_INT16U)*prx_data++;
  1247. if ((pch->RxFrameNDataBytes - 5) != nbr_bytes) { /* Compare actual number of bytes to what they say. */
  1248. pch->Err = MODBUS_ERR_FC16_01;
  1249. MBS_ErrRespSet(pch,
  1250. MODBUS_ERR_ILLEGAL_DATA_QTY);
  1251. return (DEF_TRUE);
  1252. }
  1253. if ((nbr_bytes / nbr_regs) != (CPU_INT16U)data_size) {
  1254. pch->Err = MODBUS_ERR_FC16_02;
  1255. MBS_ErrRespSet(pch,
  1256. MODBUS_ERR_ILLEGAL_DATA_VAL);
  1257. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1258. }
  1259. while (nbr_regs > 0) {
  1260. #if (MODBUS_CFG_FP_EN == DEF_ENABLED)
  1261. if (reg < MODBUS_CFG_FP_START_IX) {
  1262. reg_val_16 = ((CPU_INT16U)*prx_data++) << 8; /* Get MSB first. */
  1263. reg_val_16 += (CPU_INT16U)*prx_data++; /* Add in the LSB. */
  1264. MB_HoldingRegWr(reg,
  1265. reg_val_16,
  1266. &err);
  1267. } else {
  1268. pfp = (CPU_INT08U *)&reg_val_fp;
  1269. #if CPU_CFG_ENDIAN_TYPE == CPU_ENDIAN_TYPE_BIG
  1270. for (i = 0; i < sizeof(CPU_FP32); i++) {
  1271. *pfp++ = *prx_data++;
  1272. }
  1273. #else
  1274. pfp += sizeof(CPU_FP32) - 1;
  1275. for (i = 0; i < sizeof(CPU_FP32); i++) {
  1276. *pfp-- = *prx_data++;
  1277. }
  1278. #endif
  1279. MB_HoldingRegWrFP(reg,
  1280. reg_val_fp,
  1281. &err);
  1282. }
  1283. #else
  1284. reg_val_16 = ((CPU_INT16U)*prx_data++) << 8; /* Get MSB first. */
  1285. reg_val_16 += (CPU_INT16U)*prx_data++; /* Add in the LSB. */
  1286. MB_HoldingRegWr(reg,
  1287. reg_val_16,
  1288. &err);
  1289. #endif
  1290. switch (err) { /* See if any errors in writing the data */
  1291. case MODBUS_ERR_NONE: /* Reply with echoe of command received */
  1292. pch->WrCtr++;
  1293. reg++;
  1294. nbr_regs--;
  1295. break;
  1296. case MODBUS_ERR_RANGE:
  1297. default:
  1298. pch->Err = MODBUS_ERR_FC16_03;
  1299. MBS_ErrRespSet(pch,
  1300. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  1301. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1302. }
  1303. }
  1304. pch->TxFrameNDataBytes = 4; /* Don't echo the whole message back! */
  1305. MBS_TX_FRAME_ADDR = MBS_RX_FRAME_ADDR; /* Prepare response packet */
  1306. MBS_TX_FRAME_FC = MBS_RX_FRAME_FC;
  1307. MBS_TX_DATA_START_H = MBS_RX_DATA_START_H;
  1308. MBS_TX_DATA_START_L = MBS_RX_DATA_START_L;
  1309. MBS_TX_DATA_POINTS_H = MBS_RX_DATA_POINTS_H;
  1310. MBS_TX_DATA_POINTS_L = MBS_RX_DATA_POINTS_L;
  1311. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1312. }
  1313. #endif
  1314. #endif
  1315. /*
  1316. *********************************************************************************************************
  1317. * MBS_FC20_FileRd()
  1318. *
  1319. * Description : Read a record from a file.
  1320. *
  1321. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  1322. *
  1323. * Return(s) : DEF_TRUE If a response needs to be sent
  1324. * DEF_FALSE If not
  1325. *
  1326. * Caller(s) : MBS_FCxx_Handler().
  1327. *
  1328. * Note(s) : 1) The current version of this software only supports ONE Sub-request at a time.
  1329. *
  1330. * 2) RX command format: Example:
  1331. * <slave address> 0x11
  1332. * <function code> 0x14
  1333. * <byte count> 0x0E
  1334. * <Reference Type> 0x06
  1335. * <File number HI> 0x00
  1336. * <File number LO> 0x04
  1337. * <Starting address HI> 0x00
  1338. * <Starting address LO> 0x01
  1339. * <Register count HI> 0x00
  1340. * <Register count LO> 0x02
  1341. * <Error Check (LRC or CRC)> 0x??
  1342. *
  1343. * 3) TX reply format: Example:
  1344. * <slave address> 0x11
  1345. * <function code> 0x14
  1346. * <byte count> 0x0C
  1347. * <start address HI> 0x00
  1348. * <Reference Type> 0x06
  1349. * <Register data HI> 0x0D
  1350. * <Register data LO> 0xFE
  1351. * <Register data HI> 0x00
  1352. * <Register data LO> 0x20
  1353. * <Error Check (LRC or CRC)> 0x??
  1354. *********************************************************************************************************
  1355. */
  1356. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  1357. #if (MODBUS_CFG_FC20_EN == DEF_ENABLED)
  1358. static CPU_BOOLEAN MBS_FC20_FileRd (MODBUS_CH *pch)
  1359. {
  1360. CPU_INT08U *presp;
  1361. CPU_INT16U file_nbr;
  1362. CPU_INT16U record_nbr;
  1363. CPU_INT16U record_len;
  1364. CPU_INT16U cmd_len;
  1365. CPU_INT08U cmd_type;
  1366. CPU_INT16U err;
  1367. CPU_INT16U reg_val;
  1368. CPU_INT16U ix;
  1369. cmd_len = pch->RxFrameData[2]; /* Get the number of bytes in the command received */
  1370. if (cmd_len < 7 || cmd_len > 245) { /* Make sure the byte count Rx'd is within expected range */
  1371. pch->Err = MODBUS_ERR_FC20_01;
  1372. MBS_ErrRespSet(pch,
  1373. MODBUS_ERR_ILLEGAL_DATA_QTY);
  1374. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1375. }
  1376. cmd_type = pch->RxFrameData[3]; /* Get the reference type */
  1377. file_nbr = ((CPU_INT16U)pch->RxFrameData[4] << 8) /* Get the file number */
  1378. + (CPU_INT16U)pch->RxFrameData[5];
  1379. record_nbr = ((CPU_INT16U)pch->RxFrameData[6] << 8) /* Get the record number */
  1380. + (CPU_INT16U)pch->RxFrameData[7];
  1381. record_len = ((CPU_INT16U)pch->RxFrameData[8] << 8) /* Get the record length */
  1382. + (CPU_INT16U)pch->RxFrameData[9];
  1383. presp = &pch->TxFrameData[0]; /* Point to first location in response buffer */
  1384. *presp++ = MBS_RX_FRAME_ADDR; /* Reply back with the node address */
  1385. *presp++ = MBS_RX_FRAME_FC; /* Include the function code */
  1386. if (cmd_type == 6) { /* File type should ALWAYS be 6. */
  1387. pch->TxFrameNDataBytes = record_len * sizeof(CPU_INT16U) + 3; /* Determine the total number of data bytes in the Tx frame */
  1388. *presp++ = (CPU_INT08U)(pch->TxFrameNDataBytes - 1); /* Total byte count (excluding byte count) */
  1389. *presp++ = (CPU_INT08U)(pch->TxFrameNDataBytes - 2); /* Sub request byte count (excluding sub-request byte cnt) */
  1390. *presp++ = 6; /* Reference type is ALWAYS 6. */
  1391. ix = 0; /* Initialize the index into the record */
  1392. while (record_len > 0) {
  1393. reg_val = MB_FileRd(file_nbr, /* Get one value from the file */
  1394. record_nbr,
  1395. ix,
  1396. record_len,
  1397. &err);
  1398. switch (err) {
  1399. case MODBUS_ERR_NONE:
  1400. *presp++ = (CPU_INT08U)(reg_val >> 8); /* Store high byte of record data */
  1401. *presp++ = (CPU_INT08U)(reg_val & 0x00FF); /* Store low byte of record data */
  1402. break;
  1403. case MODBUS_ERR_FILE:
  1404. pch->Err = MODBUS_ERR_FC20_02;
  1405. MBS_ErrRespSet(pch,
  1406. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  1407. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1408. case MODBUS_ERR_RECORD:
  1409. pch->Err = MODBUS_ERR_FC20_03;
  1410. MBS_ErrRespSet(pch,
  1411. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  1412. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1413. case MODBUS_ERR_IX:
  1414. default:
  1415. pch->Err = MODBUS_ERR_FC20_04;
  1416. MBS_ErrRespSet(pch,
  1417. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  1418. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1419. }
  1420. ix++;
  1421. record_len--;
  1422. }
  1423. } else {
  1424. pch->Err = MODBUS_ERR_FC20_05;
  1425. MBS_ErrRespSet(pch,
  1426. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  1427. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1428. }
  1429. pch->Err = MODBUS_ERR_NONE;
  1430. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1431. }
  1432. #endif
  1433. #endif
  1434. /*
  1435. *********************************************************************************************************
  1436. * MBS_FC21_FileWr()
  1437. *
  1438. * Description : Write a record to a file.
  1439. *
  1440. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  1441. *
  1442. * Return(s) : DEF_TRUE If a response needs to be sent
  1443. * DEF_FALSE If not
  1444. *
  1445. * Caller(s) : MBS_FCxx_Handler().
  1446. *
  1447. * Note(s) : (1) The current version of this software only supports ONE Sub-request at a time.
  1448. *
  1449. * 2) RX command format: Example:
  1450. * <slave address> 0x11
  1451. * <function code> 0x15
  1452. * <byte count> 0x0D
  1453. * <Reference Type> 0x06
  1454. * <File number HI> 0x00
  1455. * <File number LO> 0x04
  1456. * <Starting address HI> 0x00
  1457. * <Starting address LO> 0x07
  1458. * <Register count HI> 0x00
  1459. * <Register count LO> 0x03
  1460. * <Register data HI> 0x06
  1461. * <Register data LO> 0xAF
  1462. * <Register data HI> 0x04
  1463. * <Register data LO> 0xBE
  1464. * <Register data HI> 0x10
  1465. * <Register data LO> 0x0D
  1466. * <Error Check (LRC or CRC)> 0x??
  1467. *
  1468. * 3) TX reply format: Example:
  1469. * <slave address> 0x11
  1470. * <function code> 0x15
  1471. * <byte count> 0x0D
  1472. * <Reference Type> 0x06
  1473. * <File number HI> 0x00
  1474. * <File number LO> 0x04
  1475. * <Starting address HI> 0x00
  1476. * <Starting address LO> 0x07
  1477. * <Register count HI> 0x00
  1478. * <Register count LO> 0x03
  1479. * <Register data HI> 0x06
  1480. * <Register data LO> 0xAF
  1481. * <Register data HI> 0x04
  1482. * <Register data LO> 0xBE
  1483. * <Register data HI> 0x10
  1484. * <Register data LO> 0x0D
  1485. * <Error Check (LRC or CRC)> 0x??
  1486. *********************************************************************************************************
  1487. */
  1488. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  1489. #if (MODBUS_CFG_FC21_EN == DEF_ENABLED)
  1490. static CPU_BOOLEAN MBS_FC21_FileWr (MODBUS_CH *pch)
  1491. {
  1492. CPU_INT08U *prx_data;
  1493. CPU_INT08U *pcmd;
  1494. CPU_INT08U *presp;
  1495. CPU_INT16U file_nbr;
  1496. CPU_INT16U record_nbr;
  1497. CPU_INT16U record_len;
  1498. CPU_INT16U cmd_len;
  1499. CPU_INT08U cmd_type;
  1500. CPU_INT16U err;
  1501. CPU_INT08U max;
  1502. CPU_INT16U reg_val;
  1503. CPU_INT16U ix;
  1504. cmd_len = pch->RxFrameData[2];
  1505. if (cmd_len < 7 || cmd_len > 245) { /* Make sure the byte count Rx'd is within expected range */
  1506. pch->Err = MODBUS_ERR_FC21_01;
  1507. MBS_ErrRespSet(pch,
  1508. MODBUS_ERR_ILLEGAL_DATA_QTY);
  1509. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1510. }
  1511. cmd_type = pch->RxFrameData[3]; /* Get the reference type */
  1512. file_nbr = ((CPU_INT16U)pch->RxFrameData[4] << 8) /* Get the file number */
  1513. + (CPU_INT16U)pch->RxFrameData[5];
  1514. record_nbr = ((CPU_INT16U)pch->RxFrameData[6] << 8) /* Get the record number */
  1515. + (CPU_INT16U)pch->RxFrameData[7];
  1516. record_len = ((CPU_INT16U)pch->RxFrameData[8] << 8) /* Get the record length */
  1517. + (CPU_INT16U)pch->RxFrameData[9];
  1518. prx_data = &pch->RxFrameData[10]; /* Point to first data byte */
  1519. if (cmd_type == 6) { /* File type should ALWAYS be 6. */
  1520. ix = 0; /* Initialize the index into the record */
  1521. while (record_len > 0) {
  1522. reg_val = ((CPU_INT16U)*prx_data++ << 8) & 0xFF00; /* Get data to write to file */
  1523. reg_val |= (CPU_INT16U)*prx_data++ & 0x00FF;
  1524. MB_FileWr(file_nbr, /* Write one value to the file */
  1525. record_nbr,
  1526. ix,
  1527. record_len,
  1528. reg_val,
  1529. &err);
  1530. switch (err) {
  1531. case MODBUS_ERR_NONE:
  1532. pch->WrCtr++;
  1533. break;
  1534. case MODBUS_ERR_FILE:
  1535. pch->Err = MODBUS_ERR_FC21_02;
  1536. MBS_ErrRespSet(pch,
  1537. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  1538. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1539. case MODBUS_ERR_RECORD:
  1540. pch->Err = MODBUS_ERR_FC21_03;
  1541. MBS_ErrRespSet(pch,
  1542. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  1543. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1544. case MODBUS_ERR_IX:
  1545. default:
  1546. pch->Err = MODBUS_ERR_FC21_04;
  1547. MBS_ErrRespSet(pch,
  1548. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  1549. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1550. }
  1551. ix++;
  1552. record_len--;
  1553. }
  1554. } else {
  1555. pch->Err = MODBUS_ERR_FC21_05;
  1556. MBS_ErrRespSet(pch,
  1557. MODBUS_ERR_ILLEGAL_DATA_ADDR);
  1558. return (DEF_TRUE);
  1559. }
  1560. record_len = ((CPU_INT16U)pch->RxFrameData[8] << 8) + (CPU_INT16U)pch->RxFrameData[9]; /* Get the record length */
  1561. pcmd = &pch->RxFrameData[0];
  1562. presp = &pch->TxFrameData[0]; /* Point to first location in response buffer */
  1563. max = (record_len * 2) + 9;
  1564. for (ix = 0; ix < max; ix++) { /* Copy the request into the transmit packet */
  1565. *presp++ = *pcmd++;
  1566. }
  1567. pch->Err = MODBUS_ERR_NONE;
  1568. return (DEF_TRUE); /* Tell caller that we need to send a response */
  1569. }
  1570. #endif
  1571. #endif
  1572. /*
  1573. *********************************************************************************************************
  1574. * MBS_StatInit()
  1575. *
  1576. * Description : This function is used to initialize/reset the MODBUS statistics/communications counters.
  1577. *
  1578. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  1579. *
  1580. * Return(s) : none.
  1581. *
  1582. * Caller(s) : MB_Init(),
  1583. * MBS_FC08_Loopback().
  1584. *
  1585. * Note(s) : none.
  1586. *********************************************************************************************************
  1587. */
  1588. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) && \
  1589. (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  1590. void MBS_StatInit (MODBUS_CH *pch)
  1591. {
  1592. pch->StatMsgCtr = 0; /* Initialize all MODBUS event counters. */
  1593. pch->StatCRCErrCtr = 0;
  1594. pch->StatExceptCtr = 0;
  1595. pch->StatSlaveMsgCtr = 0;
  1596. pch->StatNoRespCtr = 0;
  1597. }
  1598. #endif
  1599. /*
  1600. *********************************************************************************************************
  1601. * MBS_RxTask()
  1602. *
  1603. * Description : Handle either Modbus ASCII or Modbus RTU received packets.
  1604. *
  1605. * Argument(s) : ch Specifies the Modbus channel that needs servicing.
  1606. *
  1607. * Return(s) : none.
  1608. *
  1609. * Caller(s) : MB_RxTask().
  1610. *
  1611. * Note(s) : none.
  1612. *********************************************************************************************************
  1613. */
  1614. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED)
  1615. void MBS_RxTask (MODBUS_CH *pch)
  1616. {
  1617. if (pch != (MODBUS_CH *)0) {
  1618. #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED)
  1619. if (pch->Mode == MODBUS_MODE_ASCII) {
  1620. MBS_ASCII_Task(pch);
  1621. }
  1622. #endif
  1623. #if (MODBUS_CFG_RTU_EN == DEF_ENABLED)
  1624. if (pch->Mode == MODBUS_MODE_RTU) {
  1625. MBS_RTU_Task(pch);
  1626. }
  1627. #endif
  1628. }
  1629. }
  1630. #endif
  1631. /*
  1632. *********************************************************************************************************
  1633. * MBS_ASCII_Task()
  1634. *
  1635. * Description : Received a packet that should be encoded for Modbus ASCII mode. Process request.
  1636. *
  1637. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  1638. *
  1639. * Return(s) : none.
  1640. *
  1641. * Caller(s) : MBS_RxTask().
  1642. *
  1643. * Note(s) : none.
  1644. *********************************************************************************************************
  1645. */
  1646. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) && \
  1647. (MODBUS_CFG_ASCII_EN == DEF_ENABLED)
  1648. static void MBS_ASCII_Task (MODBUS_CH *pch)
  1649. {
  1650. CPU_BOOLEAN ok;
  1651. CPU_INT16U calc_lrc; /* Used for LRC */
  1652. CPU_BOOLEAN send_reply;
  1653. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  1654. pch->StatMsgCtr++;
  1655. #endif
  1656. if (pch->RxBufByteCtr >= MODBUS_ASCII_MIN_MSG_SIZE) {
  1657. ok = MB_ASCII_Rx(pch); /* Extract received command from .RxBuf[] & move to .RxFrameData[] */
  1658. if (ok == DEF_TRUE) {
  1659. calc_lrc = MB_ASCII_RxCalcLRC(pch); /* Calculate LRC on received ASCII packet */
  1660. if (calc_lrc != pch->RxFrameCRC) { /* If sum of all data plus received LRC is not the same */
  1661. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  1662. pch->StatCRCErrCtr++; /* then the frame was not received properly. */
  1663. pch->StatNoRespCtr++;
  1664. #endif
  1665. } else {
  1666. send_reply = MBS_FCxx_Handler(pch); /* Execute received command and formulate a response */
  1667. if (send_reply == DEF_TRUE) {
  1668. MB_ASCII_Tx(pch); /* Send back reply. */
  1669. } else {
  1670. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  1671. pch->StatNoRespCtr++;
  1672. #endif
  1673. }
  1674. }
  1675. } else {
  1676. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  1677. pch->StatNoRespCtr++;
  1678. #endif
  1679. }
  1680. }
  1681. pch->RxBufByteCtr = 0;
  1682. pch->RxBufPtr = &pch->RxBuf[0];
  1683. }
  1684. #endif
  1685. /*
  1686. *********************************************************************************************************
  1687. * MBS_RTU_Task()
  1688. *
  1689. * Description : This function processes a packet received on the Modbus channel assuming that it's an RTU
  1690. * packet.
  1691. *
  1692. * Argument(s) : pch Is a pointer to the Modbus channel's data structure.
  1693. *
  1694. * Return(s) : none.
  1695. *
  1696. * Caller(s) : MBS_RTU_Task().
  1697. *
  1698. * Note(s) : none.
  1699. *********************************************************************************************************
  1700. */
  1701. #if (MODBUS_CFG_SLAVE_EN == DEF_ENABLED) && \
  1702. (MODBUS_CFG_RTU_EN == DEF_ENABLED)
  1703. static void MBS_RTU_Task (MODBUS_CH *pch)
  1704. {
  1705. CPU_BOOLEAN ok;
  1706. CPU_INT16U calc_crc; /* Used for CRC */
  1707. CPU_BOOLEAN send_reply;
  1708. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  1709. pch->StatMsgCtr++;
  1710. #endif
  1711. if (pch->RxBufByteCtr >= MODBUS_RTU_MIN_MSG_SIZE) {
  1712. ok = MB_RTU_Rx(pch); /* Extract received command from .RxBuf[] & move to .RxFrameData[] */
  1713. if (ok == DEF_TRUE) {
  1714. calc_crc = MB_RTU_RxCalcCRC(pch); /* Do our own calculation of the CRC. */
  1715. if (calc_crc != pch->RxFrameCRC) { /* If the calculated CRC does not match the CRC received, */
  1716. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  1717. pch->StatCRCErrCtr++; /* then the frame is bad. */
  1718. pch->StatNoRespCtr++;
  1719. #endif
  1720. } else {
  1721. send_reply = MBS_FCxx_Handler(pch); /* Execute received command and formulate a response */
  1722. if (send_reply == DEF_TRUE) {
  1723. MB_RTU_Tx(pch); /* Send back reply. */
  1724. } else {
  1725. #if (MODBUS_CFG_FC08_EN == DEF_ENABLED)
  1726. pch->StatNoRespCtr++;
  1727. #endif
  1728. }
  1729. }
  1730. }
  1731. }
  1732. pch->RxBufByteCtr = 0;
  1733. pch->RxBufPtr = &pch->RxBuf[0];
  1734. }
  1735. #endif
  1736. #endif