source: ctrl/firmware/Main/SES/Core/Src/modbus.c

Last change on this file was 83, checked in by Zed, 3 months ago

Modbus Master and Slave Hardware were tested.

File size: 31.6 KB
Line 
1/*
2 * modbus.c
3 *
4 * Created: 03.09.2012 08:39:20
5 *  Author: Falko
6 */
7
8
9
10#if MODBUS_SUPPORT == TRUE
11
12#include <stdio.h>
13
14
15#include "sysdata.h"
16#include "modbus.h"
17#include "stm32h7xx_hal.h"
18#include "main.h"
19#include "stm32h7xx_hal_tim.h"
20  //#include "stm32_hal_legacy.h"
21
22  // ---------------------------------------------------------
23  // -------------------- MODUL DEFINES ----------------------
24  // ---------------------------------------------------------
25
26
27
28
29  #define MODBUS_BROADCAST_ADDRESS        0x00
30  #define FC_READ_COILS                   0x01
31  #define FC_READ_HOLDING_REGISTERS       0x03
32  #define FC_WRITE_SINGLE_REGISTER        0x06
33  #define FC_WRITE_MULTIPLE_REGISTER      0x10
34
35  /* Protocol exceptions */
36  #define ILLEGAL_FUNCTION                0x01
37  #define ILLEGAL_DATA_ADDRESS            0x02
38  #define ILLEGAL_DATA_VALUE              0x03
39  #define SLAVE_DEVICE_FAILURE            0x04
40  #define SERVER_FAILURE                    0x04
41  #define ACKNOWLEDGE                     0x05
42  #define SLAVE_DEVICE_BUSY               0x06
43  #define SERVER_BUSY                     0x06
44  #define NEGATIVE_ACKNOWLEDGE            0x07
45  #define MEMORY_PARITY_ERROR             0x08
46  #define GATEWAY_PROBLEM_PATH            0x0A
47  #define GATEWAY_PROBLEM_TARGET            0x0B
48
49  /* Local Error codes */
50  #define INVALID_CRC                     -1
51
52  // Position der Daten im Rx String
53  #define OFFSET_SLAVE_ADRESS             0x00
54  #define OFFSET_FUNCTION_CODE            0x01
55  #define OFFSET_START_ADRESS_HI          0x02
56  #define OFFSET_START_ADRESS_LO          0x03
57  #define OFFSET_NO_OF_REGISTERS_HI       0x04
58  #define OFFSET_NO_OF_REGISTERS_LO       0x05
59
60  #define MIN_NUMBER_OF_REGISTERS_FC3     0x01
61  #define MAX_NUMBER_OF_REGISTERS_FC3     0x7D
62  #define MIN_NUMBER_OF_REGISTERS_FC16    0x01
63  #define MAX_NUMBER_OF_REGISTERS_FC16    0x7B
64
65  #ifdef DEBUG
66    #define RESPONSE_TIMEOUT                300 // * 1ms
67  #else
68    #define RESPONSE_TIMEOUT                1000 // * 1ms
69  #endif
70
71  #define FAST_BAUDRATE_INTERFRAME_DELAY_us   (1750UL)
72  // --- Externe Variablen --------------------------------------------
73  extern modbus_t modbusData;
74  extern sys_data_t sys_data;
75
76
77  // --- Private Funktions Prototypen --------------------------------------------
78
79                    void    mbUartInit                      (modbus_t* const mb_data, UART_HandleTypeDef* const usart, uint32_t baudrate,  uint32_t parityMode,  uint32_t stopBits , uint32_t nrOfBitsPerChar);
80                uint16_t    mbCrc16                         (uint8_t* buf, uint32_t len);
81                    void    mbSend                          (modbus_t* mb_data );
82                uint32_t    mbSlaveReadHoldingRegisters     (uint8_t* response_string, uint8_t* msg, uint32_t tx_position, uint8_t deviceID);
83                uint32_t    mbSlaveWriteMultipleRegisters   (uint8_t* response_string, uint8_t* msg,     uint32_t tx_position, uint32_t deviceID);
84                uint32_t    mbSlaveWriteSingleRegister      (uint8_t* response_string,uint8_t* msg,uint32_t tx_position, uint32_t deviceID);
85                uint32_t    mbSlaveResponseException        (uint8_t* response_string, uint32_t function_code, uint32_t exception_code,uint32_t tx_position) ;
86static HAL_StatusTypeDef    RS485_ModbusEx_Init             (UART_HandleTypeDef* huart, uint32_t Polarity, uint32_t AssertionTime, uint32_t DeassertionTime, uint32_t charReceiveTimeout);
87static              void    UART_TxISR_8BIT                 (UART_HandleTypeDef* huart);
88
89  // --- GEMEINSAME MODBUS FUNKTIONEN --------------------------------------------
90  // Diese Funktionen werden sowohl von Modbus Master als auch Modbus Slave verwendet
91
92  /*
93    *
94    * @brief  Diese Funktion Initialisert die Modbus Datenstrukturen und die Hardware
95    *
96    * Das Modbus Modul bentigt einen UART und einen Timer pro Modbus Anschluss
97    * Die Funktion erfordert eine vorhandene Callback funktion namens HAL_UART_MspInit
98    * In dieser muss:
99    * - Der UART CLK eingeschaltet werden
100    * - Die Pins initialisert werden (Alternate Port Funktion)
101    * - Der NVIC Interrupt eingeschaltet werden
102    * @param  mb_data : Datenstruktur zur Aufnahme aller Daten
103    * @param  baudrate : Bautrate
104    * @param  parityMode : Parity, mglich ist UART_PARITY_ODD, UART_PARITY_EVEN, UART_PARITY_NONE. Default ist lt. Modbus Standart EVEN
105    * @param  usart : Timer Modul, z.B. USART1
106    * @retval None
107  */
108void mbInit(modbus_t* const mb_data, uint32_t baudrate, uint32_t parityMode, uint16_t stopBits, UART_HandleTypeDef* const usart)
109{
110    uint32_t numberOfBitsPerChar;
111    //uint32_t stopBits;
112
113    if (stopBits < 1U || stopBits > 2U) stopBits = 1U;
114
115    // Berechne Stop Bits
116    /*if ((parityMode== MODBUS_UART_PARITY_EVEN) || (parityMode == MODBUS_UART_PARITY_ODD))
117    {
118      stopBits = 1;
119    }
120    else
121    {
122      stopBits = 2;
123    }*/
124
125    // Berechne Anzahl der Bits per Char
126    numberOfBitsPerChar = NUMBER_OF_STARTBITS + NUMBER_OF_DATABITS + stopBits;
127    if ((parityMode == MODBUS_UART_PARITY_EVEN) || (parityMode == MODBUS_UART_PARITY_ODD))
128    {
129      numberOfBitsPerChar +=1;
130    }
131
132    mbUartInit(mb_data, usart, baudrate, parityMode, stopBits, numberOfBitsPerChar);
133
134    // Datenstrukturen zurcksetzen
135    mb_data->last_query_function_code         =   0;
136    mb_data->last_query_tcp_id.w              =   0;
137    mb_data->last_query_number_of_register.=   0;
138    mb_data->current_query                    =   MB_QUERY_NOTHING;
139    mb_data->last_query_slave_adress          =   0;
140    mb_data->last_query_start_adress.w        =   0;
141    mb_data->last_query_timeout               =   false;
142}
143
144  /*
145    *
146    * @brief  Diese Funktion Initialisert die Modbus UART Hardware
147    *
148    * @param  mb_data : Datenstruktur zur Aufnahme aller Daten
149    * @param  usart : UART Modul, z.B. USART1
150    * @param  baudrate : UART BAUD
151    * @param  parityMmode : Parity, mglich ist:
152              UART_PARITY_ODD, UART_PARITY_EVEN, UART_PARITY_NONE.
153              Default ist lt. Modbus Standart EVEN
154    * @param  stopBits : Anzahl der Stop Bits, lt Modbus Standart
155    *         2 Stop Bits bei Parity None, ansonsten 2 Stop Bits
156    * @retval None
157  */
158  void mbUartInit(modbus_t* const mb_data, UART_HandleTypeDef* const usart, uint32_t baudrate,  uint32_t parityMode,  uint32_t stopBits , uint32_t nrOfBitsPerChar)
159  {
160    //--- Uart Init ------------------------------------------------------------
161    mb_data->uart      = usart;
162
163    // Init aus Cube
164    mb_data->uart->Instance = usart->Instance;
165    mb_data->uart->Init.BaudRate = 19200;
166    mb_data->uart->Init.WordLength = UART_WORDLENGTH_9B;
167    mb_data->uart->Init.StopBits = UART_STOPBITS_1;
168    mb_data->uart->Init.Parity = UART_PARITY_EVEN;
169    mb_data->uart->Init.Mode = UART_MODE_TX_RX;
170    mb_data->uart->Init.HwFlowCtl = UART_HWCONTROL_NONE;
171    mb_data->uart->Init.OverSampling = UART_OVERSAMPLING_16;
172    mb_data->uart->Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
173    mb_data->uart->Init.ClockPrescaler = UART_PRESCALER_DIV1;
174    mb_data->uart->AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
175
176    // Init nderungen
177
178    // Baudrate
179    mb_data->uart->Init.BaudRate   = baudrate;
180    // Parity Mode // Word length
181    if(parityMode == MODBUS_UART_PARITY_EVEN)
182    {
183       mb_data->uart->Init.Parity = UART_PARITY_EVEN;
184       mb_data->uart->Init.WordLength = UART_WORDLENGTH_9B;
185    }
186    else if(parityMode == MODBUS_UART_PARITY_ODD)
187    {
188       mb_data->uart->Init.Parity = UART_PARITY_ODD;
189       mb_data->uart->Init.WordLength = UART_WORDLENGTH_9B;
190    }
191    else
192    {
193       mb_data->uart->Init.Parity = UART_PARITY_NONE;
194       mb_data->uart->Init.WordLength = UART_WORDLENGTH_8B;
195    }
196    // Stopbits
197    if (stopBits == 1)
198    {
199      mb_data->uart->Init.StopBits = UART_STOPBITS_1;
200    }
201    else
202    {
203      mb_data->uart->Init.StopBits = UART_STOPBITS_2;
204    }
205    // Init
206    if (RS485_ModbusEx_Init(mb_data->uart, UART_DE_POLARITY_HIGH, 0, 0,TIMEOUT_FRAME_COMPLETE*nrOfBitsPerChar) != HAL_OK)
207    {
208      Error_Handler();
209    }
210    if (HAL_UARTEx_DisableFifoMode(mb_data->uart) != HAL_OK)
211    {
212      Error_Handler();
213    }
214
215    if(HAL_UART_Receive_IT(mb_data->uart, mb_data->rx_buffer, RXBUFFERSIZE) != HAL_OK)
216    {
217      printf("uart error \n\r");
218      while(1)
219      {
220      }
221    }
222  }
223
224  /*
225    *
226    * @brief  End ongoing Rx transfer on UART peripheral (following error detection or Reception completion).
227    * @param  huart: UART handle.
228    * @retval None
229  */
230  void mbUartEndRxTransfer(UART_HandleTypeDef *huart)
231  {
232    /* Disable RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts */
233    //CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
234    //CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
235
236    /* At end of Rx process, restore huart->RxState to Ready */
237    huart->RxState = HAL_UART_STATE_READY;
238  }
239
240  void mbUartRx(modbus_t* mb_data)
241  {
242    uint32_t  pos;
243    uint8_t   data;
244
245    pos = mb_data->rx_head;
246
247    if (pos >= RXBUFFERSIZE)
248    {
249      return;
250    }
251    //data = mb_data->uart->Instance->RDR
252    data = mb_data->uart->Instance->RDR & (uint8_t)0x00FF;  //NOTE: mb_data->uart.Instance->DR gendert
253    mb_data->rx_buffer[pos] = data;
254
255    mb_data->rx_head++;
256
257    //mbTimerStart(mb_data);
258  }
259
260  HAL_StatusTypeDef mbUartTx(UART_HandleTypeDef *huart)
261  {
262    uint16_t* tmp;
263
264    if(huart->Init.WordLength == UART_WORDLENGTH_9B)
265    {
266      tmp                     =   (uint16_t*) huart->pTxBuffPtr;
267      huart->Instance->TDR    =   (uint16_t)(*tmp & (uint16_t)0x01FF); //NOTE: huart->Instance->DR gendert
268
269      if(huart->Init.Parity == UART_PARITY_NONE)
270      {
271        huart->pTxBuffPtr += 2;
272      }
273      else
274      {
275        huart->pTxBuffPtr += 1;
276      }
277    }
278    else
279    {
280      huart->Instance->TDR = (uint8_t)(*huart->pTxBuffPtr++ & (uint8_t)0x00FF);   //NOTE:huart->Instance->DR gendert
281    }
282
283    if(--huart->TxXferCount == 0)
284    {
285      /* Disable the UART Transmit Complete Interrupt */
286      __HAL_UART_DISABLE_IT(huart, UART_IT_TXE);
287
288      /* Enable the UART Transmit Complete Interrupt */
289      __HAL_UART_ENABLE_IT(huart, UART_IT_TC);
290    }
291    return HAL_OK;
292  }
293
294  // huart->State gibt es nicht mehr. Ersetzt durch huart->gState.
295  /**
296    * @brief  Wraps up transmission in non blocking mode.
297    * @param  huart: pointer to a UART_HandleTypeDef structure that contains
298    *                the configuration information for the specified UART module.
299    * @retval HAL status
300    */
301  static void UART_EndTransmit_IT(UART_HandleTypeDef *huart)
302  {
303    /* Disable the UART Transmit Complete Interrupt */
304    CLEAR_BIT(huart->Instance->CR1, USART_CR1_TCIE);
305
306    /* Tx process is ended, restore huart->gState to Ready */
307    huart->gState = HAL_UART_STATE_READY;
308
309    /* Cleat TxISR function pointer */
310    huart->TxISR = NULL;
311
312  #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
313    /*Call registered Tx complete callback*/
314    huart->TxCpltCallback(huart);
315  #else
316    /*Call legacy weak Tx complete callback*/
317    HAL_UART_TxCpltCallback(huart);
318  #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
319  }
320
321
322static HAL_StatusTypeDef RS485_ModbusEx_Init(UART_HandleTypeDef *huart, uint32_t Polarity, uint32_t AssertionTime, uint32_t DeassertionTime, uint32_t charReceiveTimeout)
323{
324  uint32_t temp;
325
326  /* Check the UART handle allocation */
327  if (huart == NULL)
328  {
329    return HAL_ERROR;
330  }
331  /* Check the Driver Enable UART instance */
332  assert_param(IS_UART_DRIVER_ENABLE_INSTANCE(huart->Instance));
333
334  /* Check the Driver Enable polarity */
335  assert_param(IS_UART_DE_POLARITY(Polarity));
336
337  /* Check the Driver Enable assertion time */
338  assert_param(IS_UART_ASSERTIONTIME(AssertionTime));
339
340  /* Check the Driver Enable deassertion time */
341  assert_param(IS_UART_DEASSERTIONTIME(DeassertionTime));
342
343  if (huart->gState == HAL_UART_STATE_RESET)
344  {
345    /* Allocate lock resource and initialize it */
346    huart->Lock = HAL_UNLOCKED;
347
348#if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
349    UART_InitCallbacksToDefault(huart);
350
351    if (huart->MspInitCallback == NULL)
352    {
353      huart->MspInitCallback = HAL_UART_MspInit;
354    }
355
356    /* Init the low level hardware */
357    huart->MspInitCallback(huart);
358#else
359    /* Init the low level hardware : GPIO, CLOCK, CORTEX */
360    HAL_UART_MspInit(huart);
361#endif /* (USE_HAL_UART_REGISTER_CALLBACKS) */
362  }
363
364  huart->gState = HAL_UART_STATE_BUSY;
365
366  /* Disable the Peripheral */
367  __HAL_UART_DISABLE(huart);
368
369  /* Set the UART Communication parameters */
370  if (UART_SetConfig(huart) == HAL_ERROR)
371  {
372    return HAL_ERROR;
373  }
374
375  if (huart->AdvancedInit.AdvFeatureInit != UART_ADVFEATURE_NO_INIT)
376  {
377    UART_AdvFeatureConfig(huart);
378  }
379
380  /* Enable the Driver Enable mode by setting the DEM bit in the CR3 register */
381  SET_BIT(huart->Instance->CR3, USART_CR3_DEM);
382
383  /* Set the Driver Enable polarity */
384  MODIFY_REG(huart->Instance->CR3, USART_CR3_DEP, Polarity);
385
386  /* Set the Driver Enable assertion and deassertion times */
387  temp = (AssertionTime << UART_CR1_DEAT_ADDRESS_LSB_POS);
388  temp |= (DeassertionTime << UART_CR1_DEDT_ADDRESS_LSB_POS);
389  MODIFY_REG(huart->Instance->CR1, (USART_CR1_DEDT | USART_CR1_DEAT), temp);
390
391// EDIT ECS START
392  /*Set receive timeout time*/
393  SET_BIT(huart->Instance->CR2, USART_CR2_RTOEN);
394  SET_BIT(huart->Instance->CR1, USART_CR1_RTOIE);
395  //MODIFY_REG(huart->Instance->RTOR, USART_RTOR_RTO, charReceiveTimeout);
396  if (huart->Init.BaudRate <= 19200) MODIFY_REG(huart->Instance->RTOR, USART_RTOR_RTO, charReceiveTimeout);
397  else
398  {
399      uint32_t fixedDelayInBitDurations = (FAST_BAUDRATE_INTERFRAME_DELAY_us * huart->Init.BaudRate) / 1000000UL + 1UL;
400      MODIFY_REG(huart->Instance->RTOR, USART_RTOR_RTO, fixedDelayInBitDurations);
401  }
402// EDIT ECS END
403
404  /* Enable the Peripheral */
405  __HAL_UART_ENABLE(huart);
406
407  /* TEACK and/or REACK to check before moving huart->gState and huart->RxState to Ready */
408  return (UART_CheckIdleState(huart));
409}
410
411//------------------------------------------------------------------------------
412
413//static int test;
414void MODBUS_UART_IRQHandler(UART_HandleTypeDef* const huart, modbus_t* const modbusData)
415{
416    uint32_t isrflags   = READ_REG(huart->Instance->ISR);
417    uint32_t cr1its     = READ_REG(huart->Instance->CR1);
418    //uint32_t cr2its     = READ_REG(huart->Instance->CR2);
419    uint32_t cr3its     = READ_REG(huart->Instance->CR3);
420
421    uint32_t errorflags;
422    //uint32_t errorcode;
423
424        errorflags = (isrflags & (uint32_t)(USART_ISR_PE | USART_ISR_FE | USART_ISR_ORE | USART_ISR_NE));
425
426    // If some errors occur
427    if ((errorflags != 0U) && ((((cr3its & (USART_CR3_RXFTIE | USART_CR3_EIE)) != 0U) || ((cr1its & (USART_CR1_RXNEIE_RXFNEIE | USART_CR1_PEIE)) != 0U))))
428    {
429                // UART parity error interrupt occurred --------------------------------
430        if (((isrflags & USART_ISR_PE) != 0U) && ((cr1its & USART_CR1_PEIE) != 0U))
431        {
432            __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_PEF);
433
434            huart->ErrorCode |= HAL_UART_ERROR_PE;
435        }
436
437                // UART frame error interrupt occurred ---------------------------------
438        if (((isrflags & USART_ISR_FE) != 0U) && ((cr3its & USART_CR3_EIE) != 0U))
439        {
440            __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_FEF);
441
442            huart->ErrorCode |= HAL_UART_ERROR_FE;
443        }
444
445        // UART noise error interrupt occurred ---------------------------------
446        if (((isrflags & USART_ISR_NE) != 0U) && ((cr3its & USART_CR3_EIE) != 0U))
447        {
448            __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_NEF);
449
450            huart->ErrorCode |= HAL_UART_ERROR_NE;
451        }
452
453        // UART Over-Run interrupt occurred ------------------------------------
454        if (((isrflags & USART_ISR_ORE) != 0U) && (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U) || ((cr3its & (USART_CR3_RXFTIE | USART_CR3_EIE)) != 0U)))
455        {
456            __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF);
457
458            huart->ErrorCode |= HAL_UART_ERROR_ORE;
459        }
460        } // End if some error occurs
461
462
463    // UART in mode Receiver (receive Timeout occured)--------------------------
464    if (((isrflags & USART_ISR_RTOF) != 0U) && (((cr1its & USART_CR1_RTOIE) != 0U) || ((cr3its & USART_CR2_RTOEN) != 0U)))
465    {
466        __HAL_UART_CLEAR_FLAG(huart, USART_ICR_RTOCF);
467        huart->RxState = HAL_UART_STATE_READY;
468        huart->gState = HAL_UART_STATE_READY;
469        modbusData->mb_rx_frame_complete = 1;
470        modbusData->setRxLed = true;
471    }
472
473    // UART in mode Receiver ---------------------------------------------------
474    if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U) && (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U) || ((cr3its & USART_CR3_RXFTIE) != 0U)))
475    {
476        if ((huart->RxState == HAL_UART_STATE_BUSY_RX) && (modbusData->rx_head < RXBUFFERSIZE))    //-> empfängt dann ein byte aber das ist nicht wild
477        {
478            modbusData->rx_buffer[modbusData->rx_head] = huart->Instance->RDR;
479            /*DEBUG//printf("xx%d: nr:%d  %d\n",test ++,modbusData.rx_head, modbusData.rx_buffer[modbusData.rx_head]);*/
480            modbusData->rx_head++;
481            modbusData->setRxLed = true;
482        }
483        else
484        {
485            __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
486        }
487    }
488
489    // UART in mode Transmitter ------------------------------------------------
490    if (((isrflags & USART_ISR_TXE_TXFNF) != 0U) && (((cr1its & USART_CR1_TXEIE_TXFNFIE) != 0U) || ((cr3its & USART_CR3_TXFTIE) != 0U)))
491    {
492        UART_TxISR_8BIT(modbusData->uart);
493        modbusData->setTxLed = true;
494    }
495
496    // UART in mode Transmitter (transmission end) -----------------------------
497    if (((isrflags & USART_ISR_TC) != 0U) && ((cr1its & USART_CR1_TCIE) != 0U))
498    {
499        modbusData->current_query = MB_QUERY_NOTHING;
500        UART_EndTransmit_IT(huart);
501        huart->RxState = HAL_UART_STATE_BUSY_RX;
502//              /*Reset TX complete interrupt flag*/
503//              __HAL_UART_CLEAR_FLAG(huart, USART_ISR_TC);
504//              /* Disable the UART Transmit Complete Interrupt */
505//              CLEAR_BIT(huart->Instance->CR1, USART_CR1_TCIE);
506//              /*TX complete callback function*/
507//              HAL_UART_TxCpltCallback(huart);
508//              /* Tx process is ended, restore huart->gState to Ready */
509//              huart->gState = HAL_UART_STATE_READY;
510        }
511
512    // Call UART Error Call back function if need be ---------------------------
513    if (huart->ErrorCode != HAL_UART_ERROR_NONE)
514    {
515                huart->RxState = HAL_UART_STATE_BUSY_RX;
516        // UART in mode Receiver -----------------------------------------------
517        if (((isrflags & USART_ISR_RXNE_RXFNE) != 0U) && (((cr1its & USART_CR1_RXNEIE_RXFNEIE) != 0U) || ((cr3its & USART_CR3_RXFTIE) != 0U)))
518        {
519                        __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);
520                        huart->ErrorCode = HAL_UART_ERROR_NONE;
521        }
522        else if (((isrflags & USART_ISR_TXE_TXFNF) != 0U) && (((cr1its & USART_CR1_TXEIE_TXFNFIE) != 0U) || ((cr3its & USART_CR3_TXFTIE) != 0U)))
523        {
524                        modbusData->current_query = MB_QUERY_NOTHING;
525                        UART_EndTransmit_IT(huart);
526                        huart->RxState = HAL_UART_STATE_BUSY_RX;
527                        modbusData->setTxLed = true;
528        }
529    }
530}
531
532//------------------------------------------------------------------------------
533
534
535
536
537
538/**
539  * @brief TX interrrupt handler for 7 or 8 bits data word length .
540  * @note   Function is called under interruption only, once
541  *         interruptions have been enabled by HAL_UART_Transmit_IT().
542  * @param huart UART handle.
543  * @retval None
544  */
545static void UART_TxISR_8BIT(UART_HandleTypeDef *huart)
546{
547  /* Check that a Tx process is ongoing */
548  if (huart->gState == HAL_UART_STATE_BUSY_TX)
549  {
550    if (huart->TxXferCount == 0U)
551    {
552      /* Disable the UART Transmit Data Register Empty Interrupt */
553      CLEAR_BIT(huart->Instance->CR1, USART_CR1_TXEIE_TXFNFIE);
554
555      /* Enable the UART Transmit Complete Interrupt */
556      SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
557    }
558    else
559    {
560      huart->Instance->TDR = (uint8_t)(*huart->pTxBuffPtr & (uint8_t)0xFF);
561      huart->pTxBuffPtr++;
562      huart->TxXferCount--;
563    }
564  }
565  else
566  {
567      /* Disable the UART Transmit Data Register Empty Interrupt */
568      CLEAR_BIT(huart->Instance->CR1, USART_CR1_TXEIE_TXFNFIE);
569
570      /* Enable the UART Transmit Complete Interrupt */
571      SET_BIT(huart->Instance->CR1, USART_CR1_TCIE);
572  }
573}
574
575
576
577
578
579
580
581
582
583
584
585
586  /**
587    * @brief  Output Compare callback in non blocking mode
588    * @param  htim : TIM OC handle
589    * @retval None
590    */
591  void mbTimerIsr(modbus_t * mb_data)
592  {
593    /* Capture compare 1 event */
594//    if(__HAL_TIM_GET_FLAG(mb_data->timer, TIM_FLAG_CC1) != RESET)
595//    {
596//      if(__HAL_TIM_GET_IT_SOURCE(mb_data->timer, TIM_IT_CC1) !=RESET)
597//      {
598//        __HAL_TIM_CLEAR_IT(mb_data->timer, TIM_IT_CC1);
599//        mb_data->timer->Channel = HAL_TIM_ACTIVE_CHANNEL_1;
600
601        mb_data->mb_rx_frame_complete=true;
602//        mb_data->timer->Instance->CNT =0;
603//        HAL_TIM_OC_Stop_IT(mb_data->timer, TIM_CHANNEL_1);
604//        mb_data->timer->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
605//
606//      }
607//    }
608  }
609
610
611  void mbSend(modbus_t * mb_data )
612  {
613    mb_data->current_query = MB_QUERY_SEND_DATA;
614    HAL_UART_Transmit_IT(mb_data->uart, mb_data->tx_buffer, mb_data->tx_head);
615  }
616
617  void mbClearTxBuffer(modbus_t * mb_data)
618  {
619    mb_data->tx_head = 0;
620  }
621
622
623
624  // Compute the MODBUS RTU CRC
625  uint16_t mbCrc16 ( uint8_t *buf, uint32_t len)
626  {
627    uint16_t crc = 0xFFFF;
628
629    for (uint32_t pos = 0; pos < len; pos++)
630    {
631      crc ^= (uint16_t)buf[pos];          // XOR byte into least sig. byte of crc
632
633      for (int i = 8; i != 0; i--)
634      {    // Loop over each bit
635        if ((crc & 0x0001) != 0)
636        {      // If the LSB is set
637                crc >>= 1;                    // Shift right and XOR 0xA001
638                crc ^= 0xA001;
639        }
640        else                            // Else LSB is not set
641        {
642                crc >>= 1;                    // Just shift right
643        }
644      }
645    }
646
647    // Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes)
648    return crc;
649  }
650
651  /* If CRC is correct returns msg_length else returns INVALID_CRC */
652  int mbCheckCrc16( uint8_t *msg, const int msg_length)
653  {
654    int ret;
655    uint16_t crc_calc;
656    uint16_t crc_received;
657
658    crc_calc = mbCrc16(msg, msg_length - 2);
659    crc_received = (msg[msg_length - 1] << 8) | msg[msg_length - 2];
660
661    // Check CRC of msg
662    if (crc_calc == crc_received) {
663            ret = msg_length;
664    } else {
665            ret = INVALID_CRC;
666    }
667    return ret;
668  }
669
670  uint32_t mbAppendCrc16(uint8_t * buffer, uint32_t tx_position)
671  {
672    uint16_t crc = mbCrc16( buffer , tx_position);
673
674    uint8_t l_crc = (uint8_t) (crc & 0x00FF) ;
675    uint8_t h_crc = (uint8_t) (crc >> 8);
676    buffer[tx_position] = l_crc;
677    tx_position++;
678    buffer[tx_position] = h_crc;
679    tx_position++;
680    return tx_position;
681  }
682
683  /************************************************************************************************************
684  Function: mb_get_frame_complete
685  Purpose:  Rckabe ob Frame komplett empfangen wurde
686  *************************************************************************************************************/
687  bool mbGetFrameComplete(modbus_t * mb_data)
688  {
689          return mb_data->mb_rx_frame_complete;
690  }
691
692  void mbClearRxFrame(modbus_t * mb_data)
693  {
694    // Wieder bei 0 im buffer anfangen
695    mb_data->rx_head = 0;
696
697    // keine Daten mehr vorhanden
698    mb_data->mb_rx_frame_complete=false;
699  }
700
701
702  // --------------------- SLAVE FUNCTIONS ---------------------------------------
703
704#define SEND_TO_SLAVES_BUFFER_COUNT 1000
705//static TASK_MODBUS_MASTER_Message_t xMessage[255];
706//static TASK_MODBUS_MASTER_Message_t *pxMessage;
707static bword_t values[SEND_TO_SLAVES_BUFFER_COUNT];
708static uint32_t y;
709static uint32_t z;
710
711uint32_t mbSlaveCheckModbusRtuQuery(modbus_t* mb_data)
712{
713    uint32_t message_lengh;
714    uint8_t *modbus_rx_message;
715    modbus_rx_message = mb_data->rx_buffer;
716    message_lengh= mb_data->rx_head;
717    uint32_t slave_adress;
718    slave_adress = modbus_rx_message[0];
719
720    if (message_lengh < 5) //Mindestens 5 Zeichen (Slave Adress + Function Code + 2x CRC
721    {
722      mbClearRxFrame(mb_data);
723      return 0;
724    }
725
726    // Prfe CRC
727    if (mbCheckCrc16(modbus_rx_message,message_lengh) == INVALID_CRC)
728    {
729      mbClearRxFrame(mb_data);
730      return 0;
731    }
732
733    if  (slave_adress == MODBUS_BROADCAST_ADDRESS)
734    {
735
736      return  RESPOND_TO_QUERY;
737    }
738    /* auf richtige Slave Adresse checken ansonsten nicht antworten*/
739    else if (slave_adress == sys_data.s.lb_slave_address)
740    {
741      return RESPOND_TO_QUERY;
742    }
743
744    mbClearRxFrame(mb_data);
745    return 0;
746}
747
748  void mbSlaveProcessRtuQuery(modbus_t * mb_data)
749  {
750    uint32_t tx_position=0; //die _Nchste_ Position in der Zeichen eingefgt werden mssen
751    uint8_t *modbus_rx_message;
752    modbus_rx_message = &mb_data->rx_buffer[0];
753
754    //Vorbereiten auf neues senden
755    mbClearTxBuffer(mb_data);
756
757    //mb_data->tx_buffer[0] = sys_data.s.vmGreenview.s.lb_slave_adress;
758    mb_data->tx_buffer[0] = *modbus_rx_message;
759    tx_position++;
760    tx_position = mbSlaveProcessPdu(mb_data->tx_buffer , modbus_rx_message,tx_position, *modbus_rx_message);
761
762    tx_position = mbAppendCrc16(mb_data->tx_buffer ,tx_position);
763    mb_data->tx_head=tx_position;
764    mbSend(mb_data);
765    mbClearRxFrame(mb_data);
766  }
767
768  uint32_t mbSlaveProcessPdu (uint8_t* response_string,    uint8_t * msg,    uint32_t tx_position,     uint8_t deviceID)
769  {
770    uint32_t function_code;
771    uint32_t ret;
772
773    function_code = msg[OFFSET_FUNCTION_CODE];
774
775    switch (function_code)
776    {
777      case FC_READ_HOLDING_REGISTERS:
778      ret= mbSlaveReadHoldingRegisters(response_string, msg,tx_position, deviceID);
779      break;
780
781      case FC_WRITE_SINGLE_REGISTER:
782      ret = mbSlaveWriteSingleRegister(response_string, msg,tx_position, deviceID);
783      break;
784
785      case FC_WRITE_MULTIPLE_REGISTER:
786      ret=mbSlaveWriteMultipleRegisters(response_string, msg,tx_position, deviceID);
787      break;
788
789      default:
790      ret=mbSlaveResponseException(response_string,function_code,ILLEGAL_FUNCTION,tx_position);
791      break;
792    }
793
794    return ret;
795  }
796
797
798  uint32_t mbSlaveReadHoldingRegisters( uint8_t * response_string, uint8_t *msg, uint32_t tx_position, uint8_t deviceID)
799  {
800    uint32_t start_adress;
801    uint32_t adress;
802    uint32_t number_of_registers;
803
804    /*stimmt die device ID mit der eigenen berein*/
805    if((deviceID != sys_data.s.lb_slave_address) && (deviceID != 0))
806    {
807       return mbSlaveResponseException(response_string,FC_WRITE_SINGLE_REGISTER,GATEWAY_PROBLEM_TARGET,tx_position);
808    }
809
810    start_adress = (msg[OFFSET_START_ADRESS_HI] << 8) + msg[OFFSET_START_ADRESS_LO];
811    number_of_registers = ( msg[OFFSET_NO_OF_REGISTERS_HI] << 8) + msg[OFFSET_NO_OF_REGISTERS_LO];
812
813    if ((number_of_registers < MIN_NUMBER_OF_REGISTERS_FC3) || (number_of_registers > MAX_NUMBER_OF_REGISTERS_FC3) )
814    {
815      return mbSlaveResponseException(response_string,FC_READ_HOLDING_REGISTERS,ILLEGAL_DATA_VALUE,tx_position);
816    }
817
818    if (start_adress+number_of_registers-1 > MAX_ADRESS)
819    {
820      return mbSlaveResponseException(response_string, FC_READ_HOLDING_REGISTERS,ILLEGAL_DATA_ADDRESS,tx_position);
821    }
822
823    response_string[tx_position] = FC_READ_HOLDING_REGISTERS;                                                                                   // FUNCTION CODE
824    tx_position++;
825    response_string[tx_position] = number_of_registers * 2;                                                                                             // Bytes
826    tx_position++;
827
828    for(adress=start_adress;adress < (start_adress + number_of_registers);adress++)
829    {
830      /*Daten aus dem Speicher senden*/
831      response_string[tx_position] = sys_data.mb[adress].b[1];
832      tx_position++;
833      response_string[tx_position] = sys_data.mb[adress].b[0];
834      tx_position++;
835    }
836
837    return tx_position;
838  }
839
840
841  uint32_t mbSlaveWriteMultipleRegisters(uint8_t * response_string, uint8_t *msg, uint32_t tx_position, uint32_t deviceID)
842  {
843
844    uint32_t start_adress;
845    uint32_t number_of_registers;
846    uint32_t adress;
847    uint32_t offset;
848
849    /*stimmt die device ID mit der eigenen berein*/
850    if((deviceID != sys_data.s.lb_slave_address) && (deviceID != 0))
851    {
852       return mbSlaveResponseException(response_string,FC_WRITE_SINGLE_REGISTER,GATEWAY_PROBLEM_TARGET,tx_position);
853    }
854
855    start_adress = (msg[OFFSET_START_ADRESS_HI] << 8) + msg[OFFSET_START_ADRESS_LO];
856    number_of_registers = ( msg[OFFSET_NO_OF_REGISTERS_HI] << 8) + msg[OFFSET_NO_OF_REGISTERS_LO];
857    offset=7;
858
859    if ((number_of_registers < MIN_NUMBER_OF_REGISTERS_FC16) || (number_of_registers > MAX_NUMBER_OF_REGISTERS_FC16) )
860    {
861      return mbSlaveResponseException(response_string, FC_WRITE_MULTIPLE_REGISTER,ILLEGAL_DATA_VALUE,tx_position);
862    }
863
864    if (start_adress+number_of_registers-1 > MAX_ADRESS)
865    {
866      return mbSlaveResponseException(response_string, FC_WRITE_MULTIPLE_REGISTER,ILLEGAL_DATA_ADDRESS,tx_position);
867    }
868
869    /*Daten in Gertespeicher schreiben*/
870    for(adress=start_adress;adress < (start_adress + number_of_registers);adress++)
871    {
872      sys_data.mb[adress].b[1] = msg[offset];
873      sys_data.mb[adress].b[0] = msg[offset+1];
874      offset+=2;
875    }
876
877    response_string[tx_position] = FC_WRITE_MULTIPLE_REGISTER; // FUNCTION CODE - 1 byte
878    tx_position++;
879    response_string[tx_position] = start_adress >> 8;
880    tx_position++;
881    response_string[tx_position] = (uint8_t ) ( start_adress  & 0x00FF); // start adresse 2 byte
882    tx_position++;
883    response_string[tx_position] = number_of_registers >> 8;
884    tx_position++;
885    response_string[tx_position] = (uint8_t ) ( number_of_registers  & 0x00FF); // Anzahl Register 2 byte
886    tx_position++;
887    return tx_position;
888  }
889
890
891  uint32_t mbSlaveWriteSingleRegister(uint8_t * response_string,uint8_t *msg,uint32_t tx_position, uint32_t deviceID)
892  {
893
894    uint32_t adress;
895
896    /*stimmt die device ID mit der eigenen berein*/
897    if((deviceID != sys_data.s.lb_slave_address) && (deviceID != 0))
898    {
899       return mbSlaveResponseException(response_string,FC_WRITE_SINGLE_REGISTER,GATEWAY_PROBLEM_TARGET,tx_position);
900    }
901
902    adress = (msg[2] << 8) + msg[3];
903
904    if (adress >  MAX_ADRESS)
905    {
906      return mbSlaveResponseException(response_string,FC_WRITE_SINGLE_REGISTER,ILLEGAL_DATA_ADDRESS,tx_position);
907    }
908
909    /*schreibe Daten in eigenen Speicher*/
910    sys_data.mb[adress].b[1] = msg[4];
911    sys_data.mb[adress].b[0] = msg[5];
912
913    response_string[tx_position]= FC_WRITE_SINGLE_REGISTER; // FUNCTION CODE
914    tx_position++;
915    response_string[tx_position]= adress >> 8;
916    tx_position++;
917    response_string[tx_position]= (uint8_t ) ( adress  & 0x00FF);
918
919    tx_position++;
920    response_string[tx_position]= msg[4];
921    tx_position++;
922    response_string[tx_position]= msg[5];
923    tx_position++;
924
925    return tx_position;
926  }
927
928
929  uint32_t mbSlaveResponseException(uint8_t* response_string, uint32_t function_code, uint32_t exception_code,uint32_t tx_position )
930  {
931    function_code += 0x80;
932    response_string[tx_position] = function_code; //  FUNCTION CODE
933    tx_position++;
934    response_string[tx_position] = exception_code; //
935    tx_position++;
936    return tx_position;
937  }
938
939
940  //---------------------------- UNKNOWN -----------------------------------------
941  //-                                                                            -
942  //------------------------------------------------------------------------------
943
944#endif
Note: See TracBrowser for help on using the repository browser.