/**
*******************************************************************************
* @file modbus_inputregs.c
* @brief Реализация работы с входными регистрами Modbus
*******************************************************************************
* @details
Модуль для доступа к регистрам внутри программы:
- Функции для доступа к входным регистрам по глобальным адресам

Модуль обработки команды чтения input registers (0x04):

@section ivalid Валидация данных:
- Проверка соответствия количества байт и регистров
- Валидация адресов через MB_DefineRegistersAddress()
- Обработка исключений при некорректных запросах
******************************************************************************/
#include "modbus_inputregs.h"


#ifdef MODBUS_ENABLE_INPUTS


/** 
  * @brief    Записать входной регистр по глобальному адресу.
  * @param    Addr          Адрес регистра.
  * @param    WriteVal      Число для записи.
  * @return   ExceptionCode Код исключения если регистра по адресу не существует, и ET_NO_ERRORS если все ок.
  *
  * @details  Позволяет обратиться к любому регистру по его глобальному адрессу.
              Вне зависимости от того как регистры размещены в памяти.
  */
MB_ExceptionTypeDef MB_Input_Write_Global(uint16_t Addr, uint16_t WriteVal)
{
  //---------CHECK FOR ERRORS----------
  MB_ExceptionTypeDef Exception = ET_NO_ERRORS;
  uint16_t *pInRegs;
  
  //------------WRITE COIL-------------
  Exception = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input, 1);
  if(Exception == ET_NO_ERRORS)
  {
    *(pInRegs) = WriteVal;
  }
  return Exception;
}


/** 
  * @brief    Считать входной регистр по глобальному адресу.
  * @param    Addr          Адрес регистра.
  * @param    Exception     Указатель на переменную для кода исключения, в случае неудачи при чтении.
  * @return   uint16_t      Возвращает значение регистра.
  *
  * @details  Позволяет обратиться к любому регистру по его глобальному адрессу.
              Вне зависимости от того как регистры размещены в памяти.
  */
uint16_t MB_Input_Read_Global(uint16_t Addr, MB_ExceptionTypeDef *Exception)
{
  //---------CHECK FOR ERRORS----------
  MB_ExceptionTypeDef Exception_tmp = 0;
    
  uint16_t *pInRegs;
  
  //------------READ COIL--------------
  Exception_tmp = MB_DefineRegistersAddress(&pInRegs, Addr, 1, RegisterType_Input, 0);

  if(Exception)             // if exception is not given to func fill it
    *Exception = Exception_tmp;

  if(Exception_tmp == ET_NO_ERRORS)
  {
    return *(pInRegs);
  }
  else
  {
    return 0;
  }
}


/**
  * @brief    Обработать функцию Read Input Registers (04 - 0x04).
  * @param    modbus_msg        Указатель на структуру собщения modbus.
  * @return   fMessageHandled   Статус о результате обработки комманды.
  * @details  Обработка команды Read Input Registers.
  */
uint8_t MB_Process_Read_Input_Regs(RS_MsgTypeDef *modbus_msg)
{
  //---------CHECK FOR ERRORS---------- 
  // get origin address for data
  uint16_t *pInRegs;      
  modbus_msg->Except_Code = MB_DefineRegistersAddress(&pInRegs, modbus_msg->Addr, modbus_msg->Qnt, RegisterType_Input, 0); // определение адреса регистров
  if(modbus_msg->Except_Code != ET_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++)
  {
    if(*((int16_t *)pInRegs) > 0)
      modbus_msg->MbData[i] = (*pInRegs++);
    else
      modbus_msg->MbData[i] = (*pInRegs++);
  } 
  return 1;
}

#endif //MODBUS_ENABLE_INPUTS
