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

#ifdef CFG_DEV_TYPE_LAND_CA
/* 标准C库头文件. */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>

/* 用户代码头文件. */
#include "cmd.h"
#include "fifo.h"
#include "common.h"
#include "ca_cau.h"
#include "serial.h"
#include "modbus.h"
#include "hwgpio.h"
#include "ca_main.h"
#include "ca_CL106d.h"
#include "ca_dbg.h"
#include "debug.h"

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

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

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

/* Private variables ---------------------------------------------------------*/
cau_t cau;
pwr_t pwr;
int cau_collect_flag = 0;

/* Private function prototypes -----------------------------------------------*/
int _pwr_read_vout(void);
int _pwr_read_vbat(void);
int _pwr_read_vsc(void);
/* Internal functions --------------------------------------------------------*/

void _cau_get_float_data(unsigned char *hex,float *val)
{
    unsigned int ivar = ((hex[0]&0xff) << 8) |((hex[1]&0xff) << 0) |((hex[2]&0xff) << 24) |((hex[3]&0xff)<<16);
    //val = (float *)&ivar;
    memcpy(val, &ivar, sizeof(float));
}

/**********************************************************************
* 函数名称:  _cau_recv
* 功能描述:
* 输入参数:
*
* 输出参数: pbuf
* 返 回 值: 0:failure 1:success
* 其它说明:
* 修改日期: 2023/12/08
***********************************************************************/
int _cau_recv(unsigned char *pkt)
{
    int len;
    len = serial_read(cau.serial_fd, pkt, MODBUS_DATA_LENGTH);
    if (len > 0 && _modbus_verify_crc(pkt, len) > 0)
    {
        return len;
    }
    return 0;
}

int _cau_set_user_param()
{
    int len;
    int ch;
    int loop;
    int slen;
    unsigned char *pkt = cau.modbus_send_buf;
    //LOG("%s:%d\n", __FUNCTION__, __LINE__);

    // cau1:0-7 use,cau2:8-15 no use,cau3:16-23 no use
    for (ch = 0; ch < MAX_CAU_CHANNEL; ch++)
    {
        cau_param_t *pparam = &pparam_config->cauParam[ch];
        len = _modbus_write_head(pkt, MB_FUNC_MULIT_WR, MB_USER_PARAM + ch * 0x10, 12);
        DBG(DBG_M_CA_CAU, "[ch%d]Range=%f,Ratio=%f,ZeroPoint=%f,ChangeThreshold=%f,HighLimit=%f,LowLimit=%f\n",
            ch, pparam->Range, pparam->Ratio, pparam->ZeroPoint, pparam->ChangeThreshold, pparam->HighLimit, pparam->LowLimit);
        _modbus_add_float(pkt + len, pparam->Range);
        len += 4;
        _modbus_add_float(pkt + len, pparam->Ratio);
        len += 4;
        _modbus_add_float(pkt + len, pparam->ZeroPoint);
        len += 4;
        _modbus_add_float(pkt + len, pparam->ChangeThreshold);
        len += 4;
        _modbus_add_float(pkt + len, pparam->HighLimit);
        len += 4;
        _modbus_add_float(pkt + len, pparam->LowLimit);
        len += 4;
        _modbus_checksum(pkt, len);
        len += 2;

        for (loop = 0; loop < 5; loop++)
        {
            serial_write(cau.serial_fd, pkt, len);
            DBG_ARRAY(DBG_M_CA_CAU, pkt, len);

            unsigned char *rxpkt = cau.modbus_recv_buf;
            if ((slen = _cau_recv(rxpkt)) > 0)
            {
                DBG_ARRAY(DBG_M_CA_CAU, rxpkt, slen);
                if (slen == 8)
                    break;
                else 
                    sleep(1);
            }
        }
        if (slen != 8)
        {
            return -1;
        }
    }
    return 0;
}

int _cau_set_user_param_ratio(Parameters_t *pbuf)
{
    int len;
    int slen;
    int ch, loop;
    unsigned char *pkt = cau.modbus_send_buf;

    for (ch = 0; ch < MAX_CAU_CHANNEL; ch++)
    {
        if (!pbuf->chClose[ch])
            continue;
        Parameter_t *param = &(pbuf->chNew[ch]);
        len = _modbus_write_head(pkt, MB_FUNC_MULIT_WR, MB_USER_PARAM + ch * 0x10, 12);
        _modbus_add_float(pkt + len, param->span);      //量程
        len += 4;
        _modbus_add_float(pkt + len, param->ratio);     //变比
        len += 4;
        _modbus_add_float(pkt + len, 0);                //零点(保留)
        len += 4;
        _modbus_add_float(pkt + len, 1000);             //突变阈值 每通道独立开
        len += 4;
        _modbus_add_float(pkt + len, 1000);             //保留
        len += 4;
        _modbus_add_float(pkt + len, 0);                //保留
        len += 4;
        _modbus_checksum(pkt, len);
        len += 2;
        DBG(DBG_M_CA_CAU, "CH%d_量程:%.2f 变比:%.2f\r\n",ch,param->span,param->ratio);

        for (loop = 0; loop < 5; loop++)
        {
            serial_write(cau.serial_fd, pkt, len);
            //print_raw_data(pkt, len);

            unsigned char *rxpkt = cau.modbus_recv_buf;
            slen = _cau_recv(rxpkt);
            if (slen != 8)
            {
                sleep(1);
                DBG(DBG_M_CA_CAU, "Send repeatedly in  %d times.\r\n", loop+1);
                continue;
            }
            break;
        }
    }
    return 0;
}

int _cau_get_user_param_ratio(Parameters_t *pbuf)
{
    int len;
    int slen;
    int ch, loop;
    unsigned char *pkt = cau.modbus_send_buf;

    for (ch = 0; ch < MAX_CAU_CHANNEL; ch++)
    {
        //if (!pbuf->chClose[ch])
        //    continue;
        len = _modbus_write_head(pkt, MB_FUNC_MULIT_RD, MB_USER_PARAM + ch * 0x10, 4);
        _modbus_checksum(pkt, len);
        len += 2;

        for (loop = 0; loop < 5; loop++)
        {
            serial_write(cau.serial_fd, pkt, len);
            print_raw_data(pkt, len);

            unsigned char *rxpkt = cau.modbus_recv_buf;
            if ((slen = _cau_recv(rxpkt)) > 0)
            {
                print_raw_data(rxpkt, slen);
                
                unsigned char *ppkt = rxpkt + 3;
                Parameter_t *param = &cau.cali_param.chOld[ch];
                _cau_get_float_data(ppkt, &param->span);
                _cau_get_float_data(ppkt+4, &param->ratio);
                DBG(DBG_M_CA_CAU, "ch%d span=%f ratio=%f\r\n", ch, param->span, param->ratio);
                break;
            }
        }
    }
    return 0;
}

int _cau_power_on()
{
    GPIO_CAU1_POWER_ON;
    sleep(5);
    return 0;
}

int _cau_power_off()
{
    GPIO_CAU1_POWER_OFF;
    return 0;
}

int _cau_parase_real_data(unsigned char *rxpkt)
{
    int ch;

    if((rxpkt[2] & 0xff) < 0x40) 
        return -1;
        
    unsigned char *ppkt = rxpkt + 3 + 0x20;
    for (ch = 0; ch < MAX_CAU_CHANNEL; ch++)
    {
        cau_real_data_t *preal = &cau.real_data;
        float val = 0;
        _cau_get_float_data(ppkt, &val);
        if(val <10.0 && val > 0.555) 
            val = val + 0.055;
        preal->tag[ch] = val;
        ppkt += 4;
        DBG(DBG_M_CA_CAU, "ch%d:%f\r\n", ch, preal->tag[ch]);
    }
    return 0;
}

int _cau_get_meas_param()
{
    int len, slen, loop;
    unsigned char *pkt = cau.modbus_send_buf;
    len = _modbus_write_head(pkt, MB_FUNC_MULIT_RD, MB_MEAS_PARAM, 0x20);
    _modbus_checksum(pkt, len);
    len += 2;

    for (loop = 0; loop < 5; loop++)
    {
        serial_write(cau.serial_fd, pkt, len);
        DBG_ARRAY(DBG_M_CA_CAU, pkt, len);
    
        unsigned char *rxpkt = cau.modbus_recv_buf;
        if ((slen = _cau_recv(rxpkt)) > 0)
        {
            DBG_ARRAY(DBG_M_CA_CAU, rxpkt, slen);
            if (slen > 68)
            {
                _cau_parase_real_data(rxpkt);
                break;
            }
            else
            {
                sleep(1);
            }
        }
        if (slen <= 68)
        {
            LOG("cau collect error!!!");
        }
    }
    return 0;
}

int _cau_get_meas_current_value()
{
    int len;
    int slen;
    unsigned char *pkt = cau.modbus_send_buf;
    len = _modbus_write_head(pkt, MB_FUNC_MULIT_RD, MB_MEAS_VALUE, 0x10);
    _modbus_checksum(pkt, len);
    len += 2;

    serial_write(cau.serial_fd, pkt, len);
    DBG_ARRAY(DBG_M_CA_CAU, pkt, len);
    
    unsigned char *rxpkt = cau.modbus_recv_buf;
    if ((slen = _cau_recv(rxpkt)) > 0)
    {
        int ch;
        DBG_ARRAY(DBG_M_CA_CAU, rxpkt, slen);
        
        unsigned char *ppkt = rxpkt + 3;
        for (ch = 0; ch < MAX_CAU_CHANNEL; ch++)
        {
            cau_real_data_t *preal = &cau.real_data;
            _cau_get_float_data(ppkt, &preal->tag[ch]);
            ppkt += 4;
            DBG(DBG_M_CA_CAU, "ch%d:%.3f\r\n", ch, preal->tag[ch]);
        }
    }
    return 0;
}

/**********************************************************************
* 函数名称:     _cau_set_channel_segment_param
* 功能描述:
* 输入参数:
*
* 输出参数: pbuf
* 返 回 值: 0:failure 1:success
* 其它说明:
* 修改日期: 2023/12/08
***********************************************************************/
int _cau_set_channel_segment_param(Parameters_t *pbuf)
{
    int ret = 0;
    int len;
    int slen;
    int ch, loop;
    unsigned char *pkt = cau.modbus_send_buf;;
    for (ch = 0; ch < MAX_CAU_CHANNEL; ch++)
    {
        int i;
        if (!pbuf->chClose[ch])
            continue;
        Parameter_t *param = &pbuf->chNew[ch];
        len = _modbus_write_head(pkt, MB_FUNC_MULIT_WR, MB_CALI_PARAM + ch *0x20 , 30);
        DBG(DBG_M_CA_CAU, "[0x%04x]\n", MB_CALI_PARAM + ch *0x20);
        for (i = 0; i < 15; i++)
        {
            DBG(DBG_M_CA_CAU, " %.6f\n", param->param[i]);
            _modbus_add_float(pkt + len, param->param[i]);
            len += 4;
        }
        _modbus_checksum(pkt, len);
        len += 2;

        for (loop = 0; loop < 5; loop++)
        {
            usleep(300*1000);
            serial_write(cau.serial_fd, pkt, len);
            //print_raw_data(pkt, len);

            unsigned char *rxpkt = cau.modbus_recv_buf;
            slen = _cau_recv(rxpkt);
            //print_raw_data(rxpkt, slen);
            if (slen != 8)
            {
                sleep(1);
                DBG(DBG_M_CA_CAU, "Send repeatedly in  %d times.\n", loop+1);
                continue;
            }
            break;
        }
    }
    return ret;
}

int _cau_get_channel_segment_param(Parameters_t *pbuf)
{
    int len;
    int slen;
    int ch, loop;
    unsigned char *pkt = cau.modbus_send_buf;;
    for (ch = 0; ch < MAX_CAU_CHANNEL; ch++)
    {
        //if (!pbuf->chClose[ch])
        //    continue;
        len = _modbus_write_head(pkt, MB_FUNC_MULIT_RD, MB_CALI_PARAM + ch *0x20, 30);
        _modbus_checksum(pkt, len);
        len += 2;

        for (loop = 0; loop < 5; loop++)
        {
            serial_write(cau.serial_fd, pkt, len);
            print_raw_data(pkt, len);

            unsigned char *rxpkt = cau.modbus_recv_buf;
            if ((slen = _cau_recv(rxpkt)) > 0)
            {
                int j;
                print_raw_data(rxpkt, slen);

                unsigned char *ppkt = rxpkt + 3;
                Parameter_t *param = &cau.cali_param.chOld[ch];
                DBG(DBG_M_CA_CAU, "ch%d param:\n", ch);
                for (j = 0; j < 15; j++)
                {
                    _cau_get_float_data(ppkt + 4 * j, &param->param[j]);
                    DBG(DBG_M_CA_CAU, "%f \n", param->param[j]);
                }
                break;
            }
        }
    }
    return 0;
}

int _cau_save_flash(Parameters_t *pbuf)
{
    int len;
    int slen;
    unsigned char *pkt = cau.modbus_send_buf;;
    len = _modbus_write_head(pkt, MB_FUNC_MULIT_WR, MB_FAC_PARAM , 2);
    pkt[len++] = 0x12;
    pkt[len++] = 0x34;
    pkt[len++] = 0x55;
    pkt[len++] = 0xAA;
    _modbus_checksum(pkt, len);
    len += 2;

    serial_write(cau.serial_fd, pkt, len);
    print_raw_data(pkt, len);

    unsigned char *rxpkt = cau.modbus_recv_buf;
    if ((slen = _cau_recv(rxpkt)) > 0)
    {
        print_raw_data(rxpkt, slen);
    }
    return 0;
}

int _find_peripheral(const char *name)
{
    int idx = -1;
    int i;
    for (i = 0; i < pparam_config->devSize; i++)
    {
        DevCfg_t *dev = &pparam_config->devs[i];
        if (dev == NULL)
            continue;

        if (strcmp((char*)dev->devName,name) == 0)
        {
            idx = i;
            break;
        }
    }
    return idx;
}

int _cau_noraml_work()
{
    unsigned int cur_time, diff_time;
    int id;
    id = _find_peripheral("CAU1");
    if (id >= 0)
    {
        cur_time = time(NULL);
        diff_time = CPUMS_DIFF(cau.last_collect_time, cur_time);
        //LOG("diff_time = %d, space=%d\n", diff_time, pparam_config->devs[id].space);
        if (diff_time >= pparam_config->devs[id].space)
        {
            cau.last_collect_time = cur_time;
            _cau_power_on();
            if (_cau_set_user_param() == 0)
            {
                //_cau_get_user_param_ratio(NULL);
                _cau_get_meas_param();
                cau_collect_flag = 1;
            }
            _cau_power_off();
        }
    }
    return 0;
}

int _cau_cali_start(Parameters_t *cali)
{
    int point;
    for (point = 0; point < CALI_POINT_MAX; point++)
    {
        if (cali->isVoltage)
        {
            cl106d_setpower(cali->sample[point], 0);
            sleep(10);
        }
        else
        {
            cl106d_setpower(57.7, cali->sample[point]);
            DBG(DBG_M_CA_CAU, "--------电流校准点%d:%.4f __%.4f-------",point,cali->sample[point],cali->sample[point]*cali->turns);
            sleep(5);
        }

        int j;
        for (j = 0; j < 20; j++)    // 1个点20个值
        {
            usleep(20*1000);
            _cau_get_meas_current_value();
            memcpy(&cau.cali_val.cauVal[point*20 + j], &cau.real_data, sizeof(cau_real_data_t));
        }
    }
    return 0;
}

float sort(float *a,int len)
{
    int i=0;
    int j;
    float t;
    float ret = 0;
    for(i=0;i<len-1;i++)        //len-1
    {
        for(j=0;j<len-i-1;j++)
        {
            if(a[j]>a[j+1])
            {
                t=a[j];
                a[j]=a[j+1];
                a[j+1]=t;
            }
        }
    }
    for(i = 5;i<15;i++)
    {
        ret += a[i];
    }
    ret = ret*0.1;
    return ret;
}

int _cau_cali_calculation(Parameters_t *cali)
{
    int ch;
    for (ch = 0; ch < MAX_CAU_CHANNEL; ch++)
    {
        if (!cali->chClose[ch])
            continue;

        int i,j;
        for (i = 0; i < CALI_POINT_MAX; i++)
        {
            float sum;
            float temp[20] = {0};
            for (j = 0; j < 20; j++)
                temp[j] = cau.cali_val.cauVal[j+i*20].tag[ch];
            sum = sort(temp,20);

            cau.cali_val.cauAvg[i].tag[ch] = sum / cali->turns;

            cau.cali_val.cauAvg[i].tag[ch] = ( (float)( (int)( (cau.cali_val.cauAvg[i].tag[ch]+0.0005)*1000 ) ) )/1000;

            cali->chNew[ch].param[i*2+5] = cali->sample[i]/cau.cali_val.cauAvg[i].tag[ch]; //校准系数a
            DBG(DBG_M_CA_CAU, "ch[%d]-[%d] avg=%.3f a=%.3f\n", ch,i,
                cau.cali_val.cauAvg[i].tag[ch],cali->chNew[ch].param[i*2+5]);
        }
    }
    return 0;
}

int _cau_manual_calibratin(Parameters_t *cali)
{
    int ch;
    _cau_get_channel_segment_param(cali);
    _cau_get_user_param_ratio(cali);
    for (ch = 0; ch < 8; ch++)
    {
        memcpy(cali->chNew[ch].param, cali->chOld[ch].param, sizeof(Parameter_t));
    }
    printh("[%s:%d]Result ManualAdjust Status\r\n", __FUNCTION__, __LINE__);
    cau.send_data(DEBUG_ManualAdjust, (char *)cali, sizeof(Parameters_t));
    while (1)
    {
        usleep(1000*1000);
    }
    return 0;
}

int _cau_calibration_process(Parameters_t *cali)
{
    if (cali == NULL)
    {
        return -1;
    }
    if (cali->cauBoard != 1)
    {
        return -1;
    }
    if (cau.workstat == 1)
    {
        return 0;
    }
    printh("[%s:%d]\n", __FUNCTION__, __LINE__);

    char tmp[256] = {0};
    sprintf(tmp, "CAU%d", cali->cauBoard);
    int id = _find_peripheral(tmp);
    if (id <= 0)
        goto err;

    _cau_power_off();
    sleep(2);
    _cau_power_on();
    sleep(5);

    if (cau.ismanual == 1)
    {
       _cau_manual_calibratin(cali); 
    }

    if (cali->inAdjust == 2)
        goto get;
    
    _cau_set_channel_segment_param(cali);
    _cau_set_user_param_ratio(cali); 

    if (cali->inAdjust == 3)
        goto init;

    cl106d_init();
    if (!cl106d_connet())
    {
        cali->err = 4;
        printh("cl106d_connet err.\n");
        goto err;
    }

    _cau_cali_start(cali);

    _cau_cali_calculation(cali);

    // 写参数
    _cau_set_channel_segment_param(cali);
    sleep(2);
    
    cau.workstat = 1;
 init:
    //保存flash
    _cau_save_flash(cali);
    sleep(2);

    _cau_power_off();
    _cau_power_on();
 get:
    _cau_get_channel_segment_param(cali);
    _cau_get_user_param_ratio(cali);
 err:
    // 此处增加回调,返回给管理工具;
    printh("[%s:%d]rebackAdjustResult\r\n", __FUNCTION__, __LINE__);
    cau.send_data(DEBUG_ADJUST_RESULT, (char *)cali, sizeof(Parameters_t));
    return 0;
}

/* CAU采集处理函数. */
void *_cau_data_handle(void *arg)
{
    cau.serial_fd = serial_open("/dev/ttymxc1", 921600);
    if (cau.serial_fd < 0)
    {
        log_err(LOG_CAU, "serial_open failed!\n");
        return NULL;
    }

    sleep(1);
    //_cau_set_user_param();

    while(1)
    {
        switch (cau.cali_param.inAdjust)
        {
            case 0:
                _cau_noraml_work();
                break;
            case 4:
                break;
            default:
                _cau_calibration_process(&cau.cali_param);
                break;
        }
        pwr.vbat = _pwr_read_vbat();
        pwr.vsc = _pwr_read_vsc();
        pwr.vout = _pwr_read_vout();
        //LOG("vbat:%d vsc:%d vout:%d", pwr.vbat, pwr.vsc, pwr.vout);
        
        usleep(100*1000);
    }

    return NULL;
}

/* CAU采集处理函数. */
void *_cau_recv_handle(void *arg)
{
    
    while(1)
    {
        sleep(1);
    }

    return NULL;
}


int32_t _cau_handle_init_common(void)
{
    struct sched_param param;
    pthread_attr_t attr;
    pthread_t pid;
    int32_t rv = 0;
    
    /* 配置线程RR调度, 优先级79 */
    pthread_attr_init(&attr);
    param.sched_priority = 79;
    pthread_attr_setschedpolicy(&attr, SCHED_RR);
    pthread_attr_setschedparam(&attr, &param);
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    rv = pthread_create(&pid, &attr, _cau_data_handle, NULL);
    if (rv != 0)
    {
        log_err(LOG_CAU, "PD can't create CAU data pthread %d!", rv);
        return E_ERROR;
    }
    else
    {
        thread_m_add("CA_CAU_CAPTURE", pid);
    }
    pthread_attr_destroy(&attr);

#if 0
    /* 初始化 CAU 收包线程. */
    /* 配置线程RR调度, 优先级80 */
    pthread_attr_init(&attr);
    param.sched_priority = 80;
    pthread_attr_setschedpolicy(&attr, SCHED_RR);
    pthread_attr_setschedparam(&attr, &param);
    pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
    rv = pthread_create(&pid, &attr, _cau_recv_handle, NULL);
    if (rv != 0)
    {
        log_err(LOG_CAU, "CAU can't create recv pthread %d!", rv);
        return E_SYS_CALL;
    }
    else
    {
        thread_m_add("CA_CAU_RECV", pid);
    }
    pthread_attr_destroy(&attr);
#endif
    return E_NONE;
}

/* Interface functions -------------------------------------------------------*/
int32_t cau_handle_init(void)
{
    /* 开启cau电源 */
    //GPIO_CAU1_POWER_ON;

    memset(&cau, 0, sizeof(cau_t));
    cau.serial_fd = -1;
    cau.last_collect_time = time(NULL);
    cau.send_data = _debug_pkt_send_data;
    
    /* 初始化模块. */
    LD_E_RETURN(DBG_M_CA_CAU_ERR, _cau_handle_init_common());

    //cmd_install_element(CONFIG_NODE, &csg_server_set_cmd);

    /* 注册配置保存函数 */

    return E_NONE;
}

static int _pwr_read_adc(int fd)
{
    char buffer[16]={0};
    int ret, cnt = 2;

    do{
        fsync(fd);
        lseek(fd,0,SEEK_SET);
        ret = read(fd,buffer,sizeof(buffer));
        if(ret <= 0)  
            usleep(1000);
        else 
            break;
    }while(cnt--);

    if(ret <= 0) 
        return -2;
    return (atoi(buffer) * 6600 /4096) + 100;

}

int _pwr_read_vsc(void)
{
    static int fd = 0;
    const char *path = "/sys/bus/iio/devices/iio:device0/in_voltage1_raw";

    if(fd <= 0)
    {
        fd = open(path, O_RDONLY);
        if(fd <= 0)
        {
            LOG("读VSC-ADC失败,PATH = %s",path);
            return -1;
        }
    }

    return _pwr_read_adc(fd);
}

int _pwr_read_vbat(void)
{
    static int fd = 0;
    const char *path = "/sys/bus/iio/devices/iio:device0/in_voltage2_raw";

    if(fd <= 0)
    {
        fd = open(path, O_RDONLY);
        if(fd <= 0)
        {
            LOG("读VBAT-ADC失败,PATH = %s",path);
            return -1;
        }
    }

    return _pwr_read_adc(fd);
}

int _pwr_read_vout(void)
{
    static int fd = 0;
    const char *path = "/sys/bus/iio/devices/iio:device0/in_voltage3_raw";

    if(fd <= 0)
    {
        fd = open(path, O_RDONLY);
        if(fd <= 0)
        {
            LOG("读VOUT-ADC失败,PATH = %s",path);
            return -1;
        }
    }

    return _pwr_read_adc(fd);
}

#endif

