/*
 * modbus.h
 *
 * Created: 03.09.2012 08:39:40
 *  Author: Falko
 */ 


#ifndef MODBUS_H_
#define MODBUS_H_
  
  #if MODBUS_SUPPORT == TRUE

    #include "stdint.h"
    #include "stdbool.h"
    #include "main.h"


    //! brief Anzahl der Startbits, nach Modbus Spezifikation immer 1, stop bits werden aus den Einstellungen geladen
    #define NUMBER_OF_STARTBITS				1	
  
    //! brief Anzahl der Datenbits, nach Modbus Spezifikation immer 8
    #define NUMBER_OF_DATABITS				8	
  
    //! brief Max Timeput zwischen zwei gesendeten char
    #define TIMEOUT_BETWEEN_CHARACTERS		        1.5
  
    //! brief Timeput bei dem fertig gesendetes Frame erkannt wird
    #define TIMEOUT_FRAME_COMPLETE			3.5
  
    //! define der Größe der Ein- und Ausgangsbuffer
    #define RXBUFFERSIZE                                255
    #define TXBUFFERSIZE                                255
  
    #define FORWARD_DATA                                TRUE
    #define SEND_TO_LOKALBUS				1
    #define RESPOND_TO_QUERY				2	
    #define MODBUS_UART_PARITY_EVEN                     'e'
    #define MODBUS_UART_PARITY_ODD                      'o'
    #define MODBUS_UART_PARITY_NONE                     'n'

    
    typedef union bword
    {
      uint16_t	        w;
      int16_t		sw;
      uint8_t		lb;
      int8_t		slb;
      uint8_t		b[2];
      int8_t		sb[2];
    } bword_t;




    typedef enum 
    { 
        ACCESS_MODE_READ_ONLY,        //Muss als erstes damit nicht initialisierte Register automatisch 0 =  READ ONLY sind
        ACCESS_MODE_READ_WRITE, 
        ACCESS_MODE_WRITE_PROTECTABLE,     
    } accessMode_t;

    typedef enum mb_error_codes_enum
    {
      MB_ERROR_NOTHING              = 0,
      MB_ERROR_TIMEOUT              = 1,
      MB_ERROR_CRC                  = 2,
      MB_ERROR_SLAVE_ADRESS         = 3,
      MB_ERROR_FUNCTION_CODE        = 4,
      MB_ERROR_BYTE_COUNT           = 5,
      MB_ERROR_START_ADRESS         = 6,
      MB_ERROR_UART_PE              = 7,                        //Parity 
      MB_ERROR_UART_NE              = 8,                        //Noise
      MB_ERROR_UART_FE              = 9,                        //Frame
      MB_ERROR_UART_ORE             = 10,                       //Overrun
    } 
    mb_error_codes_t;



    typedef enum
    {
      MB_QUERY_NOTHING,
      MB_QUERY_READ_IDENT,
      MB_QUERY_READ_DATA,
      MB_QUERY_READ_LIPRO_DATA,
      MB_QUERY_WRITE_LIPRO_BALANCER_VOLTAGE, 
      MB_QUERY_WRITE_BUTTONS,
      MB_QUERY_GSM_GATEWAY,
      MB_QUERY_REMOTEBUS_GATEWAY,
      MB_QUERY_WRITE_TO_GC,
      MB_QUERY_SEND_DEVICE_ADDRESS,
      MB_QUERY_SEND_SAVE_COMMAND,
      MB_QUERY_GATEWAY,
      MB_QUERY_SEND_DATA
    } 
    mb_status_t;


    typedef struct
    {
      //TIM_HandleTypeDef             * timer;                                  //  Timer config
      //TIM_OC_InitTypeDef            * timerOcConfig;                          //  Zeiger auf TimerInit Struktur
      UART_HandleTypeDef            * uart;                                   //  Zeiger auf das Uart Modul
      GPIO_TypeDef *                driverEnableGPIO;                       //  Zuständiger einschalt Port
      uint16_t                      driverEnableGPIOPin;                    //  Zuständiger einschalt Pin
      uint32_t                      mb_t15_total_timer_ticks;               //  max timeout zwischen einzelnen char
      uint32_t                      mb_t35_total_timer_ticks;               //  timeout frame complete
      volatile bool                 mb_rx_frame_complete;                   //  frame complete ja/nein
      uint32_t                      response_timeout_counter;               //  antwort Timeout
                                                                            //  QUERY (Anfrage):
      uint8_t                       last_query_slave_adress;                //  zugehörige Slave Andresse
      uint8_t                       last_query_function_code;               //  function Code
      bword_t                       last_query_start_adress;                //  start Adresse
      bword_t                       last_query_number_of_register;          //  Anzahl der Register
      bool                          last_query_timeout;                     //  Timeout
      bword_t                       last_query_tcp_id;                      //  stack ID
      mb_status_t                   current_query;                          //  Zeiger auf Statusstruktur
      uint8_t                       rx_buffer[RXBUFFERSIZE];                //  Bufferarray Empfangen
      uint8_t                       tx_buffer[TXBUFFERSIZE];                //  Bufferarray Senden
      uint32_t                      rx_head;                                //  
      uint32_t                      tx_head;                                //  
      volatile bool                 setTxLed;                               //  status Led
      volatile bool                 setRxLed;                               //  status Led
      accessMode_t*                 accessModeTable;
      uint16_t*                     currentAccessState;
    } 
    modbus_t;



    //Public Functions Modbus
  
                          // Timer Interrupt erkennt Fehler bei Framekomplettierung
    void                  mbTimerIsr                                  (modbus_t * mb_data);
                          // Initialiserung des Moduls muss mit den passenden Parametern gefüllt werden
   void mbInit(modbus_t * mb_data, uint32_t baudrate, uint32_t parityMode, UART_HandleTypeDef * usart,  accessMode_t * accessModeTable, uint16_t * currentAccessState );
                          // überprüft ob ein Frame komplett ist
    bool                  mbGetFrameComplete                          (modbus_t * mb_data);
                        
    void                  mbClearRxFrame                              (modbus_t * mb_data);
                          // handelt den Interrupt
    void                  mbUartIsr                                   (modbus_t* mb_data);


    //Public Fuctions Modbus SLAVE
  
                          // Umgang mit ankommenden Anfragen und Verarbeitung dieser
    void                  mbSlaveProcessRtuQuery                      (modbus_t * mb_data);
                          // Bedeutung der Anfrage und wie mit dieser umgegangen werden soll
    uint32_t              mbSlaveCheckModbusRtuQuery                  (modbus_t * mb_data);
    //                    Verarbeite eine Anfrage
    uint32_t              mbSlaveProcessPdu(modbus_t * mb_data, uint8_t * msg, uint32_t tx_position, uint8_t deviceID);

    //Public Fuctions Modbus MASTER
    void                  mbMasterStartRtuReadHoldingRegister         (uint8_t slave_adress,  uint16_t start_adress, uint16_t number_of_registers, modbus_t * mb_data);
    bool                  mbMasterGetTimeout                          (modbus_t * mb_data);	
    void                  mbMasterCheckResponseTimeout                (modbus_t * mb_data);
    mb_error_codes_t      mbMasterCheckReadMultipleRegisterResponse   (modbus_t * mb_data) ;
    mb_error_codes_t      check_write_multiple_register_response      (modbus_t * mb_data) ;	
    void                  mb_start_rtu_write_multiple_register        (uint8_t slave_adress, uint16_t adress, uint16_t * values, uint8_t number_of_registers, modbus_t  * mb_data);
    void MODBUS_UART_IRQHandler(UART_HandleTypeDef *huart);
  #endif
#endif /* MODBUS_H_ */