/**
*******************************************************************************
* @file modbus_master.h
* @brief Главный заголовочный файл Modbus библиотеки
*******************************************************************************
@addtogroup MODBUS_MASTER Modbus master funtions
@ingroup    MODBUS_CMD_PROCESS_FUNCTIONS
@brief Функции для работы в режиме Master
*******************************************************************************
* @details
Модуль реализации Modbus в режиме мастер
******************************************************************************/
#ifndef __MODBUS_MASTER_H_
#define __MODBUS_MASTER_H_ 
#include "rs_message.h"
#ifdef MODBUS_ENABLE_MASTER

/**
  * @addtogroup MODBUS_REQUEST_MSG API for Master Requests
  * @ingroup    MODBUS_FUNCTIONS
  * @brief API для формирования фрейма-запроса в режиме мастер
  * @details Примеры использования:
  * @code
  * // Чтение 10 holding registers начиная с адреса 0
  * RS_MsgTypeDef read_msg = MB_REQUEST_READ_HOLDING_REGS(1, 0, 10);
  * 
  * // Запись одного coil
  * RS_MsgTypeDef write_coil_msg = MB_REQUEST_WRITE_SINGLE_COIL(1, 5, 1);
  * 
  * // Диагностический запрос
  * RS_MsgTypeDef diag_msg = MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(1);
  * 
  * // Идентификация устройства
  * RS_MsgTypeDef dev_id_msg = MB_REQUEST_READ_DEVICE_ID_BASIC(1);
  * @endcode
  * @{
  */
  
//---------КЛАССИЧЕСКИЕ ДАННЫЕ-----------
RS_MsgTypeDef MB_REQUEST_READ_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
RS_MsgTypeDef MB_REQUEST_READ_DISCRETE_INPUTS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
RS_MsgTypeDef MB_REQUEST_READ_HOLDING_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
RS_MsgTypeDef MB_REQUEST_READ_INPUT_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity);
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_COIL(uint8_t slave_addr, uint16_t coil_addr, uint8_t value);
RS_MsgTypeDef MB_REQUEST_WRITE_SINGLE_REG(uint8_t slave_addr, uint16_t reg_addr, uint16_t value);
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_COILS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint8_t *coils_data);
RS_MsgTypeDef MB_REQUEST_WRITE_MULTIPLE_REGS(uint8_t slave_addr, uint16_t start_addr, uint16_t quantity, uint16_t *regs_data);

//---------ДИАГНОСТИЧЕСКИЕ ДАННЫЕ-----------
RS_MsgTypeDef MB_REQUEST_DIAGNOSTIC_QUERY(uint8_t slave_addr, uint16_t sub_function, uint16_t data);
RS_MsgTypeDef MB_REQUEST_RETURN_QUERY_DATA(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_RESTART_COMMUNICATIONS(uint8_t slave_addr, uint16_t data);
RS_MsgTypeDef MB_REQUEST_RETURN_DIAGNOSTIC_REGISTER(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_FORCE_LISTEN_ONLY_MODE(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_MESSAGE_COUNT(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_COMMUNICATION_ERROR_COUNT(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_EXCEPTION_ERROR_COUNT(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_MESSAGE_COUNT(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NO_RESPONSE_COUNT(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_NAK_COUNT(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_RETURN_SLAVE_BUSY_COUNT(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_RETURN_BUS_CHARACTER_OVERRUN_COUNT(uint8_t slave_addr);

//---------ИДЕНТИФИКАТОРЫ МОДБАС-----------
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_BASIC(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_REGULAR(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_EXTENDED(uint8_t slave_addr);
RS_MsgTypeDef MB_REQUEST_READ_DEVICE_ID_SPECIFIC(uint8_t slave_addr, uint8_t object_id);
/** MODBUS_REQUEST_MSG
  * @} 
  */
  
  
/**
  * @addtogroup MODBUS_REGS_API API for Registers
  * @ingroup    MODBUS_REQUEST_MSG
  * @brief API для чтения регистров из ответа в режиме мастер
  * @details Примеры использования:
  * 
  * @code
  * // Пример: Запросили 10 регистров с адреса 100, хотим получить значение регистра 105
  * uint16_t reg_value;
  * if(MB_RespGet_RegisterValue(modbus_msg, 105, &reg_value))
  * {
  *   printf("Register 105 value: %d\n", reg_value);
  * }
  * 
  * // Пример: Получить все запрошенные регистры
  * uint16_t reg_value[125];
  * MB_RespGet_RegisterAll(modbus_msg)
  * @endcode
  * @{
  */
/* Получить значение ВСЕХ регистров в ответе */
int MB_RespGet_RegisterAll(RS_MsgTypeDef *modbus_msg, uint16_t *reg_arr);
/* Получить значение регистра в ответе по его адресу */
int MB_RespGet_RegisterValue(RS_MsgTypeDef *modbus_msg, uint16_t reg_addr, uint16_t *reg_value);
  

/** MODBUS_REQ_REGS_API
  * @} 
  */


/**
  * @addtogroup MODBUS_REQ_COILS_API API for Coils  
  * @ingroup    MODBUS_REQUEST_MSG
  * @brief API для чтения coils из ответа в режиме мастер
  * @details Примеры использования:
  * 
  * @code
  * // Пример: Запросили 10 coils с адреса 20, хотим узнать состояние coil 25
  * int coil_state;
  * if(MB_RespGet_CoilState(modbus_msg, 25, &coil_state))
  * {
  *   printf("Coil 25 state: %s\n", coil_state ? "ON" : "OFF");
  * }
  * 
  * // Пример: Получить состояние всех запрошенных coils
  * for(int addr = MODBUS_MSG.Addr; addr < MODBUS_MSG.Addr + MODBUS_MSG.Qnt; addr++)
  * {
  *   int state;
  *   if(MB_RespGet_CoilState(modbus_msg, addr, &state))
  *   {
  *     printf("Coil %d: %s\n", addr, state ? "ON" : "OFF");
  *   }
  * }
  * @endcode
  * @{
  */
/* Получить состояние ВСЕХ coil в ответе */
int MB_RespGet_CoilAll(RS_MsgTypeDef *modbus_msg, int *coil_arr);
/* Получить состояние coil в ответе по его адресу */
int MB_RespGet_CoilState(RS_MsgTypeDef *modbus_msg, uint16_t coil_addr, int *coil_state);

/** MODBUS_REQ_COILS_API
  * @} 
  */
  

/**
  * @addtogroup MODBUS_REQ_DEFID_API API for Device Identifications
  * @ingroup    MODBUS_REQUEST_MSG
  * @brief API для чтения идентификторов из ответа в режиме мастер
  * @details Примеры использования:
  * 
  * @code
  * // Пример 1: Получить VendorName (ID = 0x00)
  * uint8_t length;
  * char vendor_name[64];
  * if(MB_RespGet_ObjectById(modbus_msg, 0x00, vendor_name, &length))
  * {
  *   // получено
  * }
  * 
  * // Пример 2: Перебрать все объекты в сообщении
  * uint8_t obj_id, obj_length;
  * char obj_data[256];
  * 
  * int obj_count = MB_RespGet_NumberOfObjects(modbus_msg);
  * printf("Total objects: %d\n", obj_count);
  * 
  * for(int i = 0; i < obj_count; i++)
  * {
  *   if(MB_RespGet_ObjectByIndex(modbus_msg, i, &obj_id, obj_data, &obj_length))
  *   {
  *     // получено
  *   }
  * }
  * @endcode
  * @{
  */
  
/* Получить количество объектов в сообщении */
int MB_RespGet_NumberOfObjects(RS_MsgTypeDef *modbus_msg);
/* Найти объект по ID в сообщении */
int MB_RespGet_ObjectById(RS_MsgTypeDef *modbus_msg, uint8_t obj_id, char *obj_data, uint8_t *obj_length);
/* Получить объект по индексу в сообщении */
int MB_RespGet_ObjectByIndex(RS_MsgTypeDef *modbus_msg, int index, uint8_t *obj_id, char *obj_data, uint8_t *obj_length);

    
/** MODBUS_REQ_DEFID_API
* @} 
*/
  
  

/**
  * @addtogroup MODBUS_REQ_DIAG_API API for Diagnostics
  * @ingroup    MODBUS_REQUEST_MSG  
  * @brief API для чтения диагностической информации из ответа в режиме мастер
  * @details Примеры использования:
  * 
  * @code
  * // Получить данные диагностики (значение счетчика)
  * uint16_t counter_value;
  * if(MB_RespGet_Diagnostic(modbus_msg, &counter_value))
  * {
  *   printf("Counter value: %d\n", counter_value);
  * }
  * @endcode
  * @{
  */
  
/* Получить */
int MB_RespGet_Diagnostic(RS_MsgTypeDef *modbus_msg, uint16_t *data);

/** MODBUS_REQ_DIAG_API
  * @}
  */





/**
  * @addtogroup MODBUS_MASTER
  * @{
  */

/* Сбор сообщения в буфер UART в режиме мастер (фрейм мастера из msg -> uart) */
RS_StatusTypeDef MB_Master_Collect_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff);
/* Парс сообщения в режиме мастер (фрейм слейва из uart -> msg) */
RS_StatusTypeDef MB_Master_Parse_Message(RS_HandleTypeDef *hmodbus, RS_MsgTypeDef *modbus_msg, uint8_t *modbus_uart_buff);

/** MODBUS_MASTER
  * @} 
  */

#endif //MODBUS_ENABLE_MASTER
#endif //__MODBUS_MASTER_H_
