#include "msystem.h"
#include "mgpio.h"
#include "mlogger.h"
#include "ccu_config.h"
#include "ocpp16_client.h"
#include "ocpp16.h"
#include "ocpp16_encode.h"
#include "ocpp16_decode.h"
#include "ocpp16_configkey.h"
#include "ocpp16_authorization.h"
#include "ocpp16_ChargingProfiles.h"
#include "ocpp16_OfflineChargingRecords.h"
#include "interface.h"
#include "sys_bsp.h"
#include "pcutc.h"
#include "pcuhw.h"

static char app_version[128] = {0};
static const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
char* formatAppVersion(void)
{
	int i;
	int month, mday, year, hour, min, sec;
    #define ASCII_CODE(x)  ((x)==32? 0:((x)-'0'))
    mday = ASCII_CODE(__DATE__[4])*10 + ASCII_CODE(__DATE__[5]);
    year = ASCII_CODE(__DATE__[7])*1000 + ASCII_CODE(__DATE__[8])*100 + ASCII_CODE(__DATE__[9])*10 + ASCII_CODE(__DATE__[10]);
    hour = ASCII_CODE(__TIME__[0])*10 + ASCII_CODE(__TIME__[1]);
    min  = ASCII_CODE(__TIME__[3])*10 + ASCII_CODE(__TIME__[4]);
    sec  = ASCII_CODE(__TIME__[6])*10 + ASCII_CODE(__TIME__[7]);
    #undef ASCII_CODE
  	for (i = 0; i < 12; i++)
  	{
    	if (strncmp(__DATE__, months[i], 3)==0)
    	{
      		month = i + 1;
     	 	break;
    	}
  	}

    snprintf(app_version, 128, "app_CCU_V1R1B%04d%02d%02d %02d:%02d:%02d", year, month, mday, hour, min, sec);
    return app_version;
}

static long *lock_count;
static pthread_mutex_t *lock_cs;
void pthread_locking_callback(int mode, int type, const char *file, int line)
{
	if (mode & CRYPTO_LOCK)
	{
        lock_count[type]++;
		pthread_mutex_lock(&(lock_cs[type]));
	}
	else
	{
		pthread_mutex_unlock(&(lock_cs[type]));
	}
}

pthread_t pthreads_thread_id(void)
{
    pthread_t ret;
    ret=pthread_self();
    return(ret);
}

static void CRYPTO_thread_setup(void)
{
	int i;
	lock_cs = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
    lock_count=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
	for (i = 0; i < CRYPTO_num_locks(); i++)
	{
        lock_count[i]=0;
		pthread_mutex_init(&(lock_cs[i]), NULL);
	}

	CRYPTO_set_id_callback((unsigned long (*)())pthread_thread_id);
	CRYPTO_set_locking_callback((void (*)(int, int, const char *, int))pthread_locking_callback);
}

static void CRYPTO_thread_cleanup(void)
{
	int i;
	CRYPTO_set_locking_callback(NULL);
	for (i = 0; i < CRYPTO_num_locks(); i++)
	{
		pthread_mutex_destroy(&(lock_cs[i]));
	}
	OPENSSL_free(lock_cs);
}

int openSSL_check_certificate(SSL*  ssl)
{
    int result = 0;
    /* 基于 ctx 产生一个新的 SSL */
    printi("ssl(%p)\n", ssl);
    // SSL_get_verify_result()是重点，SSL_CTX_set_verify()只是配置启不启用并没有执行认证，调用该函数才会真证进行证书认证
    // 如果验证不通过，那么程序抛出异常中止连接
    if(SSL_get_verify_result(ssl) == X509_V_OK){
        printi("ssl(%p), 证书验证通过\n", ssl);
        result = 0;
    }else{
        printi("ssl(%p), 证书验证不通过\n", ssl);
        result = -1;
    }
    X509 *cert = SSL_get_peer_certificate(ssl);
    if (cert != NULL) {
        printi("ssl(%p), 数字证书信息:\n", ssl);
        char *line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
        printi("ssl(%p), 证书: %s\n", ssl, line);
        free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
        printi("ssl(%p), 颁发者: %s\n", ssl, line);
        free(line);
        X509_free(cert);
    } else {
        printi("ssl(%p), 无证书信息！\n", ssl);
    }
    return result;
}

static void print_help(void)
{
    printf("\n*************************************************\n");
    printf("\n      sys cmd list\n\n");
    printf("\n*************************************************\n");
    printf("\n");
	
    printf("\t 0, test CAN: mcucan0. mcucan1. mcan0. spi1can3\n");
    printf("\t 1, test RS232: UART2(ttyS2) UART3(ttyS3).\n");
    printf("\t 2, test RS485: UART4(ttyS4) UART5(ttyS5) UART6(ttyS6).\n\n");

    printf("\t 3, get SYS (all) state.\n");
    printf("\t 4, get Box (all) Temp.\n");
    printf("\t 5, get GUN (all) Temp.\n\n");

    printf("\t 6, set SYS LED(1).\n");
    printf("\t 7, set SYS LED(0).\n");
    printf("\t 8, set SYS SSR(1).\n");
    printf("\t 9, set SYS SSR(0).\n");
    printf("\t 10, get SYS KMD state.\n");
    printf("\t 11, set SYS KMD(1).\n");
    printf("\t 12, set SYS KMD(0).\n\n");

    printf("\t 13, get SYS PWM state.\n");
    printf("\t 14, set SYS PWM(0).\n");
    printf("\t 15, set SYS PWM(15).\n");
    printf("\t 16, set SYS PWM(20).\n");
    printf("\t 17, set SYS PWM(25).\n");
    printf("\t 18, set SYS PWM(30).\n");
    printf("\t 19, set SYS PWM(50).\n\n");

    printf("\t 20, get GUNA (all) state.\n");
    printf("\t 21, set GUNA Elock(1).\n");
    printf("\t 22, set GUNA Elock(0).\n");
    printf("\t 23, set GUNA K1(1).\n");
    printf("\t 24, set GUNA K1(0).\n");
    printf("\t 25, set GUNA K2(1).\n");
    printf("\t 26, set GUNA K2(0).\n");
    printf("\t 27, set GUNA Aux12V(1).\n");
    printf("\t 28, set GUNA Aux12V(0).\n");
    printf("\t 29, set GUNA CP PWM(5).\n\n");

    printf("\t 30, get GUNB (all) state.\n");
    printf("\t 31, set GUNB Elock(1).\n");
    printf("\t 32, set GUNB Elock(0).\n");
    printf("\t 33, set GUNB K1(1)\n");
    printf("\t 34, set GUNB K1(0).\n");
    printf("\t 35, set GUNB K2(1).\n");
    printf("\t 36, set GUNB K2(0).\n");
    printf("\t 37, set GUNB Aux12V(1).\n");
    printf("\t 38, set GUNB Aux12V(0).\n");
    printf("\t 39, set GUNB CP PWM(5).\n");

    printf("\t40, NFC.read.\n");
    printf("\t41, log.debug(1).\n");
    printf("\t42, log.debug(0).\n");
    printf("\t43, SECCA start Transmation.\n");
    printf("\t44, SECCA stop Transmation.\n");
    printf("\t45, SECCB start Transmation.\n");
    printf("\t46, SECCB stop Transmation.\n");

    printf("\t47, pcutc.request_Power.\n");
    printf("\t48, pcutc.getVoltageCurrent.\n");
    printf("\t49, pcutc.set_GUNLine_PermittedVoltageCurrent.\n");

    printf("\n\n*************************************************\n");
}

static void* sys_CMD_loop(void* argv)
{
    uint32_t cmd;
    ccu_port_t* dev = (ccu_port_t*)argv;
    secc_port_t *seccA = (secc_port_t*)dev->seccA;
    secc_port_t *seccB = (secc_port_t*)dev->seccB;
    modbusTCP_QT_t *qttcu = (modbusTCP_QT_t*)dev->qttcu;
    uint8_t buff[64];
    printd("ENTER.\n");

    while(dev->quit == 0)
    {
        sleep(1);       //减去此处的干扰
        continue;

        print_help();
        printf("please input cmd:");
        int ret;
        do {
            ret = scanf("%d", &cmd);
            if (ret == -1) sleep(1);
        }while(ret == -1);
        printf("input cmd:%d, ret=%d", cmd, ret);

        switch(cmd)
        {
            // case 0: can_test(10); break;
            // case 1: rs232_test(10); break;
            // case 2: rs485_test(10); break;
            case 3: {
                printf("FanA:%d, FanB:%d, FanC:%d, LGPTA:%d, LGPTB:%d, WAT:%d, GAT:%d, EMG:%d, SMOKE:%d, POWERLOSS:%d\n",
                    sys_Get_FanFBA(),
                    sys_Get_FanFBB(),
                    sys_Get_FanFBC(),
                    sys_Get_LGPTFA(),
                    sys_Get_LGPTFB(),
                    sys_Get_WATFB(),
                    sys_Get_GATFB(),
                    sys_Get_EMGFB(),
                    sys_Get_SMOKE(),
                    sys_Get_POWERLOSS());
            }break;
            case 4:{
                printf("BoxTemp0:%f, BoxTemp1:%f, BoxTemp2:%f, BoxTemp3:%f, BoxTemp4:%f, BoxTemp5:%f, BoxTemp6:%f, BoxTemp7:%f\n",
                    sys_Get_BOX_Temp(0),sys_Get_BOX_Temp(1),sys_Get_BOX_Temp(2),sys_Get_BOX_Temp(3),
                    sys_Get_BOX_Temp(4),sys_Get_BOX_Temp(5),sys_Get_BOX_Temp(6),sys_Get_BOX_Temp(7));
            }break;
            case 5:{
                printf("GUNTemp0:%f, GUNTemp1:%f, GUNTemp2:%f, GUNTemp3:%f\n", 
                    sys_Get_GUN_Temp(0),sys_Get_GUN_Temp(1),sys_Get_GUN_Temp(2),sys_Get_GUN_Temp(3));
            }break;
            case 6: { 
                sys_Set_LED(1, 1);
                sys_Set_LED(2, 1);
                sys_Set_LED(3, 1);
                sys_POWER_Heartbeat();
                sys_TCULED_Heartbeat();
                sys_CCULED_Heartbeat();
                sys_PCULED_Heartbeat();
            }break;
            case 7: {
                sys_Set_LED(1, 0);
                sys_Set_LED(2, 0);
                sys_Set_LED(3, 0);
                sys_POWER_Heartbeat();
                sys_TCULED_Heartbeat();
                sys_CCULED_Heartbeat();
                sys_PCULED_Heartbeat();
            }break;
            case 8: { 
                sys_Set_SSR(1, 1);
                sys_Set_SSR(2, 1);
                sys_Set_SSR(3, 1);
            }break;
            case 9: { 
                sys_Set_SSR(1, 0);
                sys_Set_SSR(2, 0);
                sys_Set_SSR(3, 0);
            }break;
            case 10:{
                printf("KMD1:%d, KMD2:%d, KMD3:%d, KMD4:%d, KMD5:%d, KMD6:%d\n",
                    sys_Get_KMD(1), sys_Get_KMD(2), sys_Get_KMD(3),
                    sys_Get_KMD(4), sys_Get_KMD(5), sys_Get_KMD(6));
            }break;
            case 11:{
                sys_Set_KMD(1, 1);
                sys_Set_KMD(2, 1);
                sys_Set_KMD(3, 1);
                sys_Set_KMD(4, 1);
                sys_Set_KMD(5, 1);
                sys_Set_KMD(6, 1);
            }break;
            case 12:{
                sys_Set_KMD(1, 0);
                sys_Set_KMD(2, 0);
                sys_Set_KMD(3, 0);
                sys_Set_KMD(4, 0);
                sys_Set_KMD(5, 0);
                sys_Set_KMD(6, 0);
            }break;
            case 13:{ 
                printf("PWM0:%d, PWM1:%d, PWM2:%d, PWM3:%d, PWM4:%d, PWM5:%d, PWM6:%d, PWM7:%d \n",
                    sys_Get_PWMFB(0), sys_Get_PWMFB(1), sys_Get_PWMFB(2), sys_Get_PWMFB(3),
                    sys_Get_PWMFB(4), sys_Get_PWMFB(5), sys_Get_PWMFB(6), sys_Get_PWMFB(7));
            }break;  
            case 14:{ 
                sys_Set_PWM(0, 0);
                sys_Set_PWM(1, 0);
                sys_Set_PWM(2, 0);
                sys_Set_PWM(3, 0);
                sys_Set_PWM(4, 0);
                sys_Set_PWM(5, 0);
                sys_Set_PWM(6, 0);
                sys_Set_PWM(7, 0);
            }break;
            case 15:{ 
                sys_Set_PWM(0, 615);
                sys_Set_PWM(1, 615);
                sys_Set_PWM(2, 615);
                sys_Set_PWM(3, 615);
                sys_Set_PWM(4, 615);
                sys_Set_PWM(5, 615);
                sys_Set_PWM(6, 615);
                sys_Set_PWM(7, 615);
            }break;
            case 16:{
                sys_Set_PWM(0, 819);
                sys_Set_PWM(1, 819);
                sys_Set_PWM(2, 819);
                sys_Set_PWM(3, 819);
                sys_Set_PWM(4, 819);
                sys_Set_PWM(5, 819);
                sys_Set_PWM(6, 819);
                sys_Set_PWM(7, 819);
            }break;
            case 17:{
                sys_Set_PWM(0, 1024);
                sys_Set_PWM(1, 1024);
                sys_Set_PWM(2, 1024);
                sys_Set_PWM(3, 1024);
                sys_Set_PWM(4, 1024);
                sys_Set_PWM(5, 1024);
                sys_Set_PWM(6, 1024);
                sys_Set_PWM(7, 1024);
            }break;
            case 18:{
                sys_Set_PWM(0, 1229);
                sys_Set_PWM(1, 1229);
                sys_Set_PWM(2, 1229);
                sys_Set_PWM(3, 1229);
                sys_Set_PWM(4, 1229);
                sys_Set_PWM(5, 1229);
                sys_Set_PWM(6, 1229);
                sys_Set_PWM(7, 1229);
            }break;
            case 19:{
                sys_Set_PWM(0, 2048);
                sys_Set_PWM(1, 2048);
                sys_Set_PWM(2, 2048);
                sys_Set_PWM(3, 2048);
                sys_Set_PWM(4, 2048);
                sys_Set_PWM(5, 2048);
                sys_Set_PWM(6, 2048);
                sys_Set_PWM(7, 2048);
            }break;
            case 20:{
                printf("GUNA Home:%d, Fuse:%d, Elock:%d, K1:%d, K2:%d, CP:%f, PP:%f, CC1:%f\n",
                gunA_Get_HomeState(NULL),
                gunA_Get_FuseState(NULL),
                gunA_Get_ELock(NULL),
                gunA_Get_K1(NULL),
                gunA_Get_K2(NULL),
                gunA_Get_CP_Voltage(NULL, NULL),
                gunA_Get_PP_Voltage(NULL),
                gunA_Get_CC1_Voltage(NULL));
            }break;
            case 21:{ gunA_Set_ELock(NULL, 1); }break;
            case 22:{ gunA_Set_ELock(NULL, 0); }break;
            case 23:{ gunA_Set_K1(NULL, 1); }break;
            case 24:{ gunA_Set_K1(NULL, 0); }break;
            case 25:{ gunA_Set_K2(NULL, 1); }break;
            case 26:{ gunA_Set_K2(NULL, 0); }break;
            case 27:{ gunA_Set_Aux12V(NULL, 1); }break;
            case 28:{ gunA_Set_Aux12V(NULL, 0); }break;
            case 29:{ gunA_Set_PWM(NULL, 5);}break;

            case 30:{
                printf("GUNB Home:%d, Fuse:%d, Elock:%d, K1:%d, K2:%d, CP:%f, PP:%f, CC1:%f\n",
                gunB_Get_HomeState(NULL),
                gunB_Get_FuseState(NULL),
                gunB_Get_ELock(NULL),
                gunB_Get_K1(NULL),
                gunB_Get_K2(NULL),
                gunB_Get_CP_Voltage(NULL, NULL),
                gunB_Get_PP_Voltage(NULL),
                gunB_Get_CC1_Voltage(NULL));
            }break;
            case 31:{ gunB_Set_ELock(NULL, 1); }break;
            case 32:{ gunB_Set_ELock(NULL, 0); }break;
            case 33:{ gunB_Set_K1(NULL, 1); }break;
            case 34:{ gunB_Set_K1(NULL, 0); }break;
            case 35:{ gunB_Set_K2(NULL, 1); }break;
            case 36:{ gunB_Set_K2(NULL, 0); }break;
            case 37:{ gunB_Set_Aux12V(NULL, 1); }break;
            case 38:{ gunB_Set_Aux12V(NULL, 0); }break;
            case 39:{ gunB_Set_PWM(NULL, 5);}break;

            case 40: printf("\tNFC.read...\n"); if (sys_Get_NFC_CardID(dev, 10000, buff) == 0) printf("\tNFC CardID:%s\n", buff); break;
            case 41: printf("\tlog.debug(1)\n"); mlog_control(MLOG_LVL_DEBUG, 1); break;
            case 42: printf("\tlog.debug(0)\n"); mlog_control(MLOG_LVL_DEBUG, 0); break;

            case 43: printf("\tSECCA.start_transaton\n"); secc_eim_startup(seccA, "NULL", 10000, 0, 0); break;
            case 44: printf("\tSECCA.stop_transaton\n"); secc_eim_shutdown(seccA); break;
            case 45: printf("\tSECCB.start_transaton\n"); secc_eim_startup(seccB, "NULL", 10000, 0, 0); break;
            case 46: printf("\tSECCB.stop_transaton\n"); secc_eim_shutdown(seccB); break;

            case 47: printf("\tpcutc.request_Power\n"); {
                pcutcA.request_Power(&pcutcA, 0, 200, 100); 
                pcutcB.request_Power(&pcutcB, 0, 400, 300);
            }break;
            case 48: printf("\tpcutc.getVoltageCurrent\n"); {
                float maxV,minV,maxI,minI;
                pcutcA.get_PCU_maxVoltageCurrent(&pcutcA, &maxV, &maxI);
                pcutcA.get_PCU_minVoltageCurrent(&pcutcA, &minV, &minI);
                printf("GUNA.maxV:%f, minV:%f, maxI:%f, minI:%f\n", maxV, minV, maxI, minI);
                pcutcB.get_PCU_maxVoltageCurrent(&pcutcB, &maxV, &maxI);
                pcutcB.get_PCU_minVoltageCurrent(&pcutcB, &minV, &minI);
                printf("GUNB.maxV:%f, minV:%f, maxI:%f, minI:%f\n", maxV, minV, maxI, minI);
            }break;
            case 49: printf("\tpcutc.set_GUNLine_PermittedVoltageCurrent\n"); {
                pcutcA.set_GUNLine_PermittedVoltageCurrent(&pcutcA, 250);
                pcutcB.set_GUNLine_PermittedVoltageCurrent(&pcutcB, 200);
            }break;
        }
        // printf("SECC.A:%d,%f\n", dev->get_PluginHomeState(dev), dev->get_CC_voltage(dev));
    }
    printd("LEAVE.\n");
    return NULL;
}

int main(int argc, char* argv[])
{
    int MLOG_MAX_FILESIZE = MLOG_BUFF_SIZE*60*24;
    int MLOG_MAX_FILENUMB = 7;
    // signal(SIGPIPE, SIG_IGN);
    // signal(SIGTERM, singal_term_handle);
	// parse_options(argc, argv);
    {
        int c;
        while ((c = getopt(argc, argv, "s:n:v")) != -1) {
            switch (c) {
            case 's':
                MLOG_MAX_FILESIZE = atoi(optarg);
                break;
            case 'n':
                MLOG_MAX_FILENUMB = atoi(optarg);
                break;
            case 'v':{
                printf("%s\n", formatAppVersion());
                return 0;
            }
            case '?':
                break;
            default:
                exit(2);
            }
        }
    }


    // 初始化 OpenSSL
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    CRYPTO_thread_setup();
    mlog_init("/home/root/app_run/log/ccu", MLOG_MAX_FILESIZE, MLOG_MAX_FILENUMB);
	printv("\n\t%s\n", formatAppVersion());
    printv("\tMLOG_MAX_FILESIZE:%d, MLOG_MAX_FILENUMB:%d\n", MLOG_MAX_FILESIZE, MLOG_MAX_FILENUMB);

    mgpio_init();
	ccu_config_init();
    ocpp16_configkey_init();
    ocpp16_authorization_init();
    ocpp16_ChargingProfiles_init();
    ocpp16_OfflineChargingRecords_upload();
   
    ccu_PORT_init();
    
    sys_CMD_loop(&ccu_port);
    ccu_PORT_exit();

    ocpp16_OfflineChargingRecords_exit();
    ocpp16_ChargingProfiles_exit();
    ocpp16_authorization_exit();
    ocpp16_configkey_exit();
    ccu_config_exit();

    mgpio_exit();
    mlog_exit();
    CRYPTO_thread_cleanup();

	return 0;
}