#pragma once
#ifndef __MODBUS__H_
#define __MODBUS__H_

#ifdef __cplusplus
extern "C" {
#endif

#include "Arduino.h"

#define MB_ID 0xAA

/* ----------------------- Defines ------------------------------------------*/
#define MB_SER_PDU_SIZE_MIN     4       /*!< Minimum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_MAX     256     /*!< Maximum size of a Modbus RTU frame. */
#define MB_SER_PDU_SIZE_CRC     2       /*!< Size of CRC field in PDU. */
#define MB_SER_PDU_ADDR_OFF     0       /*!< Offset of slave address in Ser-PDU. */
#define MB_SER_PDU_PDU_OFF      1       /*!< Offset of Modbus-PDU in Ser-PDU. */

#define MB_ADDRESS_BROADCAST    ( 0 )   /*! Modbus broadcast address. */
#define MB_ADDRESS_MIN          ( 1 )   /*! Smallest possible slave address. */
#define MB_ADDRESS_MAX          ( 247 ) /*! Biggest possible slave address. */

#define MB_FUNC_NONE                          (  0 )
#define MB_FUNC_READ_COILS                    (  1 )
#define MB_FUNC_READ_DISCRETE_INPUTS          (  2 )
#define MB_FUNC_WRITE_SINGLE_COIL             (  5 )
#define MB_FUNC_WRITE_MULTIPLE_COILS          ( 15 )
#define MB_FUNC_READ_HOLDING_REGISTER         (  3 )
#define MB_FUNC_READ_INPUT_REGISTER           (  4 )
#define MB_FUNC_WRITE_REGISTER                (  6 )
#define MB_FUNC_WRITE_MULTIPLE_REGISTERS      ( 16 )
#define MB_FUNC_READWRITE_MULTIPLE_REGISTERS  ( 23 )
#define MB_FUNC_DIAG_READ_EXCEPTION           (  7 )
#define MB_FUNC_DIAG_DIAGNOSTIC               (  8 )
#define MB_FUNC_DIAG_GET_COM_EVENT_CNT        ( 11 )
#define MB_FUNC_DIAG_GET_COM_EVENT_LOG        ( 12 )
#define MB_FUNC_OTHER_REPORT_SLAVEID          ( 17 )
#define MB_FUNC_ERROR                         ( 128 )

enum MB_FC {
  MB_FC_NONE = 0,                     /*!< null operator */
  MB_FC_READ_COILS = 1,	              /*!< FCT=1 -> read coils or digital outputs */
  MB_FC_READ_DISCRETE_INPUT = 2,	    /*!< FCT=2 -> read digital inputs */
  MB_FC_READ_REGISTERS = 3,	          /*!< FCT=3 -> read registers or analog outputs */
  MB_FC_READ_INPUT_REGISTER = 4,	    /*!< FCT=4 -> read analog inputs */
  MB_FC_WRITE_COIL = 5,	              /*!< FCT=5 -> write single coil or output */
  MB_FC_WRITE_REGISTER = 6,	          /*!< FCT=6 -> write single register */
  MB_FC_WRITE_MULTIPLE_COILS = 15,	  /*!< FCT=15 -> write multiple coils or outputs */
  MB_FC_WRITE_MULTIPLE_REGISTERS = 16	/*!< FCT=16 -> write multiple registers */
};

enum MB_STATUS {
  MB_OK = 0,
  MB_FRAME = -1,
  MB_BUFF_OVERFLOW = -2,
  MB_CRC_ERROR = -3,
};

typedef enum {
  MB_ENOERR,                  /*!< no error. */
  MB_ENOREG,                  /*!< illegal register address. */
  MB_EINVAL,                  /*!< illegal argument. */
  MB_EPORTERR,                /*!< porting layer error. */
  MB_ENORES,                  /*!< insufficient resources. */
  MB_EIO,                     /*!< I/O error. */
  MB_EILLSTATE,               /*!< protocol stack in illegal state. */
  MB_ETIMEDOUT                /*!< timeout error occurred. */
} eMBErrorCode;

void mb_put_rec_data(uint8_t data);
void mb_init(uint8_t id, uint32_t boudrate, volatile uint32_t * time_base);
void mb_poll();
void mb_send_frame(uint8_t *frame, uint16_t length);

__attribute__((weak)) void mb_send_one_byte(uint8_t data);
__attribute__((weak)) void mb_get_frame_cb(uint8_t rcvAddress, uint8_t *frame, uint16_t length);
__attribute__((weak)) void mb_get_frame_error_cb(eMBErrorCode);

#ifdef __cplusplus
}
#endif

#endif