/*
 * FreeModbus Libary: BARE Port
 * Copyright (C) 2006 Christian Walter <wolti@sil.at>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id$
 */

/* ----------------------- Platform includes --------------------------------*/
#include "port.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"
#include "main.h"
#include "tim.h"
#include "elog.h"
/* ----------------------- static functions ---------------------------------*/
static void prvvTIMERExpiredISR(void);

/* -----------------------    variables     ---------------------------------*/

#if MODBUS_USED_FREERTOS


/* -----------------------    variables     ---------------------------------*/
extern TIM_HandleTypeDef htim7;
TIM_HandleTypeDef *pModbusTim = &htim7;
volatile uint16_t timeout = 0;
volatile uint16_t counter = 0;
volatile uint32_t dd = 0;

/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
{
    TIM_MasterConfigTypeDef sMasterConfig;

    pModbusTim->Instance = TIM7;
    pModbusTim->Init.Prescaler = ( 2 * 50 * HAL_RCC_GetPCLK1Freq() / 1000000) - 1;
    pModbusTim->Init.CounterMode = TIM_COUNTERMODE_UP;
    pModbusTim->Init.Period = usTim1Timerout50us - 1;
    pModbusTim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    
    timeout = usTim1Timerout50us; // 赋值timeout 多少个周期

    if (HAL_TIM_Base_Init(pModbusTim) != HAL_OK)
    {
        return FALSE;
    }

    sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(pModbusTim, &sMasterConfig) != HAL_OK)
    {
        return FALSE;
    }

    /* 避免一开始进入了超时中断,关闭中断，停止计数，归0 */

    // HAL_NVIC_SetPriority(TIM7_IRQn, 5, 0);
    // HAL_NVIC_EnableIRQ(TIM7_IRQn);

	__HAL_TIM_CLEAR_FLAG( &htim7, TIM_FLAG_UPDATE );              // 先清除一下定时器的中断标记,防止使能中断后直接触发中断
    __HAL_TIM_CLEAR_IT( &htim7, TIM_IT_UPDATE );
    __HAL_TIM_ENABLE_IT(&htim7, TIM_IT_UPDATE);					// 使能定时器更新中断
    //  __HAL_TIM_DISABLE(&htim7);	

    // __HAL_TIM_CLEAR_FLAG( pModbusTim, TIM_FLAG_UPDATE );
    // __HAL_TIM_SET_COUNTER( pModbusTim, 0 );
    // __HAL_TIM_DISABLE_IT( pModbusTim,TIM_FLAG_UPDATE );
    // HAL_TIM_Base_Stop( pModbusTim );
    // __HAL_TIM_SET_COUNTER( pModbusTim, 0 );
    // HAL_TIM_Base_Stop_IT( pModbusTim );
 

    return TRUE;
}

inline void
vMBPortTimersEnable()
{
    /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
    counter = 0; // 启用定时器时， 
    
    // HAL_TIM_Base_Start_IT(pModbusTim);
    // __HAL_TIM_SET_COUNTER(pModbusTim, 0);		// 清空计数器
    // __HAL_TIM_SET_COUNTER( pModbusTim, 0 );
    // __HAL_TIM_ENABLE_IT( pModbusTim,TIM_FLAG_UPDATE );
    // HAL_TIM_Base_Start( pModbusTim );

	__HAL_TIM_CLEAR_IT(&htim7,TIM_IT_UPDATE);
		__HAL_TIM_ENABLE_IT(&htim7,TIM_IT_UPDATE);
		__HAL_TIM_SET_COUNTER(&htim7,0);
		__HAL_TIM_ENABLE(&htim7);

    // __HAL_TIM_SET_COUNTER(&htim7, 0);		// 清空计数器
    // __HAL_TIM_ENABLE(&htim7);				// 使能定时器
 

}

inline void
vMBPortTimersDisable()
{
    /* Disable any pending timers. */
    // HAL_TIM_Base_Stop_IT(pModbusTim);
    // __HAL_TIM_SET_COUNTER(pModbusTim, 0);		// 清空计数器
    
    // __HAL_TIM_SET_COUNTER( pModbusTim, 0 );
    // __HAL_TIM_DISABLE_IT( pModbusTim,TIM_FLAG_UPDATE );
    // HAL_TIM_Base_Stop( pModbusTim );
    // __HAL_TIM_SET_COUNTER( pModbusTim, 0 );

	__HAL_TIM_DISABLE(&htim7);
    __HAL_TIM_SET_COUNTER(&htim7,0);
    __HAL_TIM_DISABLE_IT(&htim7,TIM_IT_UPDATE);
    __HAL_TIM_CLEAR_IT(&htim7,TIM_IT_UPDATE);
 
    //  __HAL_TIM_DISABLE(&htim7);				// 禁能定时器
 
}

/* Create an ISR which is called whenever the timer has expired. This function
 * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
 * the timer has expired.
 */
static void prvvTIMERExpiredISR(void)
{
    (void)pxMBPortCBTimerExpired();
}


void TIM7_IRQHandler(void)
{
    if(__HAL_TIM_GET_FLAG(&htim7, TIM_FLAG_UPDATE) != RESET && __HAL_TIM_GET_IT_SOURCE(&htim7, TIM_IT_UPDATE) !=RESET)
    // if(__HAL_TIM_GET_FLAG(&htim7, TIM_FLAG_UPDATE))			// 更新中断标记被置位
    {
        dd++;
        __HAL_TIM_CLEAR_FLAG(&htim7, TIM_FLAG_UPDATE);		// 清除中断标记
        __HAL_TIM_CLEAR_IT(&htim7,TIM_IT_UPDATE);
        __HAL_TIM_SET_COUNTER(&htim7, 0);
            prvvTIMERExpiredISR();								// 通知modbus3.5个字符等待时间到
    }
    HAL_TIM_IRQHandler( &htim7 );
}
  
 
#else

 
#include <FreeRTOS.h>
// #include <timers.h>
/* ----------------------- static functions ---------------------------------*/
osTimerId_t modbusTimerHandle;
const osTimerAttr_t modbusTimer_attributes = {
  .name = "modbusTimer"
};

// static TimerHandle_t timer;

volatile uint32_t timer_ticks = 0;
volatile uint32_t dd = 0;

static void prvvTIMERExpiredISR( void );
static void timer_timeout_ind( void* parameter );

/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortTimersInit( USHORT usTim1Timerout50us ) {
  /*
  Freertos can't create timer in isr!  预先创建定时器？ 先初始化好？
  So,I use hardware timer here!  req=1Mhz
  */
  timer_ticks = (50 * usTim1Timerout50us) / (1000  * 1000 / configTICK_RATE_HZ) + 1;
  modbusTimerHandle = osTimerNew(
      timer_timeout_ind, 
      osTimerOnce,   // osTimerOnce   osTimerPeriodic
      NULL, 
      &modbusTimer_attributes );

//   modbusTimerHandle = xTimerCreate(
//       "Slave timer",
//       (50 * usTim1Timerout50us) / (1000 * 1000 / configTICK_RATE_HZ) + 1,
//       pdFALSE, (void *)2, timer_timeout_ind);

  if (modbusTimerHandle == NULL)
    return FALSE;

  // osTimerStart( modbusTimerHandle, (50 * usTim1Timerout50us) / (1000 * 1000 / configTICK_RATE_HZ) + 1);
  return TRUE;
}

void vMBPortTimersEnable() {
    // log_i(" enable timer...... %d", timer_ticks );
    osTimerStart( modbusTimerHandle, timer_ticks );
    if( osTimerIsRunning(modbusTimerHandle) !=) 
    {
         log_i("   timer running... %d", timer_ticks );

    }
    // osTimerStart  已经包含   (IS_IRQ() 
}

void vMBPortTimersDisable() {
    // log_i(" disbale timer......  " );
    osTimerStop(modbusTimerHandle);
    // osTimerStop  已经包含   (IS_IRQ() 

}

void prvvTIMERExpiredISR(void) 
{ 
    (void)pxMBPortCBTimerExpired(); 
}

static void timer_timeout_ind( void* parameter ) 
{
    dd++;
    // log_i( "  timer  timout......  " );
    prvvTIMERExpiredISR( );
}

#endif



#if 0
 
/* -----------------------    variables     ---------------------------------*/
extern TIM_HandleTypeDef htim7;
TIM_HandleTypeDef *pModbusTim = &htim7;
volatile uint16_t timeout = 0;
volatile uint16_t counter = 0;
volatile uint32_t dd = 0;

/* ----------------------- Start implementation -----------------------------*/
BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
{
    TIM_MasterConfigTypeDef sMasterConfig;

    pModbusTim->Instance = TIM7;
    pModbusTim->Init.Prescaler = ( 2 * 50 * HAL_RCC_GetPCLK1Freq() / 1000000) - 1;
    pModbusTim->Init.CounterMode = TIM_COUNTERMODE_UP;
    pModbusTim->Init.Period = usTim1Timerout50us - 1;
    pModbusTim->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    
    timeout = usTim1Timerout50us; // 赋值timeout 多少个周期

    if (HAL_TIM_Base_Init(pModbusTim) != HAL_OK)
    {
        return FALSE;
    }

    sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(pModbusTim, &sMasterConfig) != HAL_OK)
    {
        return FALSE;
    }

    /* 避免一开始进入了超时中断,关闭中断，停止计数，归0 */

    // HAL_NVIC_SetPriority(TIM7_IRQn, 5, 0);
    // HAL_NVIC_EnableIRQ(TIM7_IRQn);

	__HAL_TIM_CLEAR_FLAG( &htim7, TIM_FLAG_UPDATE );              // 先清除一下定时器的中断标记,防止使能中断后直接触发中断
    __HAL_TIM_CLEAR_IT( &htim7, TIM_IT_UPDATE );
    __HAL_TIM_ENABLE_IT(&htim7, TIM_IT_UPDATE);					// 使能定时器更新中断
    //  __HAL_TIM_DISABLE(&htim7);	

    // __HAL_TIM_CLEAR_FLAG( pModbusTim, TIM_FLAG_UPDATE );
    // __HAL_TIM_SET_COUNTER( pModbusTim, 0 );
    // __HAL_TIM_DISABLE_IT( pModbusTim,TIM_FLAG_UPDATE );
    // HAL_TIM_Base_Stop( pModbusTim );
    // __HAL_TIM_SET_COUNTER( pModbusTim, 0 );
    // HAL_TIM_Base_Stop_IT( pModbusTim );
 

    return TRUE;
}

inline void
vMBPortTimersEnable()
{
    /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
    counter = 0; // 启用定时器时， 
    
    // HAL_TIM_Base_Start_IT(pModbusTim);
    // __HAL_TIM_SET_COUNTER(pModbusTim, 0);		// 清空计数器
    // __HAL_TIM_SET_COUNTER( pModbusTim, 0 );
    // __HAL_TIM_ENABLE_IT( pModbusTim,TIM_FLAG_UPDATE );
    // HAL_TIM_Base_Start( pModbusTim );

	__HAL_TIM_CLEAR_IT(&htim7,TIM_IT_UPDATE);
		__HAL_TIM_ENABLE_IT(&htim7,TIM_IT_UPDATE);
		__HAL_TIM_SET_COUNTER(&htim7,0);
		__HAL_TIM_ENABLE(&htim7);

    // __HAL_TIM_SET_COUNTER(&htim7, 0);		// 清空计数器
    // __HAL_TIM_ENABLE(&htim7);				// 使能定时器
 

}

inline void
vMBPortTimersDisable()
{
    /* Disable any pending timers. */
    // HAL_TIM_Base_Stop_IT(pModbusTim);
    // __HAL_TIM_SET_COUNTER(pModbusTim, 0);		// 清空计数器
    
    // __HAL_TIM_SET_COUNTER( pModbusTim, 0 );
    // __HAL_TIM_DISABLE_IT( pModbusTim,TIM_FLAG_UPDATE );
    // HAL_TIM_Base_Stop( pModbusTim );
    // __HAL_TIM_SET_COUNTER( pModbusTim, 0 );

	__HAL_TIM_DISABLE(&htim7);
    __HAL_TIM_SET_COUNTER(&htim7,0);
    __HAL_TIM_DISABLE_IT(&htim7,TIM_IT_UPDATE);
    __HAL_TIM_CLEAR_IT(&htim7,TIM_IT_UPDATE);
 
    //  __HAL_TIM_DISABLE(&htim7);				// 禁能定时器
 
}

/* Create an ISR which is called whenever the timer has expired. This function
 * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
 * the timer has expired.
 */
static void prvvTIMERExpiredISR(void)
{
    (void)pxMBPortCBTimerExpired();
}


void TIM7_IRQHandler(void)
{
    // if(__HAL_TIM_GET_FLAG(&htim7, TIM_FLAG_UPDATE) != RESET && __HAL_TIM_GET_IT_SOURCE(&htim7, TIM_IT_UPDATE) !=RESET)
    if(__HAL_TIM_GET_FLAG(&htim7, TIM_FLAG_UPDATE))			// 更新中断标记被置位
    {
        dd++;
        __HAL_TIM_CLEAR_FLAG(&htim7, TIM_FLAG_UPDATE);		// 清除中断标记
        __HAL_TIM_CLEAR_IT(&htim7,TIM_IT_UPDATE);
        __HAL_TIM_SET_COUNTER(&htim7, 0);
            prvvTIMERExpiredISR();								// 通知modbus3.5个字符等待时间到
    }
    HAL_TIM_IRQHandler( &htim7 );
}
 

#endif