/**
******************************************************************************
* @file modbus_holdregs.c
* @brief Реализация работы с регистрами хранения Modbus
******************************************************************************
* @details
Модуль обработки команд для holding registers (регистров хранения):
- Чтение множественных регистров (0x03) - копирование данных в буфер ответа
- Запись одиночного регистра (0x06) - прямая запись значения
- Запись множественных регистров (0x10) - пакетная запись из буфера

@section  Валидация данных:
- Проверка соответствия количества байт и регистров
Валидация адресов через MB_DefineRegistersAddress()
- Обработка исключений при некорректных запросах

@section  Echo-ответы:
При успешной записи формируется echo-ответ с теми же данными,
что были в запросе (для функций 0x05, 0x06, 0x0F, 0x10).
******************************************************************************/
#include "modbus_inputregs.h"


#ifdef MODBUS_ENABLE_HOLDINGS


/**
  * @brief    Обработать функцию Read Holding Registers (03 - 0x03).
  * @param    modbus_msg        Указатель на структуру собщения modbus.
  * @return   fMessageHandled   Статус о результате обработки комманды.
  * @details  Обработка команды Read Holding Registers.
  */
uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg)
{
  //---------CHECK FOR ERRORS---------- 
  // get origin address for data
  uint16_t *pHoldRegs;      
  modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров
  if(modbus_msg->Except_Code != NO_ERRORS)
    return 0;
  

  //-----------READING REGS------------
  // setup output message data size 
  modbus_msg->ByteCnt = modbus_msg->Qnt*2; // *2 because we transmit 8 bits, not 16 bits
  // read data
  int i;
  for (i = 0; i<modbus_msg->Qnt; i++)
  {
    modbus_msg->DATA[i] = *(pHoldRegs++);
  } 
  return 1;
}

/**
  * @brief    Обработать функцию Write Single Register (06 - 0x06).
  * @param    modbus_msg        Указатель на структуру собщения modbus.
  * @return   fMessageHandled   Статус о результате обработки комманды.
  * @details  Обработка команды Write Single Register.
  */
uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg)
{ 
  // get origin address for data
  uint16_t *pHoldRegs;      
  modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, 1, RegisterType_Holding); // определение адреса регистров
  if(modbus_msg->Except_Code != NO_ERRORS)
    return 0;
  
  //-----------WRITTING REG------------ 
  *(pHoldRegs) = modbus_msg->Qnt;
  return 1;
}

/**
  * @brief    Обработать функцию Write Multiple Registers (16 - 0x10).
  * @param    modbus_msg        Указатель на структуру собщения modbus.
  * @return   fMessageHandled   Статус о результате обработки комманды.
  * @details  Обработка команды Write Multiple Registers.
  */
uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg)
{
  //---------CHECK FOR ERRORS----------
  if (modbus_msg->Qnt*2 != modbus_msg->ByteCnt)
  { // if quantity and bytes count arent match
    modbus_msg->Except_Code = 3;
    return 0;
  } 
  // get origin address for data
  uint16_t *pHoldRegs;      
  modbus_msg->Except_Code = MB_DefineRegistersAddress(&pHoldRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Holding); // определение адреса регистров
  if(modbus_msg->Except_Code != NO_ERRORS)
    return 0;
  
  //-----------WRITTING REGS----------- 
  for (int i = 0; i<modbus_msg->Qnt; i++)
  {
    *(pHoldRegs++) = modbus_msg->DATA[i];
  }
  return 1;
}


#else //MODBUS_ENABLE_HOLDINGS

uint8_t MB_Process_Read_Hold_Regs(RS_MsgTypeDef *modbus_msg) {return 0;}
uint8_t MB_Process_Write_Single_Reg(RS_MsgTypeDef *modbus_msg) {return 0;}
uint8_t MB_Process_Write_Miltuple_Regs(RS_MsgTypeDef *modbus_msg) {return 0;}

#endif