/*****************************************************************************
 * file    lib/management/mtimer.c
 * author  Yuliang
 * version 1.0.0
 * date    22-Sep-2021
 * brief   This file provides all the timer related operation functions.
 ******************************************************************************
 * Attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2021 LandPower</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of LandPower nor the names of its contributors may be used to 
 *      endorse or promote products derived from this software without specific
 *      prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <sys/time.h>
#include <pthread.h>
#include <signal.h>

#include "array.h"
#include "mtimer.h"
#include "cmd.h"

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
static pthread_t mtimer_pid;
static array_t *mtimer_array;
static pthread_mutex_t mtimer_mutex;

/* Private function prototypes -----------------------------------------------*/
extern void _mtimer_lock(void);
extern void _mtimer_unlock(void);

/* 485设备显示. */
CMD(mtime_show, 
    mtime_show_cmd,
    "show mtime",
    SHOW_STR
    "mtime\n")
{    
    mtimer_t *entry = NULL;
    uint32_t i = 0;
    
    /* 遍历所有外设 */
    _mtimer_lock();
    vty_out(vty, "ID %-32s INR%s", "NAME", VTY_NEWLINE);
    for (i = 0; i < array_active(mtimer_array); i++)
    {
        entry = array_lookup(mtimer_array, i);
        if (NULL == entry)
        {
            continue;
        }

        vty_out(vty, "%-02d %-32s %d%s", i, entry->name, entry->interval, VTY_NEWLINE);
    }

    _mtimer_unlock();
    return CMD_SUCCESS;
}

/* Internal functions --------------------------------------------------------*/
void _mtimer_lock(void)
{
    pthread_mutex_lock(&mtimer_mutex);
}

void _mtimer_unlock(void)
{
    pthread_mutex_unlock(&mtimer_mutex);
}

/* 定时器线程. */
void *_mtimer_process(void *arg)
{    
    uint32_t i = 0;
    uint32_t t = 0;
    mtimer_t *entry = NULL;
    
    while(1)
    {
        /* 最小粒度1s */
        sleep(1);

        /* 遍历所有定时器 */
        _mtimer_lock();
        t = time(NULL);
        for (i = 0; i < array_active(mtimer_array); i++)
        {
            entry = array_lookup(mtimer_array, i);
            if (NULL == entry)
            {
                continue;
            }
            
            /* 判断时间有没有到 */
            if (abs(t - entry->time) < entry->interval)
            {
                continue;
            }

            /* 调用回调函数 */
            entry->handle(entry->arg);
                        
            /* 删除定时器 */
            array_unset(mtimer_array, i);
            XFREE(MTYPE_MTIMER, entry);
        }
        _mtimer_unlock();
    }

    return NULL;
}

/* Interface functions -------------------------------------------------------*/
/* description: 添加定时器.
   param:
   return:  (E_NONE)成功,(其他)失败 */
int32_t mtimer_add(MTIMER_CALLBACK func, void *arg, uint16_t interval, char *name)
{
    mtimer_t *timer = NULL;

    _mtimer_lock();
    timer = XMALLOC(MTYPE_MTIMER, sizeof(mtimer_t));
    if (NULL == timer)
    {
        DBG(DBG_M_MTIMER, "Malloc error!\r\n");
        _mtimer_unlock();
        return E_MEM;
    }

    timer->handle = func;
    timer->arg = arg;
    snprintf(timer->name, DEV_NAME_STR_LEN, "%s", name);
    timer->interval = interval;
    timer->time = time(NULL);
    array_append(mtimer_array, timer, MTYPE_MTIMER);

    _mtimer_unlock();
    return E_NONE;
}

/* description: 删除定时器.
   param:
   return:  (E_NONE)成功,(其他)失败 */
int32_t mtimer_del(MTIMER_CALLBACK func, void *arg)
{
    uint32_t i = 0;
    mtimer_t *entry = NULL;

    _mtimer_lock();
    /* 遍历数组 */
    for (i = 0; i < array_active(mtimer_array); i++)
    {
        entry = array_lookup(mtimer_array, i);
        if (NULL == entry)
        {
            continue;
        }

        /* 比较数据 */
        if (entry->handle == func && entry->arg == arg)
        {
            /* 删除定时器 */
            array_unset(mtimer_array, i);
            XFREE(MTYPE_MTIMER, entry);
        }
    }
    
    _mtimer_unlock();
    return E_NONE;
}

/* description: 定时器初始化.
   param:
   return:  (E_NONE)成功,(其他)失败 */
int32_t mtimer_init(void)
{
    struct sched_param param;
    pthread_attr_t attr;
    pthread_mutexattr_t attr_m;

    /* 初始化用户列表 */
    mtimer_array = array_init(16, MTYPE_MTIMER);

    /* 递归锁 */
    pthread_mutexattr_init(&attr_m);
    pthread_mutexattr_settype(&attr_m, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&mtimer_mutex, &attr_m);

    /* 配置线程RR调度,优先级50 */
    pthread_attr_init(&attr);
    param.sched_priority = 50;
    pthread_attr_setschedpolicy(&attr, SCHED_RR);
    pthread_attr_setschedparam(&attr, &param);
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

    /* 创建接收数据线程. */
    if (pthread_create(&mtimer_pid, &attr, _mtimer_process, NULL) != 0)
    {
        log_err(LOG_DEFAULT, "mtimer_init can't create pthread!");
    }
    else
    {
        thread_m_add("TIMER", mtimer_pid);
    }
    pthread_attr_destroy(&attr);

    cmd_install_element(COMMON_NODE, &mtime_show_cmd);

    return E_NONE;
}
/************************ (C) COPYRIGHT LandPower ***** END OF FILE ****/
