Modbus.c 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904
  1. /*
  2. * Modbus.c
  3. * Modbus RTU Master and Slave library for STM32 CUBE with FreeRTOS
  4. * Created on: May 5, 2020
  5. * Author: Alejandro Mera
  6. * Adapted from https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino
  7. */
  8. #include "FreeRTOS.h"
  9. #include "cmsis_os.h"
  10. #include "task.h"
  11. #include "queue.h"
  12. #include "main.h"
  13. #include "Modbus.h"
  14. #include "timers.h"
  15. #include "semphr.h"
  16. #if ENABLE_TCP == 1
  17. #include "api.h"
  18. #include "ip4_addr.h"
  19. #include "netif.h"
  20. #endif
  21. #ifndef ENABLE_USART_DMA
  22. #define ENABLE_USART_DMA 0
  23. #endif
  24. #define bitRead(value, bit) (((value) >> (bit)) & 0x01)
  25. #define bitSet(value, bit) ((value) |= (1UL << (bit)))
  26. #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
  27. #define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit))
  28. #define lowByte(w) ((w) & 0xff)
  29. #define highByte(w) ((w) >> 8)
  30. ///Queue Modbus telegrams for master
  31. const osMessageQueueAttr_t QueueTelegram_attributes = {
  32. .name = "QueueModbusTelegram"
  33. };
  34. const osThreadAttr_t myTaskModbusA_attributes = {
  35. .name = "TaskModbusSlave",
  36. .priority = (osPriority_t) osPriorityNormal,
  37. .stack_size = 128 * 4
  38. };
  39. const osThreadAttr_t myTaskModbusA_attributesTCP = {
  40. .name = "TaskModbusSlave",
  41. .priority = (osPriority_t) osPriorityNormal,
  42. .stack_size = 256 * 4
  43. };
  44. //Task Modbus Master
  45. //osThreadId_t myTaskModbusAHandle;
  46. const osThreadAttr_t myTaskModbusB_attributes = {
  47. .name = "TaskModbusMaster",
  48. .priority = (osPriority_t) osPriorityNormal,
  49. .stack_size = 128 * 4
  50. };
  51. const osThreadAttr_t myTaskModbusB_attributesTCP = {
  52. .name = "TaskModbusMaster",
  53. .priority = (osPriority_t) osPriorityNormal,
  54. .stack_size = 256 * 4
  55. };
  56. //Semaphore to access the Modbus Data
  57. const osSemaphoreAttr_t ModBusSphr_attributes = {
  58. .name = "ModBusSphr"
  59. };
  60. uint8_t numberHandlers = 0;
  61. static void sendTxBuffer(modbusHandler_t *modH);
  62. static int16_t getRxBuffer(modbusHandler_t *modH);
  63. static uint8_t validateAnswer(modbusHandler_t *modH);
  64. static void buildException( uint8_t u8exception, modbusHandler_t *modH );
  65. static uint8_t validateRequest(modbusHandler_t * modH);
  66. static uint16_t word(uint8_t H, uint8_t l);
  67. static void get_FC1(modbusHandler_t *modH);
  68. static void get_FC3(modbusHandler_t *modH);
  69. static int8_t process_FC1(modbusHandler_t *modH );
  70. static int8_t process_FC3(modbusHandler_t *modH );
  71. static int8_t process_FC5( modbusHandler_t *modH);
  72. static int8_t process_FC6(modbusHandler_t *modH );
  73. static int8_t process_FC15(modbusHandler_t *modH );
  74. static int8_t process_FC16(modbusHandler_t *modH);
  75. static void vTimerCallbackT35(TimerHandle_t *pxTimer);
  76. static void vTimerCallbackTimeout(TimerHandle_t *pxTimer);
  77. //static int16_t getRxBuffer(modbusHandler_t *modH);
  78. static int8_t SendQuery(modbusHandler_t *modH , modbus_t telegram);
  79. #if ENABLE_TCP ==1
  80. static bool TCPwaitConnData(modbusHandler_t *modH);
  81. static void TCPinitserver(modbusHandler_t *modH);
  82. static mb_errot_t TCPconnectserver(modbusHandler_t * modH, modbus_t *telegram);
  83. static mb_errot_t TCPgetRxBuffer(modbusHandler_t * modH);
  84. #endif
  85. /* Ring Buffer functions */
  86. // This function must be called only after disabling USART RX interrupt or inside of the RX interrupt
  87. void RingAdd(modbusRingBuffer_t *xRingBuffer, uint8_t u8Val)
  88. {
  89. xRingBuffer->uxBuffer[xRingBuffer->u8end] = u8Val;
  90. xRingBuffer->u8end = (xRingBuffer->u8end + 1) % MAX_BUFFER;
  91. if (xRingBuffer->u8available == MAX_BUFFER)
  92. {
  93. xRingBuffer->overflow = true;
  94. xRingBuffer->u8start = (xRingBuffer->u8start + 1) % MAX_BUFFER;
  95. }
  96. else
  97. {
  98. xRingBuffer->overflow = false;
  99. xRingBuffer->u8available++;
  100. }
  101. }
  102. // This function must be called only after disabling USART RX interrupt
  103. uint8_t RingGetAllBytes(modbusRingBuffer_t *xRingBuffer, uint8_t *buffer)
  104. {
  105. return RingGetNBytes(xRingBuffer, buffer, xRingBuffer->u8available);
  106. }
  107. // This function must be called only after disabling USART RX interrupt
  108. uint8_t RingGetNBytes(modbusRingBuffer_t *xRingBuffer, uint8_t *buffer, uint8_t uNumber)
  109. {
  110. uint8_t uCounter;
  111. if(xRingBuffer->u8available == 0 || uNumber == 0 ) return 0;
  112. if(uNumber > MAX_BUFFER) return 0;
  113. for(uCounter = 0; uCounter < uNumber && uCounter< xRingBuffer->u8available ; uCounter++)
  114. {
  115. buffer[uCounter] = xRingBuffer->uxBuffer[xRingBuffer->u8start];
  116. xRingBuffer->u8start = (xRingBuffer->u8start + 1) % MAX_BUFFER;
  117. }
  118. xRingBuffer->u8available = xRingBuffer->u8available - uCounter;
  119. xRingBuffer->overflow = false;
  120. RingClear(xRingBuffer);
  121. return uCounter;
  122. }
  123. uint8_t RingCountBytes(modbusRingBuffer_t *xRingBuffer)
  124. {
  125. return xRingBuffer->u8available;
  126. }
  127. void RingClear(modbusRingBuffer_t *xRingBuffer)
  128. {
  129. xRingBuffer->u8start = 0;
  130. xRingBuffer->u8end = 0;
  131. xRingBuffer->u8available = 0;
  132. xRingBuffer->overflow = false;
  133. }
  134. /* End of Ring Buffer functions */
  135. const unsigned char fctsupported[] =
  136. {
  137. MB_FC_READ_COILS,
  138. MB_FC_READ_DISCRETE_INPUT,
  139. MB_FC_READ_REGISTERS,
  140. MB_FC_READ_INPUT_REGISTER,
  141. MB_FC_WRITE_COIL,
  142. MB_FC_WRITE_REGISTER,
  143. MB_FC_WRITE_MULTIPLE_COILS,
  144. MB_FC_WRITE_MULTIPLE_REGISTERS
  145. };
  146. /**
  147. * @brief
  148. * Initialization for a Master/Slave.
  149. * this function will check the configuration parameters
  150. * of the modbus handler
  151. *
  152. * @param modH modbus handler
  153. */
  154. void ModbusInit(modbusHandler_t * modH)
  155. {
  156. if (numberHandlers < MAX_M_HANDLERS)
  157. {
  158. //Initialize the ring buffer
  159. RingClear(&modH->xBufferRX);
  160. if(modH->uModbusType == MB_SLAVE)
  161. {
  162. //Create Modbus task slave
  163. #if ENABLE_TCP == 1
  164. if( modH->xTypeHW == TCP_HW)
  165. {
  166. modH->myTaskModbusAHandle = osThreadNew(StartTaskModbusSlave, modH, &myTaskModbusA_attributesTCP);
  167. }
  168. else{
  169. modH->myTaskModbusAHandle = osThreadNew(StartTaskModbusSlave, modH, &myTaskModbusA_attributes);
  170. }
  171. #else
  172. modH->myTaskModbusAHandle = osThreadNew(StartTaskModbusSlave, modH, &myTaskModbusA_attributes);
  173. #endif
  174. }
  175. else if (modH->uModbusType == MB_MASTER)
  176. {
  177. //Create Modbus task Master and Queue for telegrams
  178. #if ENABLE_TCP == 1
  179. if( modH->xTypeHW == TCP_HW)
  180. {
  181. modH->myTaskModbusAHandle = osThreadNew(StartTaskModbusMaster, modH, &myTaskModbusB_attributesTCP);
  182. }
  183. else
  184. {
  185. modH->myTaskModbusAHandle = osThreadNew(StartTaskModbusMaster, modH, &myTaskModbusB_attributes);
  186. }
  187. #else
  188. modH->myTaskModbusAHandle = osThreadNew(StartTaskModbusMaster, modH, &myTaskModbusB_attributes);
  189. #endif
  190. modH->xTimerTimeout=xTimerCreate("xTimerTimeout", // Just a text name, not used by the kernel.
  191. modH->u16timeOut , // The timer period in ticks.
  192. pdFALSE, // The timers will auto-reload themselves when they expire.
  193. ( void * )modH->xTimerTimeout, // Assign each timer a unique id equal to its array index.
  194. (TimerCallbackFunction_t) vTimerCallbackTimeout // Each timer calls the same callback when it expires.
  195. );
  196. if(modH->xTimerTimeout == NULL)
  197. {
  198. while(1); //error creating timer, check heap and stack size
  199. }
  200. modH->QueueTelegramHandle = osMessageQueueNew (MAX_TELEGRAMS, sizeof(modbus_t), &QueueTelegram_attributes);
  201. if(modH->QueueTelegramHandle == NULL)
  202. {
  203. while(1); //error creating queue for telegrams, check heap and stack size
  204. }
  205. }
  206. else
  207. {
  208. while(1); //Error Modbus type not supported choose a valid Type
  209. }
  210. if (modH->myTaskModbusAHandle == NULL)
  211. {
  212. while(1); //Error creating Modbus task, check heap and stack size
  213. }
  214. modH->xTimerT35 = xTimerCreate("TimerT35", // Just a text name, not used by the kernel.
  215. T35 , // The timer period in ticks.
  216. pdFALSE, // The timers will auto-reload themselves when they expire.
  217. ( void * )modH->xTimerT35, // Assign each timer a unique id equal to its array index.
  218. (TimerCallbackFunction_t) vTimerCallbackT35 // Each timer calls the same callback when it expires.
  219. );
  220. if (modH->xTimerT35 == NULL)
  221. {
  222. while(1); //Error creating the timer, check heap and stack size
  223. }
  224. modH->ModBusSphrHandle = osSemaphoreNew(1, 1, &ModBusSphr_attributes);
  225. if(modH->ModBusSphrHandle == NULL)
  226. {
  227. while(1); //Error creating the semaphore, check heap and stack size
  228. }
  229. mHandlers[numberHandlers] = modH;
  230. numberHandlers++;
  231. }
  232. else
  233. {
  234. while(1); //error no more Modbus handlers supported
  235. }
  236. }
  237. /**
  238. * @brief
  239. * Start object.
  240. *
  241. * Call this AFTER calling begin() on the serial port, typically within setup().
  242. *
  243. * (If you call this function, then you should NOT call any of
  244. * ModbusRtu's own begin() functions.)
  245. *
  246. * @ingroup setup
  247. */
  248. void ModbusStart(modbusHandler_t * modH)
  249. {
  250. if(modH->xTypeHW != USART_HW && modH->xTypeHW != TCP_HW && modH->xTypeHW != USB_CDC_HW && modH->xTypeHW != USART_HW_DMA )
  251. {
  252. while(1); //ERROR select the type of hardware
  253. }
  254. if (modH->xTypeHW == USART_HW_DMA && ENABLE_USART_DMA == 0 )
  255. {
  256. while(1); //ERROR To use USART_HW_DMA you need to enable it in the ModbusConfig.h file
  257. }
  258. if (modH->xTypeHW == USART_HW || modH->xTypeHW == USART_HW_DMA )
  259. {
  260. if (modH->EN_Port != NULL )
  261. {
  262. // return RS485 transceiver to transmit mode
  263. HAL_GPIO_WritePin(modH->EN_Port, modH->EN_Pin, GPIO_PIN_RESET);
  264. }
  265. if (modH->uModbusType == MB_SLAVE && modH->u16regs == NULL )
  266. {
  267. while(1); //ERROR define the DATA pointer shared through Modbus
  268. }
  269. //check that port is initialized
  270. while (HAL_UART_GetState(modH->port) != HAL_UART_STATE_READY)
  271. {
  272. }
  273. #if ENABLE_USART_DMA ==1
  274. if( modH->xTypeHW == USART_HW_DMA )
  275. {
  276. if(HAL_UARTEx_ReceiveToIdle_DMA(modH->port, modH->xBufferRX.uxBuffer, MAX_BUFFER ) != HAL_OK)
  277. {
  278. while(1)
  279. {
  280. //error in your initialization code
  281. }
  282. }
  283. __HAL_DMA_DISABLE_IT(modH->port->hdmarx, DMA_IT_HT); // we don't need half-transfer interrupt
  284. }
  285. else{
  286. // Receive data from serial port for Modbus using interrupt
  287. if(HAL_UART_Receive_IT(modH->port, &modH->dataRX, 1) != HAL_OK)
  288. {
  289. while(1)
  290. {
  291. //error in your initialization code
  292. }
  293. }
  294. }
  295. #else
  296. // Receive data from serial port for Modbus using interrupt
  297. if(HAL_UART_Receive_IT(modH->port, &modH->dataRX, 1) != HAL_OK)
  298. {
  299. while(1)
  300. {
  301. //error in your initialization code
  302. }
  303. }
  304. #endif
  305. if(modH->u8id !=0 && modH->uModbusType == MB_MASTER )
  306. {
  307. while(1)
  308. {
  309. //error Master ID must be zero
  310. }
  311. }
  312. if(modH->u8id ==0 && modH->uModbusType == MB_SLAVE )
  313. {
  314. while(1)
  315. {
  316. //error Master ID must be zero
  317. }
  318. }
  319. }
  320. #if ENABLE_TCP == 1
  321. #endif
  322. modH->u8lastRec = modH->u8BufferSize = 0;
  323. modH->u16InCnt = modH->u16OutCnt = modH->u16errCnt = 0;
  324. }
  325. #if ENABLE_USB_CDC == 1
  326. extern void MX_USB_DEVICE_Init(void);
  327. void ModbusStartCDC(modbusHandler_t * modH)
  328. {
  329. if (modH->uModbusType == MB_SLAVE && modH->u16regs == NULL )
  330. {
  331. while(1); //ERROR define the DATA pointer shared through Modbus
  332. }
  333. modH->u8lastRec = modH->u8BufferSize = 0;
  334. modH->u16InCnt = modH->u16OutCnt = modH->u16errCnt = 0;
  335. }
  336. #endif
  337. void vTimerCallbackT35(TimerHandle_t *pxTimer)
  338. {
  339. //Notify that a stream has just arrived
  340. int i;
  341. //TimerHandle_t aux;
  342. for(i = 0; i < numberHandlers; i++)
  343. {
  344. if( (TimerHandle_t *)mHandlers[i]->xTimerT35 == pxTimer ){
  345. if(mHandlers[i]->uModbusType == MB_MASTER)
  346. {
  347. xTimerStop(mHandlers[i]->xTimerTimeout,0);
  348. }
  349. xTaskNotify(mHandlers[i]->myTaskModbusAHandle, 0, eSetValueWithOverwrite);
  350. }
  351. }
  352. }
  353. void vTimerCallbackTimeout(TimerHandle_t *pxTimer)
  354. {
  355. //Notify that a stream has just arrived
  356. int i;
  357. //TimerHandle_t aux;
  358. for(i = 0; i < numberHandlers; i++)
  359. {
  360. if( (TimerHandle_t *)mHandlers[i]->xTimerTimeout == pxTimer ){
  361. xTaskNotify(mHandlers[i]->myTaskModbusAHandle, ERR_TIME_OUT, eSetValueWithOverwrite);
  362. }
  363. }
  364. }
  365. #if ENABLE_TCP ==1
  366. bool TCPwaitConnData(modbusHandler_t *modH)
  367. {
  368. struct netbuf *inbuf;
  369. err_t recv_err, accept_err;
  370. char* buf;
  371. uint16_t buflen;
  372. uint16_t uLength;
  373. bool xTCPvalid;
  374. xTCPvalid = false;
  375. tcpclients_t *clientconn;
  376. //select the next connection slot to work with using round-robin
  377. modH->newconnIndex++;
  378. if (modH->newconnIndex>NUMBERTCPCONN)
  379. {
  380. modH->newconnIndex = 0;
  381. }
  382. clientconn = &modH->newconns[modH->newconnIndex];
  383. //NULL means there is a free connection slot, so we can accept an incoming client connection
  384. if (clientconn->conn == NULL){
  385. /* accept any incoming connection */
  386. accept_err = netconn_accept(modH->conn, &clientconn->conn);
  387. if(accept_err != ERR_OK)
  388. {
  389. // not valid incoming connection at this time
  390. ModbusCloseConn(clientconn->conn);
  391. return xTCPvalid;
  392. }
  393. else
  394. {
  395. clientconn->aging=0;
  396. }
  397. }
  398. netconn_set_recvtimeout(clientconn->conn , modH->u16timeOut);
  399. recv_err = netconn_recv(clientconn->conn, &inbuf);
  400. if (recv_err == ERR_CLSD) //the connection was closed
  401. {
  402. //Close and clean the connection
  403. ModbusCloseConn(clientconn->conn);
  404. clientconn->aging = 0;
  405. return xTCPvalid;
  406. }
  407. if (recv_err == ERR_TIMEOUT) //No new data
  408. {
  409. //continue the aging process
  410. modH->newconns[modH->newconnIndex].aging++;
  411. // if the connection is old enough and inactive close and clean it up
  412. if (modH->newconns[modH->newconnIndex].aging >= TCPAGINGCYCLES)
  413. {
  414. ModbusCloseConn(clientconn->conn);
  415. clientconn->aging = 0;
  416. }
  417. return xTCPvalid;
  418. }
  419. if (recv_err == ERR_OK)
  420. {
  421. if (netconn_err(clientconn->conn) == ERR_OK)
  422. {
  423. /* Read the data from the port, blocking if nothing yet there.
  424. We assume the request (the part we care about) is in one netbuf */
  425. netbuf_data(inbuf, (void**)&buf, &buflen);
  426. if (buflen>11) // minimum frame size for modbus TCP
  427. {
  428. if(buf[2] == 0 || buf[3] == 0 ) //validate protocol ID
  429. {
  430. uLength = (buf[4]<<8 & 0xff00) | buf[5];
  431. if(uLength< (MAX_BUFFER-2) && (uLength + 6) <= buflen)
  432. {
  433. for(int i = 0; i < uLength; i++)
  434. {
  435. modH->u8Buffer[i] = buf[i+6];
  436. }
  437. modH->u16TransactionID = (buf[0]<<8 & 0xff00) | buf[1];
  438. modH->u8BufferSize = uLength + 2; //add 2 dummy bytes for CRC
  439. xTCPvalid = true; // we have data for the modbus slave
  440. }
  441. }
  442. }
  443. netbuf_delete(inbuf); // delete the buffer always
  444. clientconn->aging = 0; //reset the aging counter
  445. }
  446. }
  447. return xTCPvalid;
  448. }
  449. void TCPinitserver(modbusHandler_t *modH)
  450. {
  451. err_t err;
  452. /* Create a new TCP connection handle */
  453. if(modH-> xTypeHW == TCP_HW)
  454. {
  455. modH->conn = netconn_new(NETCONN_TCP);
  456. if (modH->conn!= NULL)
  457. {
  458. /* Bind to port (502) Modbus with default IP address */
  459. if(modH->uTcpPort == 0) modH->uTcpPort = 502; //if port not defined
  460. err = netconn_bind(modH->conn, NULL, modH->uTcpPort);
  461. if (err == ERR_OK)
  462. {
  463. /* Put the connection into LISTEN state */
  464. netconn_listen(modH->conn);
  465. netconn_set_recvtimeout(modH->conn, 1); // this is necessary to make it non blocking
  466. }
  467. else{
  468. while(1)
  469. {
  470. // error binding the TCP Modbus port check your configuration
  471. }
  472. }
  473. }
  474. else{
  475. while(1)
  476. {
  477. // error creating new connection check your configuration,
  478. // this function must be called after the scheduler is started
  479. }
  480. }
  481. }
  482. }
  483. #endif
  484. void StartTaskModbusSlave(void *argument)
  485. {
  486. modbusHandler_t *modH = (modbusHandler_t *)argument;
  487. //uint32_t notification;
  488. #if ENABLE_TCP ==1
  489. if( modH->xTypeHW == TCP_HW )
  490. {
  491. TCPinitserver(modH); // start the Modbus server slave
  492. }
  493. #endif
  494. for(;;)
  495. {
  496. modH->i8lastError = 0;
  497. #if ENABLE_USB_CDC ==1
  498. if(modH-> xTypeHW == USB_CDC_HW)
  499. {
  500. ulTaskNotifyTake(pdTRUE, portMAX_DELAY); /* Block indefinitely until a Modbus Frame arrives */
  501. if (modH->u8BufferSize == ERR_BUFF_OVERFLOW) // is this necessary?
  502. {
  503. modH->i8lastError = ERR_BUFF_OVERFLOW;
  504. modH->u16errCnt++;
  505. continue;
  506. }
  507. }
  508. #endif
  509. #if ENABLE_TCP ==1
  510. if(modH-> xTypeHW == TCP_HW)
  511. {
  512. if(TCPwaitConnData(modH) == false) // wait for connection and receive data
  513. {
  514. continue; // TCP package was not validated
  515. }
  516. }
  517. #endif
  518. if(modH->xTypeHW == USART_HW || modH->xTypeHW == USART_HW_DMA)
  519. {
  520. ulTaskNotifyTake(pdTRUE, portMAX_DELAY); /* Block until a Modbus Frame arrives */
  521. if (getRxBuffer(modH) == ERR_BUFF_OVERFLOW)
  522. {
  523. modH->i8lastError = ERR_BUFF_OVERFLOW;
  524. modH->u16errCnt++;
  525. continue;
  526. }
  527. }
  528. if (modH->u8BufferSize < 7)
  529. {
  530. //The size of the frame is invalid
  531. modH->i8lastError = ERR_BAD_SIZE;
  532. modH->u16errCnt++;
  533. continue;
  534. }
  535. // check slave id
  536. if ( modH->u8Buffer[ID] != modH->u8id)
  537. {
  538. #if ENABLE_TCP == 0
  539. continue; // continue this is not for us
  540. #else
  541. if(modH->xTypeHW != TCP_HW)
  542. {
  543. continue; //for Modbus TCP this is not validated, user should modify accordingly if needed
  544. }
  545. #endif
  546. }
  547. // validate message: CRC, FCT, address and size
  548. uint8_t u8exception = validateRequest(modH);
  549. if (u8exception > 0)
  550. {
  551. if (u8exception != ERR_TIME_OUT)
  552. {
  553. buildException( u8exception, modH);
  554. sendTxBuffer(modH);
  555. }
  556. modH->i8lastError = u8exception;
  557. //return u8exception
  558. continue;
  559. }
  560. modH->i8lastError = 0;
  561. xSemaphoreTake(modH->ModBusSphrHandle , portMAX_DELAY); //before processing the message get the semaphore
  562. // process message
  563. switch(modH->u8Buffer[ FUNC ] )
  564. {
  565. case MB_FC_READ_COILS:
  566. case MB_FC_READ_DISCRETE_INPUT:
  567. modH->i8state = process_FC1(modH);
  568. break;
  569. case MB_FC_READ_INPUT_REGISTER:
  570. case MB_FC_READ_REGISTERS :
  571. modH->i8state = process_FC3(modH);
  572. break;
  573. case MB_FC_WRITE_COIL:
  574. modH->i8state = process_FC5(modH);
  575. break;
  576. case MB_FC_WRITE_REGISTER :
  577. modH->i8state = process_FC6(modH);
  578. break;
  579. case MB_FC_WRITE_MULTIPLE_COILS:
  580. modH->i8state = process_FC15(modH);
  581. break;
  582. case MB_FC_WRITE_MULTIPLE_REGISTERS :
  583. modH->i8state = process_FC16(modH);
  584. break;
  585. default:
  586. break;
  587. }
  588. xSemaphoreGive(modH->ModBusSphrHandle); //Release the semaphore
  589. continue;
  590. }
  591. }
  592. void ModbusQuery(modbusHandler_t * modH, modbus_t telegram )
  593. {
  594. //Add the telegram to the TX tail Queue of Modbus
  595. if (modH->uModbusType == MB_MASTER)
  596. {
  597. telegram.u32CurrentTask = (uint32_t *) osThreadGetId();
  598. xQueueSendToBack(modH->QueueTelegramHandle, &telegram, 0);
  599. }
  600. else{
  601. while(1);// error a slave cannot send queries as a master
  602. }
  603. }
  604. void ModbusQueryInject(modbusHandler_t * modH, modbus_t telegram )
  605. {
  606. //Add the telegram to the TX head Queue of Modbus
  607. xQueueReset(modH->QueueTelegramHandle);
  608. telegram.u32CurrentTask = (uint32_t *) osThreadGetId();
  609. xQueueSendToFront(modH->QueueTelegramHandle, &telegram, 0);
  610. }
  611. #if ENABLE_TCP ==1
  612. void ModbusCloseConn(struct netconn *conn)
  613. {
  614. if(conn != NULL)
  615. {
  616. netconn_close(conn);
  617. netconn_delete(conn);
  618. conn = NULL;
  619. }
  620. }
  621. #endif
  622. /**
  623. * @brief
  624. * *** Only Modbus Master ***
  625. * Generate a query to an slave with a modbus_t telegram structure
  626. * The Master must be in COM_IDLE mode. After it, its state would be COM_WAITING.
  627. * This method has to be called only in loop() section.
  628. *
  629. * @see modbus_t
  630. * @param modH modbus handler
  631. * @param modbus_t modbus telegram structure (id, fct, ...)
  632. * @ingroup loop
  633. */
  634. int8_t SendQuery(modbusHandler_t *modH , modbus_t telegram )
  635. {
  636. uint8_t u8regsno, u8bytesno;
  637. uint8_t error = 0;
  638. xSemaphoreTake(modH->ModBusSphrHandle , portMAX_DELAY); //before processing the message get the semaphore
  639. if (modH->u8id!=0) error = ERR_NOT_MASTER;
  640. if (modH->i8state != COM_IDLE) error = ERR_POLLING ;
  641. if ((telegram.u8id==0) || (telegram.u8id>247)) error = ERR_BAD_SLAVE_ID;
  642. if(error)
  643. {
  644. modH->i8lastError = error;
  645. xSemaphoreGive(modH->ModBusSphrHandle);
  646. return error;
  647. }
  648. modH->u16regs = telegram.u16reg;
  649. // telegram header
  650. modH->u8Buffer[ ID ] = telegram.u8id;
  651. modH->u8Buffer[ FUNC ] = telegram.u8fct;
  652. modH->u8Buffer[ ADD_HI ] = highByte(telegram.u16RegAdd );
  653. modH->u8Buffer[ ADD_LO ] = lowByte( telegram.u16RegAdd );
  654. switch( telegram.u8fct )
  655. {
  656. case MB_FC_READ_COILS:
  657. case MB_FC_READ_DISCRETE_INPUT:
  658. case MB_FC_READ_REGISTERS:
  659. case MB_FC_READ_INPUT_REGISTER:
  660. modH->u8Buffer[ NB_HI ] = highByte(telegram.u16CoilsNo );
  661. modH->u8Buffer[ NB_LO ] = lowByte( telegram.u16CoilsNo );
  662. modH->u8BufferSize = 6;
  663. break;
  664. case MB_FC_WRITE_COIL:
  665. modH->u8Buffer[ NB_HI ] = (( telegram.u16reg[0]> 0) ? 0xff : 0);
  666. modH->u8Buffer[ NB_LO ] = 0;
  667. modH->u8BufferSize = 6;
  668. break;
  669. case MB_FC_WRITE_REGISTER:
  670. modH->u8Buffer[ NB_HI ] = highByte( telegram.u16reg[0]);
  671. modH->u8Buffer[ NB_LO ] = lowByte( telegram.u16reg[0]);
  672. modH->u8BufferSize = 6;
  673. break;
  674. case MB_FC_WRITE_MULTIPLE_COILS: // TODO: implement "sending coils"
  675. u8regsno = telegram.u16CoilsNo / 16;
  676. u8bytesno = u8regsno * 2;
  677. if ((telegram.u16CoilsNo % 16) != 0)
  678. {
  679. u8bytesno++;
  680. u8regsno++;
  681. }
  682. modH->u8Buffer[ NB_HI ] = highByte(telegram.u16CoilsNo );
  683. modH->u8Buffer[ NB_LO ] = lowByte( telegram.u16CoilsNo );
  684. modH->u8Buffer[ BYTE_CNT ] = u8bytesno;
  685. modH->u8BufferSize = 7;
  686. for (uint16_t i = 0; i < u8bytesno; i++)
  687. {
  688. if(i%2)
  689. {
  690. modH->u8Buffer[ modH->u8BufferSize ] = lowByte( telegram.u16reg[ i/2 ] );
  691. }
  692. else
  693. {
  694. modH->u8Buffer[ modH->u8BufferSize ] = highByte( telegram.u16reg[ i/2 ] );
  695. }
  696. modH->u8BufferSize++;
  697. }
  698. break;
  699. case MB_FC_WRITE_MULTIPLE_REGISTERS:
  700. modH->u8Buffer[ NB_HI ] = highByte(telegram.u16CoilsNo );
  701. modH->u8Buffer[ NB_LO ] = lowByte( telegram.u16CoilsNo );
  702. modH->u8Buffer[ BYTE_CNT ] = (uint8_t) ( telegram.u16CoilsNo * 2 );
  703. modH->u8BufferSize = 7;
  704. for (uint16_t i=0; i< telegram.u16CoilsNo; i++)
  705. {
  706. modH->u8Buffer[ modH->u8BufferSize ] = highByte( telegram.u16reg[ i ] );
  707. modH->u8BufferSize++;
  708. modH->u8Buffer[ modH->u8BufferSize ] = lowByte( telegram.u16reg[ i ] );
  709. modH->u8BufferSize++;
  710. }
  711. break;
  712. }
  713. sendTxBuffer(modH);
  714. xSemaphoreGive(modH->ModBusSphrHandle);
  715. modH->i8state = COM_WAITING;
  716. modH->i8lastError = 0;
  717. return 0;
  718. }
  719. #if ENABLE_TCP == 1
  720. static mb_errot_t TCPconnectserver(modbusHandler_t * modH, modbus_t *telegram)
  721. {
  722. err_t err;
  723. tcpclients_t *clientconn;
  724. //select the current connection slot to work with
  725. clientconn = &modH->newconns[modH->newconnIndex];
  726. if(telegram->u8clientID >= NUMBERTCPCONN )
  727. {
  728. return ERR_BAD_TCP_ID;
  729. }
  730. // if the connection is null open a new connection
  731. if (clientconn->conn == NULL)
  732. {
  733. clientconn->conn = netconn_new(NETCONN_TCP);
  734. if (clientconn == NULL)
  735. {
  736. while(1)
  737. {
  738. // error creating new connection check your configuration and heap size
  739. }
  740. }
  741. err = netconn_connect(clientconn->conn, (ip_addr_t *)&telegram->xIpAddress, telegram->u16Port);
  742. if (err != ERR_OK )
  743. {
  744. /*
  745. netconn_close(clientconn->conn);
  746. netconn_delete(clientconn->conn);
  747. clientconn=NULL;
  748. */
  749. ModbusCloseConn(clientconn->conn);
  750. return ERR_TIME_OUT;
  751. }
  752. }
  753. return ERR_OK;
  754. }
  755. static mb_errot_t TCPgetRxBuffer(modbusHandler_t * modH)
  756. {
  757. struct netbuf *inbuf;
  758. err_t err = ERR_TIME_OUT;
  759. char* buf;
  760. uint16_t buflen;
  761. uint16_t uLength;
  762. tcpclients_t *clientconn;
  763. //select the current connection slot to work with
  764. clientconn = &modH->newconns[modH->newconnIndex];
  765. netconn_set_recvtimeout(clientconn->conn, modH->u16timeOut);
  766. err = netconn_recv(clientconn->conn, &inbuf);
  767. uLength = 0;
  768. if (err == ERR_OK)
  769. {
  770. err = netconn_err(clientconn->conn) ;
  771. if (err == ERR_OK)
  772. {
  773. /* Read the data from the port, blocking if nothing yet there.
  774. We assume the request (the part we care about) is in one netbuf */
  775. err = netbuf_data(inbuf, (void**)&buf, &buflen);
  776. if(err == ERR_OK )
  777. {
  778. if (buflen>11) // minimum frame size for modbus TCP
  779. {
  780. if(buf[2] == 0 || buf[3] == 0 ) //validate protocol ID
  781. {
  782. uLength = (buf[4]<<8 & 0xff00) | buf[5];
  783. if(uLength< (MAX_BUFFER-2) && (uLength + 6) <= buflen)
  784. {
  785. for(int i = 0; i < uLength; i++)
  786. {
  787. modH->u8Buffer[i] = buf[i+6];
  788. }
  789. modH->u16TransactionID = (buf[0]<<8 & 0xff00) | buf[1];
  790. modH->u8BufferSize = uLength + 2; //include 2 dummy bytes for CRC
  791. }
  792. }
  793. }
  794. } // netbuf_data
  795. netbuf_delete(inbuf); //delete the buffer always
  796. }
  797. }
  798. //netconn_close(modH->newconn);
  799. //netconn_delete(modH->newconn);
  800. return err;
  801. }
  802. #endif
  803. void StartTaskModbusMaster(void *argument)
  804. {
  805. modbusHandler_t *modH = (modbusHandler_t *)argument;
  806. uint32_t ulNotificationValue;
  807. modbus_t telegram;
  808. for(;;)
  809. {
  810. /*Wait indefinitely for a telegram to send */
  811. xQueueReceive(modH->QueueTelegramHandle, &telegram, portMAX_DELAY);
  812. #if ENABLE_TCP ==1
  813. if(modH->xTypeHW == TCP_HW)
  814. {
  815. modH->newconnIndex = telegram.u8clientID;
  816. ulNotificationValue = TCPconnectserver( modH, &telegram);
  817. if(ulNotificationValue == ERR_OK)
  818. {
  819. SendQuery(modH, telegram);
  820. /* Block until a Modbus Frame arrives or query timeouts*/
  821. ulNotificationValue = TCPgetRxBuffer(modH); // TCP receives the data and the notification simultaneously since it is synchronous
  822. if (ulNotificationValue != ERR_OK) //close the TCP connection
  823. {
  824. /*
  825. netconn_close(modH->newconns[modH->newconnIndex].conn);
  826. netconn_delete(modH->newconns[modH->newconnIndex].conn);
  827. modH->newconns[modH->newconnIndex].conn = NULL;
  828. */
  829. ModbusCloseConn(modH->newconns[modH->newconnIndex].conn);
  830. }
  831. }
  832. else
  833. {
  834. /*
  835. netconn_close(modH->newconns[modH->newconnIndex].conn);
  836. netconn_delete(modH->newconns[modH->newconnIndex].conn);
  837. modH->newconns[modH->newconnIndex].conn = NULL;
  838. */
  839. ModbusCloseConn(modH->newconns[modH->newconnIndex].conn);
  840. }
  841. }
  842. else // send a query for USART and USB_CDC
  843. {
  844. SendQuery(modH, telegram);
  845. /* Block until a Modbus Frame arrives or query timeouts*/
  846. ulNotificationValue = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
  847. }
  848. #else
  849. // This is the case for implementations with only USART support
  850. SendQuery(modH, telegram);
  851. /* Block indefinitely until a Modbus Frame arrives or query timeouts*/
  852. ulNotificationValue = ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
  853. #endif
  854. // notify the task the request timeout
  855. modH->i8lastError = 0;
  856. if(ulNotificationValue)
  857. {
  858. modH->i8state = COM_IDLE;
  859. modH->i8lastError = ERR_TIME_OUT;
  860. modH->u16errCnt++;
  861. xTaskNotify((TaskHandle_t)telegram.u32CurrentTask, modH->i8lastError, eSetValueWithOverwrite);
  862. continue;
  863. }
  864. #if ENABLE_USB_CDC ==1 || ENABLE_TCP ==1
  865. if(modH->xTypeHW == USART_HW) //TCP and USB_CDC use different methods to get the buffer
  866. {
  867. getRxBuffer(modH);
  868. }
  869. #else
  870. getRxBuffer(modH);
  871. #endif
  872. if ( modH->u8BufferSize < 6){
  873. modH->i8state = COM_IDLE;
  874. modH->i8lastError = ERR_BAD_SIZE;
  875. modH->u16errCnt++;
  876. xTaskNotify((TaskHandle_t)telegram.u32CurrentTask, modH->i8lastError, eSetValueWithOverwrite);
  877. continue;
  878. }
  879. xTimerStop(modH->xTimerTimeout,0); // cancel timeout timer
  880. // validate message: id, CRC, FCT, exception
  881. int8_t u8exception = validateAnswer(modH);
  882. if (u8exception != 0)
  883. {
  884. modH->i8state = COM_IDLE;
  885. modH->i8lastError = u8exception;
  886. xTaskNotify((TaskHandle_t)telegram.u32CurrentTask, modH->i8lastError, eSetValueWithOverwrite);
  887. continue;
  888. }
  889. modH->i8lastError = u8exception;
  890. xSemaphoreTake(modH->ModBusSphrHandle , portMAX_DELAY); //before processing the message get the semaphore
  891. // process answer
  892. switch( modH->u8Buffer[ FUNC ] )
  893. {
  894. case MB_FC_READ_COILS:
  895. case MB_FC_READ_DISCRETE_INPUT:
  896. //call get_FC1 to transfer the incoming message to u16regs buffer
  897. get_FC1(modH);
  898. break;
  899. case MB_FC_READ_INPUT_REGISTER:
  900. case MB_FC_READ_REGISTERS :
  901. // call get_FC3 to transfer the incoming message to u16regs buffer
  902. get_FC3(modH);
  903. break;
  904. case MB_FC_WRITE_COIL:
  905. case MB_FC_WRITE_REGISTER :
  906. case MB_FC_WRITE_MULTIPLE_COILS:
  907. case MB_FC_WRITE_MULTIPLE_REGISTERS :
  908. // nothing to do
  909. break;
  910. default:
  911. break;
  912. }
  913. modH->i8state = COM_IDLE;
  914. if (modH->i8lastError ==0) // no error the error_OK, we need to use a different value than 0 to detect the timeout
  915. {
  916. xSemaphoreGive(modH->ModBusSphrHandle); //Release the semaphore
  917. xTaskNotify((TaskHandle_t)telegram.u32CurrentTask, ERR_OK_QUERY, eSetValueWithOverwrite);
  918. }
  919. continue;
  920. }
  921. }
  922. /**
  923. * This method processes functions 1 & 2 (for master)
  924. * This method puts the slave answer into master data buffer
  925. *
  926. * @ingroup register
  927. */
  928. void get_FC1(modbusHandler_t *modH)
  929. {
  930. uint8_t u8byte, i;
  931. u8byte = 3;
  932. for (i=0; i< modH->u8Buffer[2]; i++) {
  933. if(i%2)
  934. {
  935. modH->u16regs[i/2]= word(modH->u8Buffer[i+u8byte], lowByte(modH->u16regs[i/2]));
  936. }
  937. else
  938. {
  939. modH->u16regs[i/2]= word(highByte(modH->u16regs[i/2]), modH->u8Buffer[i+u8byte]);
  940. }
  941. }
  942. }
  943. /**
  944. * This method processes functions 3 & 4 (for master)
  945. * This method puts the slave answer into master data buffer
  946. *
  947. * @ingroup register
  948. */
  949. void get_FC3(modbusHandler_t *modH)
  950. {
  951. uint8_t u8byte, i;
  952. u8byte = 3;
  953. for (i=0; i< modH->u8Buffer[ 2 ] /2; i++)
  954. {
  955. modH->u16regs[ i ] = word(modH->u8Buffer[ u8byte ], modH->u8Buffer[ u8byte +1 ]);
  956. u8byte += 2;
  957. }
  958. }
  959. /**
  960. * @brief
  961. * This method validates master incoming messages
  962. *
  963. * @return 0 if OK, EXCEPTION if anything fails
  964. * @ingroup buffer
  965. */
  966. uint8_t validateAnswer(modbusHandler_t *modH)
  967. {
  968. // check message crc vs calculated crc
  969. #if ENABLE_TCP ==1
  970. if(modH->xTypeHW != TCP_HW)
  971. {
  972. #endif
  973. uint16_t u16MsgCRC =
  974. ((modH->u8Buffer[modH->u8BufferSize - 2] << 8)
  975. | modH->u8Buffer[modH->u8BufferSize - 1]); // combine the crc Low & High bytes
  976. if ( calcCRC(modH->u8Buffer, modH->u8BufferSize-2) != u16MsgCRC )
  977. {
  978. modH->u16errCnt ++;
  979. return ERR_BAD_CRC;
  980. }
  981. #if ENABLE_TCP ==1
  982. }
  983. #endif
  984. // check exception
  985. if ((modH->u8Buffer[ FUNC ] & 0x80) != 0)
  986. {
  987. modH->u16errCnt ++;
  988. return ERR_EXCEPTION;
  989. }
  990. // check fct code
  991. bool isSupported = false;
  992. for (uint8_t i = 0; i< sizeof( fctsupported ); i++)
  993. {
  994. if (fctsupported[i] == modH->u8Buffer[FUNC])
  995. {
  996. isSupported = 1;
  997. break;
  998. }
  999. }
  1000. if (!isSupported)
  1001. {
  1002. modH->u16errCnt ++;
  1003. return EXC_FUNC_CODE;
  1004. }
  1005. return 0; // OK, no exception code thrown
  1006. }
  1007. /**
  1008. * @brief
  1009. * This method moves Serial buffer data to the Modbus u8Buffer.
  1010. *
  1011. * @return buffer size if OK, ERR_BUFF_OVERFLOW if u8BufferSize >= MAX_BUFFER
  1012. * @ingroup buffer
  1013. */
  1014. int16_t getRxBuffer(modbusHandler_t *modH)
  1015. {
  1016. int16_t i16result;
  1017. if(modH->xTypeHW == USART_HW)
  1018. {
  1019. HAL_UART_AbortReceive_IT(modH->port); // disable interrupts to avoid race conditions on serial port
  1020. }
  1021. if (modH->xBufferRX.overflow)
  1022. {
  1023. RingClear(&modH->xBufferRX); // clean up the overflowed buffer
  1024. i16result = ERR_BUFF_OVERFLOW;
  1025. }
  1026. else
  1027. {
  1028. modH->u8BufferSize = RingGetAllBytes(&modH->xBufferRX, modH->u8Buffer);
  1029. modH->u16InCnt++;
  1030. i16result = modH->u8BufferSize;
  1031. }
  1032. if(modH->xTypeHW == USART_HW)
  1033. {
  1034. HAL_UART_Receive_IT(modH->port, &modH->dataRX, 1);
  1035. }
  1036. return i16result;
  1037. }
  1038. /**
  1039. * @brief
  1040. * This method validates slave incoming messages
  1041. *
  1042. * @return 0 if OK, EXCEPTION if anything fails
  1043. * @ingroup modH Modbus handler
  1044. */
  1045. uint8_t validateRequest(modbusHandler_t *modH)
  1046. {
  1047. // check message crc vs calculated crc
  1048. #if ENABLE_TCP ==1
  1049. uint16_t u16MsgCRC;
  1050. u16MsgCRC= ((modH->u8Buffer[modH->u8BufferSize - 2] << 8)
  1051. | modH->u8Buffer[modH->u8BufferSize - 1]); // combine the crc Low & High bytes
  1052. if (modH->xTypeHW != TCP_HW)
  1053. {
  1054. if ( calcCRC( modH->u8Buffer, modH->u8BufferSize-2 ) != u16MsgCRC )
  1055. {
  1056. modH->u16errCnt ++;
  1057. return ERR_BAD_CRC;
  1058. }
  1059. }
  1060. #else
  1061. uint16_t u16MsgCRC;
  1062. u16MsgCRC= ((modH->u8Buffer[modH->u8BufferSize - 2] << 8)
  1063. | modH->u8Buffer[modH->u8BufferSize - 1]); // combine the crc Low & High bytes
  1064. if ( calcCRC( modH->u8Buffer, modH->u8BufferSize-2 ) != u16MsgCRC )
  1065. {
  1066. modH->u16errCnt ++;
  1067. return ERR_BAD_CRC;
  1068. }
  1069. #endif
  1070. // check fct code
  1071. bool isSupported = false;
  1072. for (uint8_t i = 0; i< sizeof( fctsupported ); i++)
  1073. {
  1074. if (fctsupported[i] == modH->u8Buffer[FUNC])
  1075. {
  1076. isSupported = 1;
  1077. break;
  1078. }
  1079. }
  1080. if (!isSupported)
  1081. {
  1082. modH->u16errCnt ++;
  1083. return EXC_FUNC_CODE;
  1084. }
  1085. // check start address & nb range
  1086. uint16_t u16AdRegs = 0;
  1087. uint16_t u16NRegs = 0;
  1088. //uint8_t u8regs;
  1089. switch ( modH->u8Buffer[ FUNC ] )
  1090. {
  1091. case MB_FC_READ_COILS:
  1092. case MB_FC_READ_DISCRETE_INPUT:
  1093. case MB_FC_WRITE_MULTIPLE_COILS:
  1094. u16AdRegs = word( modH->u8Buffer[ ADD_HI ], modH->u8Buffer[ ADD_LO ]) / 16;
  1095. u16NRegs = word( modH->u8Buffer[ NB_HI ], modH->u8Buffer[ NB_LO ]) /16;
  1096. if(word( modH->u8Buffer[ NB_HI ], modH->u8Buffer[ NB_LO ]) % 16) u16NRegs++; // check for incomplete words
  1097. // verify address range
  1098. if((u16AdRegs + u16NRegs) > modH->u16regsize) return EXC_ADDR_RANGE;
  1099. //verify answer frame size in bytes
  1100. u16NRegs = word( modH->u8Buffer[ NB_HI ], modH->u8Buffer[ NB_LO ]) / 8;
  1101. if(word( modH->u8Buffer[ NB_HI ], modH->u8Buffer[ NB_LO ]) % 8) u16NRegs++;
  1102. u16NRegs = u16NRegs + 5; // adding the header and CRC ( Slave address + Function code + number of data bytes to follow + 2-byte CRC )
  1103. if(u16NRegs > 256) return EXC_REGS_QUANT;
  1104. break;
  1105. case MB_FC_WRITE_COIL:
  1106. u16AdRegs = word( modH->u8Buffer[ ADD_HI ], modH->u8Buffer[ ADD_LO ]) / 16;
  1107. if(word( modH->u8Buffer[ ADD_HI ], modH->u8Buffer[ ADD_LO ]) % 16) u16AdRegs++; // check for incomplete words
  1108. if (u16AdRegs > modH->u16regsize) return EXC_ADDR_RANGE;
  1109. break;
  1110. case MB_FC_WRITE_REGISTER :
  1111. u16AdRegs = word( modH->u8Buffer[ ADD_HI ], modH->u8Buffer[ ADD_LO ]);
  1112. if (u16AdRegs > modH-> u16regsize) return EXC_ADDR_RANGE;
  1113. break;
  1114. case MB_FC_READ_REGISTERS :
  1115. case MB_FC_READ_INPUT_REGISTER :
  1116. case MB_FC_WRITE_MULTIPLE_REGISTERS :
  1117. u16AdRegs = word( modH->u8Buffer[ ADD_HI ], modH->u8Buffer[ ADD_LO ]);
  1118. u16NRegs = word( modH->u8Buffer[ NB_HI ], modH->u8Buffer[ NB_LO ]);
  1119. if (( u16AdRegs + u16NRegs ) > modH->u16regsize) return EXC_ADDR_RANGE;
  1120. //verify answer frame size in bytes
  1121. u16NRegs = u16NRegs*2 + 5; // adding the header and CRC
  1122. if ( u16NRegs > 256 ) return EXC_REGS_QUANT;
  1123. break;
  1124. }
  1125. return 0; // OK, no exception code thrown
  1126. }
  1127. /**
  1128. * @brief
  1129. * This method creates a word from 2 bytes
  1130. *
  1131. * @return uint16_t (word)
  1132. * @ingroup H Most significant byte
  1133. * @ingroup L Less significant byte
  1134. */
  1135. uint16_t word(uint8_t H, uint8_t L)
  1136. {
  1137. bytesFields W;
  1138. W.u8[0] = L;
  1139. W.u8[1] = H;
  1140. return W.u16[0];
  1141. }
  1142. /**
  1143. * @brief
  1144. * This method calculates CRC
  1145. *
  1146. * @return uint16_t calculated CRC value for the message
  1147. * @ingroup Buffer
  1148. * @ingroup u8length
  1149. */
  1150. uint16_t calcCRC(uint8_t *Buffer, uint8_t u8length)
  1151. {
  1152. unsigned int temp, temp2, flag;
  1153. temp = 0xFFFF;
  1154. for (unsigned char i = 0; i < u8length; i++)
  1155. {
  1156. temp = temp ^ Buffer[i];
  1157. for (unsigned char j = 1; j <= 8; j++)
  1158. {
  1159. flag = temp & 0x0001;
  1160. temp >>=1;
  1161. if (flag)
  1162. temp ^= 0xA001;
  1163. }
  1164. }
  1165. // Reverse byte order.
  1166. temp2 = temp >> 8;
  1167. temp = (temp << 8) | temp2;
  1168. temp &= 0xFFFF;
  1169. // the returned value is already swapped
  1170. // crcLo byte is first & crcHi byte is last
  1171. return temp;
  1172. }
  1173. /**
  1174. * @brief
  1175. * This method builds an exception message
  1176. *
  1177. * @ingroup u8exception exception number
  1178. * @ingroup modH modbus handler
  1179. */
  1180. void buildException( uint8_t u8exception, modbusHandler_t *modH )
  1181. {
  1182. uint8_t u8func = modH->u8Buffer[ FUNC ]; // get the original FUNC code
  1183. modH->u8Buffer[ ID ] = modH->u8id;
  1184. modH->u8Buffer[ FUNC ] = u8func + 0x80;
  1185. modH->u8Buffer[ 2 ] = u8exception;
  1186. modH->u8BufferSize = EXCEPTION_SIZE;
  1187. }
  1188. #if ENABLE_USB_CDC == 1
  1189. extern uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len);
  1190. #endif
  1191. /**
  1192. * @brief
  1193. * This method transmits u8Buffer to Serial line.
  1194. * Only if u8txenpin != 0, there is a flow handling in order to keep
  1195. * the RS485 transceiver in output state as long as the message is being sent.
  1196. * This is done with TC bit.
  1197. * The CRC is appended to the buffer before starting to send it.
  1198. *
  1199. * @return nothing
  1200. * @ingroup modH Modbus handler
  1201. */
  1202. static void sendTxBuffer(modbusHandler_t *modH)
  1203. {
  1204. // append CRC to message
  1205. #if ENABLE_TCP == 1
  1206. if(modH->xTypeHW != TCP_HW)
  1207. {
  1208. #endif
  1209. uint16_t u16crc = calcCRC(modH->u8Buffer, modH->u8BufferSize);
  1210. modH->u8Buffer[ modH->u8BufferSize ] = u16crc >> 8;
  1211. modH->u8BufferSize++;
  1212. modH->u8Buffer[ modH->u8BufferSize ] = u16crc & 0x00ff;
  1213. modH->u8BufferSize++;
  1214. #if ENABLE_TCP == 1
  1215. }
  1216. #endif
  1217. #if ENABLE_USB_CDC == 1 || ENABLE_TCP == 1
  1218. if(modH->xTypeHW == USART_HW || modH->xTypeHW == USART_HW_DMA )
  1219. {
  1220. #endif
  1221. if (modH->EN_Port != NULL)
  1222. {
  1223. //enable transmitter, disable receiver to avoid echo on RS485 transceivers
  1224. HAL_HalfDuplex_EnableTransmitter(modH->port);
  1225. HAL_GPIO_WritePin(modH->EN_Port, modH->EN_Pin, GPIO_PIN_SET);
  1226. }
  1227. #if ENABLE_USART_DMA ==1
  1228. if(modH->xTypeHW == USART_HW)
  1229. {
  1230. #endif
  1231. // transfer buffer to serial line IT
  1232. HAL_UART_Transmit_IT(modH->port, modH->u8Buffer, modH->u8BufferSize);
  1233. #if ENABLE_USART_DMA ==1
  1234. }
  1235. else
  1236. {
  1237. //transfer buffer to serial line DMA
  1238. HAL_UART_Transmit_DMA(modH->port, modH->u8Buffer, modH->u8BufferSize);
  1239. }
  1240. #endif
  1241. ulTaskNotifyTake(pdTRUE, 250); //wait notification from TXE interrupt
  1242. /*
  1243. * If you are porting the library to a different MCU check the
  1244. * USART datasheet and add the corresponding family in the following
  1245. * preprocessor conditions
  1246. */
  1247. #if defined(STM32H7) || defined(STM32F3) || defined(STM32L4)
  1248. while((modH->port->Instance->ISR & USART_ISR_TC) ==0 )
  1249. #else
  1250. // F429, F103, L152 ...
  1251. while((modH->port->Instance->SR & USART_SR_TC) ==0 )
  1252. #endif
  1253. {
  1254. //block the task until the the last byte is send out of the shifting buffer in USART
  1255. }
  1256. if (modH->EN_Port != NULL)
  1257. {
  1258. //return RS485 transceiver to receive mode
  1259. HAL_GPIO_WritePin(modH->EN_Port, modH->EN_Pin, GPIO_PIN_RESET);
  1260. //enable receiver, disable transmitter
  1261. HAL_HalfDuplex_EnableReceiver(modH->port);
  1262. }
  1263. // set timeout for master query
  1264. if(modH->uModbusType == MB_MASTER )
  1265. {
  1266. xTimerReset(modH->xTimerTimeout,0);
  1267. }
  1268. #if ENABLE_USB_CDC == 1 || ENABLE_TCP == 1
  1269. }
  1270. #if ENABLE_USB_CDC == 1
  1271. else if(modH->xTypeHW == USB_CDC_HW)
  1272. {
  1273. CDC_Transmit_FS(modH->u8Buffer, modH->u8BufferSize);
  1274. // set timeout for master query
  1275. if(modH->uModbusType == MB_MASTER )
  1276. {
  1277. xTimerReset(modH->xTimerTimeout,0);
  1278. }
  1279. }
  1280. #endif
  1281. #if ENABLE_TCP == 1
  1282. else if(modH->xTypeHW == TCP_HW)
  1283. {
  1284. struct netvector xNetVectors[2];
  1285. uint8_t u8MBAPheader[6];
  1286. size_t uBytesWritten;
  1287. u8MBAPheader[0] = highByte(modH->u16TransactionID); // this might need improvement the transaction ID could be validated
  1288. u8MBAPheader[1] = lowByte(modH->u16TransactionID);
  1289. u8MBAPheader[2] = 0; //protocol ID
  1290. u8MBAPheader[3] = 0; //protocol ID
  1291. u8MBAPheader[4] = 0; //highbyte data length always 0
  1292. u8MBAPheader[5] = modH->u8BufferSize; //highbyte data length
  1293. xNetVectors[0].len = 6;
  1294. xNetVectors[0].ptr = (void *) u8MBAPheader;
  1295. xNetVectors[1].len = modH->u8BufferSize;
  1296. xNetVectors[1].ptr = (void *) modH->u8Buffer;
  1297. netconn_set_sendtimeout(modH->newconns[modH->newconnIndex].conn, modH->u16timeOut);
  1298. err_enum_t err;
  1299. err = netconn_write_vectors_partly(modH->newconns[modH->newconnIndex].conn, xNetVectors, 2, NETCONN_COPY, &uBytesWritten);
  1300. if (err != ERR_OK )
  1301. {
  1302. /*
  1303. netconn_close(modH->newconns[modH->newconnIndex].conn);
  1304. netconn_delete(modH->newconns[modH->newconnIndex].conn);
  1305. modH->newconns[modH->newconnIndex].conn = NULL;*/
  1306. ModbusCloseConn(modH->newconns[modH->newconnIndex].conn);
  1307. }
  1308. if(modH->uModbusType == MB_MASTER )
  1309. {
  1310. xTimerReset(modH->xTimerTimeout,0);
  1311. }
  1312. }
  1313. #endif
  1314. #endif
  1315. modH->u8BufferSize = 0;
  1316. // increase message counter
  1317. modH->u16OutCnt++;
  1318. }
  1319. /**
  1320. * @brief
  1321. * This method processes functions 1 & 2
  1322. * This method reads a bit array and transfers it to the master
  1323. *
  1324. * @return u8BufferSize Response to master length
  1325. * @ingroup discrete
  1326. */
  1327. int8_t process_FC1(modbusHandler_t *modH )
  1328. {
  1329. uint16_t u16currentRegister;
  1330. uint8_t u8currentBit, u8bytesno, u8bitsno;
  1331. uint8_t u8CopyBufferSize;
  1332. uint16_t u16currentCoil, u16coil;
  1333. // get the first and last coil from the message
  1334. uint16_t u16StartCoil = word( modH->u8Buffer[ ADD_HI ], modH->u8Buffer[ ADD_LO ] );
  1335. uint16_t u16Coilno = word( modH->u8Buffer[ NB_HI ], modH->u8Buffer[ NB_LO ] );
  1336. // put the number of bytes in the outcoming message
  1337. u8bytesno = (uint8_t) (u16Coilno / 8);
  1338. if (u16Coilno % 8 != 0) u8bytesno ++;
  1339. modH->u8Buffer[ ADD_HI ] = u8bytesno;
  1340. modH->u8BufferSize = ADD_LO;
  1341. modH->u8Buffer[modH->u8BufferSize + u8bytesno - 1 ] = 0;
  1342. // read each coil from the register map and put its value inside the outcoming message
  1343. u8bitsno = 0;
  1344. for (u16currentCoil = 0; u16currentCoil < u16Coilno; u16currentCoil++)
  1345. {
  1346. u16coil = u16StartCoil + u16currentCoil;
  1347. u16currentRegister = (u16coil / 16);
  1348. u8currentBit = (uint8_t) (u16coil % 16);
  1349. bitWrite(
  1350. modH->u8Buffer[ modH->u8BufferSize ],
  1351. u8bitsno,
  1352. bitRead( modH->u16regs[ u16currentRegister ], u8currentBit ) );
  1353. u8bitsno ++;
  1354. if (u8bitsno > 7)
  1355. {
  1356. u8bitsno = 0;
  1357. modH->u8BufferSize++;
  1358. }
  1359. }
  1360. // send outcoming message
  1361. if (u16Coilno % 8 != 0) modH->u8BufferSize ++;
  1362. u8CopyBufferSize = modH->u8BufferSize +2;
  1363. sendTxBuffer(modH);
  1364. return u8CopyBufferSize;
  1365. }
  1366. /**
  1367. * @brief
  1368. * This method processes functions 3 & 4
  1369. * This method reads a word array and transfers it to the master
  1370. *
  1371. * @return u8BufferSize Response to master length
  1372. * @ingroup register
  1373. */
  1374. int8_t process_FC3(modbusHandler_t *modH)
  1375. {
  1376. uint16_t u16StartAdd = word( modH->u8Buffer[ ADD_HI ], modH->u8Buffer[ ADD_LO ] );
  1377. uint8_t u8regsno = word( modH->u8Buffer[ NB_HI ], modH->u8Buffer[ NB_LO ] );
  1378. uint8_t u8CopyBufferSize;
  1379. uint16_t i;
  1380. modH->u8Buffer[ 2 ] = u8regsno * 2;
  1381. modH->u8BufferSize = 3;
  1382. for (i = u16StartAdd; i < u16StartAdd + u8regsno; i++)
  1383. {
  1384. modH->u8Buffer[ modH->u8BufferSize ] = highByte(modH->u16regs[i]);
  1385. modH->u8BufferSize++;
  1386. modH->u8Buffer[ modH->u8BufferSize ] = lowByte(modH->u16regs[i]);
  1387. modH->u8BufferSize++;
  1388. }
  1389. u8CopyBufferSize = modH->u8BufferSize +2;
  1390. sendTxBuffer(modH);
  1391. return u8CopyBufferSize;
  1392. }
  1393. /**
  1394. * @brief
  1395. * This method processes function 5
  1396. * This method writes a value assigned by the master to a single bit
  1397. *
  1398. * @return u8BufferSize Response to master length
  1399. * @ingroup discrete
  1400. */
  1401. int8_t process_FC5( modbusHandler_t *modH )
  1402. {
  1403. uint8_t u8currentBit;
  1404. uint16_t u16currentRegister;
  1405. uint8_t u8CopyBufferSize;
  1406. uint16_t u16coil = word( modH->u8Buffer[ ADD_HI ], modH->u8Buffer[ ADD_LO ] );
  1407. // point to the register and its bit
  1408. u16currentRegister = (u16coil / 16);
  1409. u8currentBit = (uint8_t) (u16coil % 16);
  1410. // write to coil
  1411. bitWrite(
  1412. modH->u16regs[ u16currentRegister ],
  1413. u8currentBit,
  1414. modH->u8Buffer[ NB_HI ] == 0xff );
  1415. // send answer to master
  1416. modH->u8BufferSize = 6;
  1417. u8CopyBufferSize = modH->u8BufferSize +2;
  1418. sendTxBuffer(modH);
  1419. return u8CopyBufferSize;
  1420. }
  1421. /**
  1422. * @brief
  1423. * This method processes function 6
  1424. * This method writes a value assigned by the master to a single word
  1425. *
  1426. * @return u8BufferSize Response to master length
  1427. * @ingroup register
  1428. */
  1429. int8_t process_FC6(modbusHandler_t *modH )
  1430. {
  1431. uint16_t u16add = word( modH->u8Buffer[ ADD_HI ], modH->u8Buffer[ ADD_LO ] );
  1432. uint8_t u8CopyBufferSize;
  1433. uint16_t u16val = word( modH->u8Buffer[ NB_HI ], modH->u8Buffer[ NB_LO ] );
  1434. modH->u16regs[ u16add ] = u16val;
  1435. // keep the same header
  1436. modH->u8BufferSize = RESPONSE_SIZE;
  1437. u8CopyBufferSize = modH->u8BufferSize + 2;
  1438. sendTxBuffer(modH);
  1439. return u8CopyBufferSize;
  1440. }
  1441. /**
  1442. * @brief
  1443. * This method processes function 15
  1444. * This method writes a bit array assigned by the master
  1445. *
  1446. * @return u8BufferSize Response to master length
  1447. * @ingroup discrete
  1448. */
  1449. int8_t process_FC15( modbusHandler_t *modH )
  1450. {
  1451. uint8_t u8currentBit, u8frameByte, u8bitsno;
  1452. uint16_t u16currentRegister;
  1453. uint8_t u8CopyBufferSize;
  1454. uint16_t u16currentCoil, u16coil;
  1455. bool bTemp;
  1456. // get the first and last coil from the message
  1457. uint16_t u16StartCoil = word( modH->u8Buffer[ ADD_HI ], modH->u8Buffer[ ADD_LO ] );
  1458. uint16_t u16Coilno = word( modH->u8Buffer[ NB_HI ], modH->u8Buffer[ NB_LO ] );
  1459. // read each coil from the register map and put its value inside the outcoming message
  1460. u8bitsno = 0;
  1461. u8frameByte = 7;
  1462. for (u16currentCoil = 0; u16currentCoil < u16Coilno; u16currentCoil++)
  1463. {
  1464. u16coil = u16StartCoil + u16currentCoil;
  1465. u16currentRegister = (u16coil / 16);
  1466. u8currentBit = (uint8_t) (u16coil % 16);
  1467. bTemp = bitRead(
  1468. modH->u8Buffer[ u8frameByte ],
  1469. u8bitsno );
  1470. bitWrite(
  1471. modH->u16regs[ u16currentRegister ],
  1472. u8currentBit,
  1473. bTemp );
  1474. u8bitsno ++;
  1475. if (u8bitsno > 7)
  1476. {
  1477. u8bitsno = 0;
  1478. u8frameByte++;
  1479. }
  1480. }
  1481. // send outcoming message
  1482. // it's just a copy of the incomping frame until 6th byte
  1483. modH->u8BufferSize = 6;
  1484. u8CopyBufferSize = modH->u8BufferSize +2;
  1485. sendTxBuffer(modH);
  1486. return u8CopyBufferSize;
  1487. }
  1488. /**
  1489. * @brief
  1490. * This method processes function 16
  1491. * This method writes a word array assigned by the master
  1492. *
  1493. * @return u8BufferSize Response to master length
  1494. * @ingroup register
  1495. */
  1496. int8_t process_FC16(modbusHandler_t *modH )
  1497. {
  1498. uint16_t u16StartAdd = modH->u8Buffer[ ADD_HI ] << 8 | modH->u8Buffer[ ADD_LO ];
  1499. uint16_t u16regsno = modH->u8Buffer[ NB_HI ] << 8 | modH->u8Buffer[ NB_LO ];
  1500. uint8_t u8CopyBufferSize;
  1501. uint16_t i;
  1502. uint16_t temp;
  1503. // build header
  1504. modH->u8Buffer[ NB_HI ] = 0;
  1505. modH->u8Buffer[ NB_LO ] = (uint8_t) u16regsno; // answer is always 256 or less bytes
  1506. modH->u8BufferSize = RESPONSE_SIZE;
  1507. // write registers
  1508. for (i = 0; i < u16regsno; i++)
  1509. {
  1510. temp = word(
  1511. modH->u8Buffer[ (BYTE_CNT + 1) + i * 2 ],
  1512. modH->u8Buffer[ (BYTE_CNT + 2) + i * 2 ]);
  1513. modH->u16regs[ u16StartAdd + i ] = temp;
  1514. }
  1515. u8CopyBufferSize = modH->u8BufferSize +2;
  1516. sendTxBuffer(modH);
  1517. return u8CopyBufferSize;
  1518. }