/*  plc hle utils project {{{
 *
 * Copyright (C) 2018 MStar Semiconductor
 *
 * <<<Licence>>>
 *
 * }}} */

#include "timer.h"

const int attenuation_group = 58;


void sleep_ms (int milliseconds)
{
    struct timespec ts;
    ts.tv_sec = milliseconds / 1000;
    ts.tv_nsec = (milliseconds % 1000) * 1000000;
    nanosleep (&ts, NULL);
}


char* current_time (void)
{
    static char timebuff[128];
    struct timeval  tv;
    struct timezone tz;
    struct tm tmp;
    struct tm *tm = &tmp;

    gettimeofday (&tv, &tz);
    localtime_r(&tv.tv_sec, &tmp);
    // tv.tv_sec += tmp.tm_gmtoff;
    // tm = localtime (&tv.tv_sec);

    sprintf(timebuff, " %02d:%02d:%02d %ld.%ldms ", tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec / 1000, tv.tv_usec % 1000);
    return timebuff;

    // tv_usec is microsecond
    // LOG_PRINT (LOG_VERBOSE, " %02d:%02d:%02d %ld.%ldms \n", tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec / 1000, tv.tv_usec % 1000);
}


void cm_atten_char_ind_send (void *opened_interface, pev_item *pev)
{
    mme_ctx_t ind_ctx;
    uint8_t send_buff[ETH_DATA_LEN];
    uint32_t buff_len = 0;
    mme_error_t result;
    int i;

    mme_init (&ind_ctx, CM_ATTEN_CHAR_IND, send_buff, ETH_DATA_LEN);

    atten_char_ind atten_ind =
    {
        .application_type = 0,
        .security_type = 0,
        .ACVarField.num_sounds = pev->receive_sounds,
        .ACVarField.ATTEN_PROFILE.num_groups = attenuation_group
    };
    memcpy (atten_ind.ACVarField.source_address, pev->mac, sizeof (pev->mac));
    memcpy (atten_ind.ACVarField.run_id, pev->run_id, sizeof (pev->run_id));
    for (i = 0; i < attenuation_group; i++)
    {
        atten_ind.ACVarField.ATTEN_PROFILE.AAG[i] = pev->AAG[i] / pev->receive_sounds;
    }

    mme_put (&ind_ctx, &atten_ind, sizeof (atten_ind), &buff_len);

    LOG_PRINT (LOG_INFO, "[EVSE] sends CM_ATTEN_CHAR.IND\n");
    result = mme_send (opened_interface, &ind_ctx, MME_SEND_IND_RSP, pev->mac);
    if (result != MME_SUCCESS)
    {
        LOG_PRINT (LOG_VERBOSE, "mme_send() error, result = %d\n", result);
    }
}



/**
 * The following handler are called by PEV.
 */
static void sent_cm_slac_parm_req_handler (int sig, siginfo_t *si, void *uc)
{

    pev *pev = si->si_value.sival_ptr;
    if (DEBUG_DISPLAY)
    {
        LOG_PRINT (LOG_VERBOSE, "CM_SLAC_PARM_REQ Timer stop at %s\n", current_time());
    }
    pev->cm_slac_parm_timer_flag = 0;
}

static void received_cm_atten_char_ind_handler (int sig, siginfo_t *si, void *uc)
{
    pev *pev = si->si_value.sival_ptr;
    if (DEBUG_DISPLAY)
    {
        LOG_PRINT (LOG_VERBOSE, "CM_START_ATTEN_CHAR.IND Timer stop at %s", current_time());
    }
    pev->cm_start_atten_char_timer_flag = 0;
}

/**
 * The following handler are called by EVSE.
 */
static void received_cm_start_atten_char_ind_handler (int sig, siginfo_t *si, void *uc)
{
    pev_item *pev = si->si_value.sival_ptr;
    if (DEBUG_DISPLAY)
    {
        LOG_PRINT (LOG_VERBOSE, "received_CM_START_ATTEN_CHAR_IND_Handler stop at %s", current_time());
    }

    if (pev->matching_state == RECEIVED_CM_START_ATTEN_CHAR_IND)
    {
        pev->matching_state = SENT_CM_ATTEN_CHAR_IND;
        // Need to send CM_ATTEN_CHAR.IND
        cm_atten_char_ind_send (pev->iface, pev);
    }

    pev->cm_start_atten_char_ind_timer_retry--;
    if (pev->cm_start_atten_char_ind_timer_retry<=0)
    {
        if (timer_delete (pev->cm_start_atten_char_ind_timer_id) == 0)
        {
            LOG_PRINT (LOG_VERBOSE, "Delete CM_START_ATTEN_CHAR_IND_TIMER successfully.\n");
        }
        else
        {
            LOG_PRINT (LOG_VERBOSE, "CM_START_ATTEN_CHAR_IND_TIMER was already deleted.\n");
        }
    }


}

static void sent_cm_slac_match_cnf_handler (int sig, siginfo_t *si, void *uc)
{

    pev_item *pev = si->si_value.sival_ptr;

    LOG_PRINT (LOG_VERBOSE, "received_cm_slac_match_cnf_handler stop at %s", current_time());

    vs_get_status_req_send(pev->iface);
}

int make_pev_timer(pev *pev_status, int expire_ms, int interval_ms)
{
    // first expire time
    // [Notice: tv_nsec cannot exceed one second]
    int expire_sec = expire_ms / 1000;
    int expire_msec = expire_ms % 1000;

    // the period of timer
    int interval_sec = interval_ms / 1000;
    int interval_msec = interval_ms % 1000;

    timer_t *timer_id;
    struct sigevent te;
    struct itimerspec its;
    struct sigaction sa;
    int sig_no = SIGRTMIN;


    /* Set up signal handler. */
    sa.sa_flags = SA_SIGINFO;

    // set the corresponding handler according to the pev.current_state
    switch (pev_status->current_state)
    {
    case 0:
        timer_id = &pev_status->cm_slac_parm_timer_id;
        sa.sa_sigaction = sent_cm_slac_parm_req_handler;
        break;
    // this case start from send CM_START_ATTEN_CHAR.IND
    case 1:
        timer_id = &pev_status->cm_start_atten_char_timer_id;
        sa.sa_sigaction = received_cm_atten_char_ind_handler;
        break;
    default:
        LOG_PRINT (LOG_VERBOSE, "Unknown current_state\n");
        return TIMER_ERROR;
    }

    sigemptyset (&sa.sa_mask);
    if (sigaction (sig_no, &sa, NULL) == -1)
    {
        LOG_PRINT (LOG_DEBUG, "Error sigaction\n");
        return TIMER_ERROR;
    }

    /* Set and enable alarm */
    te.sigev_notify = SIGEV_SIGNAL;
    te.sigev_signo = sig_no;
    te.sigev_value.sival_ptr = pev_status;
    if (timer_create(CLOCK_REALTIME, &te, timer_id) )
    {
        LOG_PRINT (LOG_DEBUG, "timer_create() error\n");
        return TIMER_ERROR;
    }

    its.it_value.tv_sec = expire_sec;
    its.it_value.tv_nsec = expire_msec * 1000000;


    its.it_interval.tv_sec = interval_sec;
    its.it_interval.tv_nsec = interval_msec * 1000000;

    if (timer_settime (*timer_id, 0, &its, NULL))
    {
        LOG_PRINT (LOG_DEBUG, "timer_settime() error\n");
        return TIMER_ERROR;
    }
    if (DEBUG_DISPLAY)
    {
        LOG_PRINT (LOG_VERBOSE, "Set the timer %p at %s, timeout:%d, interv:%d\n", *timer_id, current_time(), expire_ms, interval_ms);
    }
    return TIMER_SUCCESS;
}


int make_evse_timer(pev_item *pev, int expire_ms, int interval_ms)
{
    // first expire time
    // [Notice: tv_nsec cannot exceed one second]
    int expire_sec = expire_ms / 1000;
    int expire_msec = expire_ms % 1000;

    // the period of timer
    int interval_sec = interval_ms / 1000;
    int interval_msec = interval_ms % 1000;

    timer_t* timer_id;
    struct sigevent te;
    struct itimerspec its;
    struct sigaction sa;
    int sig_no = SIGRTMIN + 1;

    /* Set up signal handler. */
    sa.sa_flags = SA_SIGINFO | SA_RESTART;

    // set the corresponding handler according to the pev.current state
    switch (pev->matching_state)
    {
    case 1:
        timer_id = &pev->cm_start_atten_char_ind_timer_id;
        sa.sa_sigaction = received_cm_start_atten_char_ind_handler;
        break;
    case 5:
        timer_id = &pev->cm_slac_match_cnf_timer_id;
        sa.sa_sigaction = sent_cm_slac_match_cnf_handler;
        break;
    default:
        LOG_PRINT (LOG_VERBOSE, "Unknown current state\n");
        return TIMER_SUCCESS;
    }

    sigemptyset (&sa.sa_mask);
    if (sigaction (sig_no, &sa, NULL) == -1)
    {
        LOG_PRINT (LOG_DEBUG, "Error sigaction\n");
        return TIMER_ERROR;
    }

    /* Set and enable alarm */
    te.sigev_notify = SIGEV_SIGNAL;
    te.sigev_signo = sig_no;
    te.sigev_value.sival_ptr = pev;

    if (timer_create (CLOCK_REALTIME, &te, timer_id) != 0)
    {
        LOG_PRINT (LOG_DEBUG, "timer_create error\n");
        return TIMER_ERROR;
    }

    its.it_value.tv_sec = expire_sec;
    its.it_value.tv_nsec = expire_msec * 1000000;

    its.it_interval.tv_sec = interval_sec;
    its.it_interval.tv_nsec = interval_msec * 1000000;

    if (timer_settime (*timer_id, 0, &its, NULL) != 0)
    {
        LOG_PRINT (LOG_DEBUG, "timer_settime() error\n");
        return TIMER_ERROR;
    }
    if (DEBUG_DISPLAY)
    {
        LOG_PRINT (LOG_VERBOSE, "Set the timer %p at %s, timeout:%d, interv:%d", *timer_id, current_time(), expire_ms, interval_ms);
    }
    return TIMER_SUCCESS;
}

