/********************************* (C) ROTEK ***********************************
 * @module  template
 * @file    template.c
 * @version 1.0.0
 * @date    XX.XX.XXXX
 * $brief   Template
 *******************************************************************************
 * @history     Version  Author         Comment
 * XX.XX.XXXX   1.0.0    Telenkov D.A.  First release.
 *******************************************************************************
 */

#include "stm32f4xx.h"  
#include "snmp_api.h"
#include "trap_api.h"
#include "settings_api.h"
#include "common_config.h"
#include "rtc.h"
#include "megatec.h"

#ifdef PRINTF_STDLIB
#include <stdio.h>
#endif
#ifdef PRINTF_CUSTOM
#include "tinystdio.h"
#endif
#include <stdbool.h>
#include <string.h>

#include "lwip/opt.h"
#include "lwip/api.h"
#include "lwip/sys.h"
#include "lwip/udp.h"

#include "snmp.h"
#include "snmp_msg.h"
#include "private_mib.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

/**
  * @brief  Пул всех возможных трапов устройства
  */
extern TRAP_t traps[];

/**
  * @brief  Общая структура настроек
  */
extern SETTINGS_t sSettings;

/**
  * @brief  Очередь для отправки трапов
  */
QueueHandle_t    SNMP_TrapQueue;

/**
  * @brief  Инициализация параметров SNMP
  * @retval 
  */
void SNMP_Init(void)
{
  //SETTINGS_SetSnmpDef();
  SNMP_AgentInit();
}


/**
  * @brief  Системный тик SNMP. Таск должен вызываться с частотой 100Гц.
  * @retval 
  */
void SNMP_SysUpTimeTask(void *arg)
{
  TickType_t xLastWakeTime;
  const TickType_t xFrequency = 10;
  
  xLastWakeTime = xTaskGetTickCount();
  
  while(1)
  {
	vTaskDelayUntil( &xLastWakeTime, xFrequency );
    snmp_inc_sysuptime();
  }
}

/**
  * @brief  Тестовый таск для проверки отправки трапов
  * @retval 
  */
void snmp_trap_tread(void *arg)
{
  uint8_t trapName;
	
  while(1)
  {
    if (xQueueReceive(SNMP_TrapQueue, &trapName, 0) == pdTRUE)
	{
      SNMP_SetManagerIP(sSettings.sSnmp.managerIP);
	  SNMP_SendVarbindTrap(&traps[trapName]);
      
      SNMP_SetManagerIP(sSettings.sSnmp.managerIP2);
	  SNMP_SendVarbindTrap(&traps[trapName]);
      
      SNMP_SetManagerIP(sSettings.sSnmp.managerIP3);
	  SNMP_SendVarbindTrap(&traps[trapName]);

	  SNMP_SetManagerIP(sSettings.sSnmp.managerIP4);
	  SNMP_SendVarbindTrap(&traps[trapName]);

	  SNMP_SetManagerIP(sSettings.sSnmp.managerIP5);
	  SNMP_SendVarbindTrap(&traps[trapName]);
	}
  }  

}

/**
  * @brief  Инициализация SNMP агента
  * @retval 
  */
void SNMP_AgentInit(void)
{
  SNMP_SetObjDescr();
  SNMP_SetReadCommunity(sSettings.sSnmp.readCommunity);
  SNMP_SetWriteCommunity(sSettings.sSnmp.writeCommunity);
  SNMP_SetSysContact(sSettings.sSnmp.sysContact);
  SNMP_SetSysName(sSettings.sSnmp.sysName);
  SNMP_SetSysLocation(sSettings.sSnmp.sysLocation);
  SNMP_SetManagerIP(sSettings.sSnmp.managerIP);
  SNMP_SetObjID();
  SNMP_SetTrapOnOff(1);
  
  SNMP_InitTrapsBase();
	
  snmp_init();
  udp_init();
  
  SNMP_TrapQueue = xQueueCreate(SNMP_TRAP_QUEUE_SIZE, sizeof(uint8_t));
}

/**
  * @brief  Пользовательская функция для отправки трапа из массива traps[] 
  *         Трап помещается в очередь. Работа с очередью происходит по принципу
  *         FIFO буфера. 
  *         Если в настройках трапа отправка отключена, то трап игнорируется.
  * @retval 
  */
void SNMP_SendUserTrap(uint8_t trapName)
{
  uint16_t availableSpace;
  uint8_t  dummyTrap;
  
  if (traps[trapName].trapEnable)
  {	
    availableSpace = uxQueueSpacesAvailable(SNMP_TrapQueue);
  
    if (availableSpace == 0)
	  xQueueReceive(SNMP_TrapQueue, &dummyTrap, 0);
  
    xQueueSend(SNMP_TrapQueue, &trapName, 0);
  }
}

/**
  * @brief  Установить SNMP Descriptor
  * @retval 
  */
// TODO
void SNMP_SetObjDescr(void)
{
  static uint8_t len;
  
  strcpy(sSettings.sSnmp.sysDescr, sSettings.sSnmp.sysName);
  strcat(sSettings.sSnmp.sysDescr, " ");
  strcat(sSettings.sSnmp.sysDescr, VERSION);
  strcat(sSettings.sSnmp.sysDescr, " ");
  strcat(sSettings.sSnmp.sysDescr, sSettings.sSnmp.sysContact);
  strcat(sSettings.sSnmp.sysDescr, " ");
  strcat(sSettings.sSnmp.sysDescr, sSettings.sInfo.serialNumber);
  strcat(sSettings.sSnmp.sysDescr, " ");
  strcat(sSettings.sSnmp.sysDescr, UPS.model);
  
  len = strlen(sSettings.sSnmp.sysDescr);
  snmp_set_sysdesr((u8_t*)sSettings.sSnmp.sysDescr, &len);
}

/**
  * @brief  Установить SNMP Community для чтения
  */
void SNMP_SetReadCommunity(char *comm)
{
  strcpy(sSettings.sSnmp.readCommunity, comm);
}

/**
  * @brief  Установить SNMP Community для записи
  */
void SNMP_SetWriteCommunity(char *comm)
{
  strcpy(sSettings.sSnmp.writeCommunity, comm);
}

/**
  * @brief  Установить SNMP SysContact
  * @retval 
  */
void SNMP_SetSysContact(char *con)
{
  static uint8_t len;
  
  len = strlen(con);
  snmp_set_syscontact((u8_t*)con, &len);
}

/**
  * @brief  Установить SNMP SysName
  * @retval 
  */
void SNMP_SetSysName(char *name)
{
  static uint8_t len;
  
  len = strlen(name);
  snmp_set_sysname((u8_t*)name, &len);
}

/**
  * @brief  Установить SNMP SysLocation
  * @retval 
  */
void SNMP_SetSysLocation(char *loc)
{
  static uint8_t len;
  
  len = strlen(loc);
  snmp_set_syslocation((u8_t*)loc, &len);
}

/**
  * @brief  Установить SNMP SysManagerIP
  * @retval 
  */
void SNMP_SetManagerIP(char *ip)
{
  static ip_addr_t trap_addr;
  
  ipaddr_aton(ip, &trap_addr);
  snmp_trap_dst_ip_set(0, &trap_addr);
}

/**
  * @brief  Установить SNMP Object ID
  * @retval 
  */
void SNMP_SetObjID(void)
{
  static struct snmp_obj_id my_object_id = {9, {1, 3, 6, 1, 4, 1, 41752, 911, 3}};
  
  snmp_set_sysobjid(&my_object_id);
}

/**
  * @brief  Вкл/выкл трапы
  * @retval 
  */
void SNMP_SetTrapOnOff(uint8_t state)
{
  snmp_trap_dst_enable(0, (u8_t)state);
}


/********************************* (C) ROTEK **********************************/
