/***********************************************
深14串口通信程序
***********************************************/
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <time.h>
#include <sys/types.h>  
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>  
#include <termios.h>  
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <arpa/inet.h>
#include "hiredis/hiredis.h"
#include "cjson/cJSON.h"
#include "iniparser/iniparser.h"
 
#define FALSE -1  
#define TRUE 0
#define OFF 0
#define ON  1

//BARESIP_STATUS
#define IDLE        0
#define INUSE       1
#define RING        2
#define RINGING     3
#define HOLD        4
#define OFFLINE     5
#define DIALING     6
//BARESIP_REG
#define REGISTER_FAIL   0
#define REGISTER_OK     1
//KEY STATUS
#define UP      0
#define DOWN    1
//REDIS_CHANNEL
#define BARESIP_CHAN    0
#define GPIO_CHAN       1

typedef enum 
{   
    AI_EVENT_HELP = 1,
    AI_EVENT_DRL,
    AI_EVENT_BDL,
    AI_EVENT_DJL,
    AI_EVENT_BDW,
    AI_EVENT_CY,
    AI_EVENT_YHM,
    AI_EVENT_KLR,
    AI_EVENT_ADL,
    AI_EVENT_MDL,
    AI_EVENT_DCL,
    AI_EVENT_ZBA,
    AI_EVENT_ZHL,
    AI_EVENT_KBJ
} AI_ALARM_EVENT;

typedef struct
{
    int call_en;
    char call_num[32];
    char call_line[16];
    int http_en;
    char http_url[128];
    int relay_en;
    int relay_duration;
    int screen_en;
    int screen_id;
    int screen_duration;
} ai_conf;

#define SPK_CONF    "/etc/speaker.conf"
#define FUN			"FUNCTION"

static int DEBUG = OFF;
static int BARESIP_STATUS = OFFLINE;
static int ACCOUNT1_REG = REGISTER_FAIL;
static int ACCOUNT2_REG = REGISTER_FAIL;
static int ACCOUNT3_REG = REGISTER_FAIL;
static int ACCOUNTP2P_REG = REGISTER_FAIL;
//static char deviceId[16];
static int delay;
redisContext *pctlContext;

  
int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300, \
				   B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300,};  
int name_arr[] = {115200, 38400, 19200,  9600, 4800, 2400, 1200,  300, \
				  115200, 38400, 19200,  9600, 4800, 2400, 1200,  300, };  

void set_speed(int fd, int speed){  
  int   i;   
  int   status;   
  struct termios   Opt;  

  tcgetattr(fd, &Opt);   
  for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++) {   
    if  (speed == name_arr[i]) {       
      tcflush(fd, TCIOFLUSH);       
      cfsetispeed(&Opt, speed_arr[i]);    
      cfsetospeed(&Opt, speed_arr[i]);     
      status = tcsetattr(fd, TCSANOW, &Opt);    
      if  (status != 0) {          
        printf("tcsetattr fd1\n");    
        return;       
      }      
      tcflush(fd,TCIOFLUSH);     
    }    
  }  
}
  
int set_Parity(int fd,int databits,int stopbits,int parity)  
{   
    struct termios options;   
    if  ( tcgetattr( fd,&options)  !=  0) {   
        printf("SetupSerial 1\n");       
        return(FALSE);    
    }  
    options.c_cflag &= ~CSIZE;   
    switch (databits)   
    {     
    case 7:       
        options.c_cflag |= CS7;   
        break;  
    case 8:       
        options.c_cflag |= CS8;  
        break;     
    default:      
        fprintf(stderr,"Unsupported data size\n"); return (FALSE);    
    }  
    switch (parity)   
    {     
        case 'n':  
        case 'N':      
            options.c_cflag &= ~PARENB;   /* Clear parity enable */  
            options.c_iflag &= ~INPCK;     /* Enable parity checking */   
            break;    
        case 'o':     
        case 'O':       
            options.c_cflag |= (PARODD | PARENB);   
            options.c_iflag |= INPCK;             /* Disnable parity checking */   
            break;    
        case 'e':    
        case 'E':     
            options.c_cflag |= PARENB;     /* Enable parity */      
            options.c_cflag &= ~PARODD;      
            options.c_iflag |= INPCK;       /* Disnable parity checking */  
            break;  
        case 'S':   
        case 's':  /*as no parity*/     
            options.c_cflag &= ~PARENB;  
            options.c_cflag &= ~CSTOPB;
            break;
        default:
            fprintf(stderr,"Unsupported parity\n");
            return (FALSE);
    }
      
    switch (stopbits)  
    {
        case 1:
            options.c_cflag &= ~CSTOPB;
            break;
        case 2:
            options.c_cflag |= CSTOPB;
           break;
        default:
             fprintf(stderr,"Unsupported stop bits\n");
             return (FALSE);
    }
    /* Set input parity option */
    if (parity != 'n')
        options.c_iflag |= INPCK;
    options.c_cc[VTIME] = 150;
    options.c_cc[VMIN] = 0; /* Update the options and do it NOW */  
    options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input*/
    options.c_oflag  &= ~OPOST;   /*Output*/
    options.c_iflag &= ~(ICRNL | IGNCR | IXON | IXOFF);
    tcflush(fd,TCIFLUSH);

    if (tcsetattr(fd,TCSANOW,&options) != 0)
    {
        printf("SetupSerial 3\n");
        return (FALSE);
    }
    return (TRUE);    
}

typedef    unsigned char     uchar; 
typedef    unsigned int      uint; 
typedef    unsigned short    uInt16;
uint crc;                  // CRC 码
uint crc16l(uchar *ptr,uchar len)        // ptr 为数据指针，len 为数据长度 
{ 

uInt16 i,j,tmp,CRC16;

CRC16=0xffff;
for (i=0;i<len;i++)
{  
    CRC16=*ptr^CRC16;
    for (j=0;j< 8;j++)
        {
            tmp=CRC16 & 0x0001;
            CRC16 =CRC16 >>1;
            if (tmp)
            CRC16=CRC16 ^ 0xa001;    
        }
        *ptr++;
    }

    return(CRC16);
}

int GetCmdValue(char *file, char *key, char *value, int lenth)
{
	dictionary  *   ini ;
	ini = iniparser_load(file);
	
    if (ini==NULL) {
        fprintf(stderr, "cannot parse file: %s\n", file);
        return FALSE ;
    }
	strcpy(value, iniparser_getstring(ini, key, ""));
	//printf("keystr: \"%s\" ; value: %s.", key, value);
	iniparser_freedict(ini);
	return TRUE;
}

char * getAlarmStr(unsigned char ev)
{
    switch(ev)
    {
        case 0x00:
            return "Hey Zycoo";
        case 0x01:
            return "Intruder";
        case 0x02:
            return "Assault";
        case 0x03:
            return "Code Gray";
        case 0x04:
            return "Lockdown";
        case 0x05:
            return "Shooter";
        case 0x06:
            return "Code Silver";
        case 0x07:
            return "Evacuare";
        case 0x08:
            return "Code Orange";
        case 0x09:
            return "Fire";
        case 0x0a:
            return "Code Red";
        case 0x0b:
            return "Injure";
        case 0x0c:
            return "Medical Emergency";
        case 0x0d:
            return "Code Blue";
        case 0x0e:
            return "Code Yellow";
        case 0x0f:
            return "Code Black";
        case 0x10:
            return "Code Green";
        case 0x11:
            return "Nine one one";
        case 0x12:
            return "One one Two";
        case 0x13:
            return "Nine nine nine";
        case 0x14:
            return "SOS";
        case 0x15:
            return "ABC";
        case 0x16:
            return "Call One-O-One";
        case 0x17:
            return "Call One-O-Two";
        case 0x18:
            return "Call One-O-Three";
        case 0x19:
            return "Call One-O-Four";
        case 0x1a:
            return "Call One-O-Five";
        case 0x1b:
            return "Call One-O-Six";
        case 0x1c:
            return "Call One-O-Seven";
        case 0x1d:
            return "Call One-O-Eight";
        case 0x1e:
            return "Call One-O-Nine";
        case 0x1f:
            return "Call Security";
        case 0x20:
            return "Play Audio One";
        case 0x21:
            return "Play Audio Two";
        case 0x22:
            return "Play Audio Three";
        case 0x23:
            return "Play Audio Four";
        case 0x24:
            return "Play Audio Five";
    }
}

void writeLog(char *type,char *action, char *remark)
{
	char logstr[256];
	sprintf(logstr, "%s,%s,%s", type, action, remark);
    redisReply *pReply;
    pReply = redisCommand(pctlContext, "LPUSH writelog-channel %s", logstr);

    freeReplyObject(pReply);
}

//发送控制指令
void control_cmd(char *cmd)
{
    redisReply * pReply;
    pReply = redisCommand( pctlContext, "LPUSH control-channel %s", cmd );

    freeReplyObject( pReply );
}

//发送屏幕显示指令
void screen_control(const char *cmd)
{
    redisReply * pReply;
    pReply = redisCommand( pctlContext, "PUBLISH screen-channel %s", cmd );

    freeReplyObject( pReply );
}


//发送控制指令
void relay_cmd(char *cmd)
{
    redisReply * pReply;
    pReply = redisCommand( pctlContext, "LPUSH output-channel %s", cmd );

    freeReplyObject( pReply );
}

void outputControl(int enable){
    char cmd[64];
    if(enable){
        sprintf(cmd,"{\"id\":\"gpio67\",\"type\":\"On\"}");
        relay_cmd(cmd);
    }
    else
    {
        sprintf(cmd,"{\"id\":\"gpio67\",\"type\":\"Off\"}");
        relay_cmd(cmd);
    }
}

//解析订阅状态
void ProcessReply( redisReply * pReply )
{
    redisReply * pSubReply = NULL;

    if ( pReply != NULL && pReply->elements == 3 )
    {
        pSubReply = pReply->element[2];
        //printf( "Msg [%s]", pSubReply->str );
        cJSON *pJson =  cJSON_Parse(pSubReply->str);
        if ( pJson ) {
            if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "incoming") == 0 &&
                strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_ESTABLISHED") == 0)
            {
                BARESIP_STATUS = INUSE;
            }
            else if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "outgoing") == 0 &&
                strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_ESTABLISHED") == 0)
            {
                BARESIP_STATUS = INUSE;
            }
            else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_CLOSED") == 0)
            {
                BARESIP_STATUS = IDLE;
            }
            else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_INCOMING") == 0)
            {
                BARESIP_STATUS = RING;
            }
            else if(strcmp(cJSON_GetObjectItem(pJson, "direction")->valuestring, "outgoing") == 0 &&
                strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "CALL_OUTGOING") == 0)
            {
                BARESIP_STATUS = RINGING;
            }
            else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "REGISTER_OK") == 0)
            {
                //如果是注册成功点亮指示灯
                char enac1[8],enac2[8],enac3[8],accountaor1[192], accountaor2[192], accountaor3[192];
                char account1[32], domain1[128], account2[32], domain2[128], account3[32], domain3[128];
                if(BARESIP_STATUS == OFFLINE || BARESIP_STATUS == DIALING || strcmp(cJSON_GetObjectItem(pJson, "class")->valuestring, "init register") == 0)
                {
                    BARESIP_STATUS = IDLE;
                }
				if(cJSON_GetObjectItem(pJson, "accountaor") != NULL)
				{
					GetCmdValue(SPK_CONF, "account_info_1:enable", enac1, sizeof(enac1));
					if(strcmp(enac1, "yes") == 0 && ACCOUNT1_REG == REGISTER_FAIL)
					{
						GetCmdValue(SPK_CONF, "account_info_1:username", account1, sizeof(account1));
						GetCmdValue(SPK_CONF, "account_info_1:domain", domain1, sizeof(domain1));
                        if(strlen(domain1) == 0)
                        {
                            GetCmdValue(SPK_CONF, "account_info_1:server", domain1, sizeof(domain1));
                        }
						memset(accountaor1, '\0', sizeof(accountaor1));
						sprintf(accountaor1, "sip:%s@%s", account1, domain1);
						if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor1) == 0)
						{
							ACCOUNT1_REG = REGISTER_OK;
							cJSON_Delete(pJson);
							return;
						}
					}
					GetCmdValue(SPK_CONF, "account_info_2:enable", enac2, sizeof(enac2));
					if(strcmp(enac2, "yes") == 0 && ACCOUNT2_REG == REGISTER_FAIL)
					{
						GetCmdValue(SPK_CONF, "account_info_2:username", account2, sizeof(account2));
						GetCmdValue(SPK_CONF, "account_info_2:domain", domain2, sizeof(domain2));
                        if(strlen(domain2) == 0)
                        {
                            GetCmdValue(SPK_CONF, "account_info_2:server", domain2, sizeof(domain2));
                        }
						memset(accountaor2, '\0', sizeof(accountaor2));
						sprintf(accountaor2, "sip:%s@%s", account2, domain2);
						if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor2) == 0)
						{
							ACCOUNT2_REG = REGISTER_OK;
							cJSON_Delete(pJson);
							return;
						}
					}
					GetCmdValue(SPK_CONF, "account_info_3:enable", enac3, sizeof(enac3));
					if(strcmp(enac3, "yes") == 0 && ACCOUNT3_REG == REGISTER_FAIL)
					{
						GetCmdValue(SPK_CONF, "account_info_3:username", account3, sizeof(account3));
						GetCmdValue(SPK_CONF, "account_info_3:domain", domain3, sizeof(domain3));
                        if(strlen(domain3) == 0)
                        {
                            GetCmdValue(SPK_CONF, "account_info_3:server", domain3, sizeof(domain3));
                        }
						memset(accountaor3, '\0', sizeof(accountaor3));
						sprintf(accountaor3, "sip:%s@%s", account3, domain3);
						if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor3) == 0)
						{
							ACCOUNT3_REG = REGISTER_OK;
							cJSON_Delete(pJson);
							return;
						}
					}
				}
            }
            else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "REGISTER_FAIL") == 0 )
            {
                char enac1[8],enac2[8],enac3[8],accountaor1[192], accountaor2[192], accountaor3[192];
                char account1[32], domain1[128], account2[32], domain2[128], account3[32], domain3[128];

				if(cJSON_GetObjectItem(pJson, "accountaor") != NULL)
				{
					GetCmdValue(SPK_CONF, "account_info_1:enable", enac1, sizeof(enac1));
					if(strcmp(enac1, "yes") == 0 && ACCOUNT1_REG == REGISTER_OK)
					{
						GetCmdValue(SPK_CONF, "account_info_1:username", account1, sizeof(account1));
						GetCmdValue(SPK_CONF, "account_info_1:domain", domain1, sizeof(domain1));
                        if(strlen(domain1) == 0)
                        {
                            GetCmdValue(SPK_CONF, "account_info_1:server", domain1, sizeof(domain1));
                        }
						memset(accountaor1, '\0', sizeof(accountaor1));
						sprintf(accountaor1, "sip:%s@%s", account1, domain1);
						if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor1) == 0)
						{
							ACCOUNT1_REG = REGISTER_FAIL;
                            if( ACCOUNT2_REG == REGISTER_FAIL && ACCOUNT3_REG == REGISTER_FAIL && ACCOUNTP2P_REG == REGISTER_FAIL ){
                                BARESIP_STATUS = OFFLINE;
                            }
							cJSON_Delete(pJson);
							return;
						}
					}
					GetCmdValue(SPK_CONF, "account_info_2:enable", enac2, sizeof(enac2));
					if(strcmp(enac2, "yes") == 0 && ACCOUNT2_REG == REGISTER_OK)
					{
						GetCmdValue(SPK_CONF, "account_info_2:username", account2, sizeof(account2));
						GetCmdValue(SPK_CONF, "account_info_2:domain", domain2, sizeof(domain2));
                        if(strlen(domain2) == 0)
                        {
                            GetCmdValue(SPK_CONF, "account_info_2:server", domain2, sizeof(domain2));
                        }
						memset(accountaor2, '\0', sizeof(accountaor2));
						sprintf(accountaor2, "sip:%s@%s", account2, domain2);
						if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor2) == 0)
						{
                            ACCOUNT2_REG = REGISTER_FAIL;
                            if( ACCOUNT1_REG == REGISTER_FAIL && ACCOUNT3_REG == REGISTER_FAIL && ACCOUNTP2P_REG == REGISTER_FAIL ){
                                BARESIP_STATUS = OFFLINE;
                            }
							cJSON_Delete(pJson);
							return;
						}
					}
					GetCmdValue(SPK_CONF, "account_info_3:enable", enac3, sizeof(enac3));
					if(strcmp(enac3, "yes") == 0 && ACCOUNT3_REG == REGISTER_OK)
					{
						GetCmdValue(SPK_CONF, "account_info_3:username", account3, sizeof(account3));
						GetCmdValue(SPK_CONF, "account_info_3:domain", domain3, sizeof(domain3));
                        if(strlen(domain3) == 0)
                        {
                            GetCmdValue(SPK_CONF, "account_info_3:server", domain3, sizeof(domain3));
                        }
						memset(accountaor3, '\0', sizeof(accountaor3));
						sprintf(accountaor3, "sip:%s@%s", account3, domain3);
						if (strcmp(cJSON_GetObjectItem(pJson, "accountaor")->valuestring, accountaor3) == 0)
						{
                            ACCOUNT3_REG = REGISTER_FAIL;
                            if( ACCOUNT1_REG == REGISTER_FAIL && ACCOUNT2_REG == REGISTER_FAIL && ACCOUNTP2P_REG == REGISTER_FAIL ){
                                BARESIP_STATUS = OFFLINE;
                            }
							cJSON_Delete(pJson);
							return;
						}
					}
				}
            }
            else if(strcmp(cJSON_GetObjectItem(pJson, "type")->valuestring, "EXIT") == 0)
            {
                BARESIP_STATUS = OFFLINE;
            }
            else if(cJSON_GetObjectItem(pJson, "event")->type == 1 && cJSON_GetObjectItem(pJson, "event")->valueint == 0){
                if(strncmp(cJSON_GetObjectItem(pJson, "data")->valuestring,"\n--- User Agents",16) == 0)
                {
                    char p2penable[8];
                    GetCmdValue(SPK_CONF, "account_info_p2p:enable", p2penable, sizeof(p2penable));
                    if(strcmp(p2penable,"yes") == 0)
                    {
                        BARESIP_STATUS = IDLE;
                        if(ACCOUNTP2P_REG == REGISTER_FAIL)
                        {
                            ACCOUNTP2P_REG = REGISTER_OK;
                        }
                    }
                    else if(ACCOUNTP2P_REG == REGISTER_OK)
                    {
                        ACCOUNTP2P_REG = REGISTER_FAIL;
                    }
                }
            }
            cJSON_Delete(pJson);
        }else{
            printf( "parse failed!\n");
        }
    }
}

/*
* 订阅baresip实时状态.
*/
void *baresip_status()
{
    redisContext * pContext = redisConnect( "127.0.0.1", 6379 );

    if ( NULL == pContext || pContext->err == 1 )
    {
        printf( "%s\n", pContext->errstr );
        exit( -1 );
    }

    char * pKey = "session-channel";

    redisReply * pReply = redisCommand( pContext, "SUBSCRIBE %s", pKey );
    freeReplyObject( pReply );
    while ( redisGetReply( pContext, (void **)&pReply ) == REDIS_OK )
    {
        ProcessReply(pReply );
        freeReplyObject( pReply );
    }

    redisFree( pContext );
}

int get_line(int * line_id)
{
	char enac[8], strtmp[32];
	int id = 0;

	memset(line_id,-1,sizeof(line_id));
	for(int i = 1; i < 4;i ++)
	{
		bzero(strtmp, sizeof(strtmp));
		sprintf(strtmp,"account_info_%d:enable",i);
		GetCmdValue(SPK_CONF, strtmp, enac, sizeof(enac));
		if(strcmp(enac,"yes") == 0)
		{
			line_id[i] = id;
			id ++;
		}
	}
	return TRUE;
}

//按键动作
void outbound_call(char *exten, char *onekey_line)
{
    char cmd[256], strtmp[32];;
    int line_id[4];

    if(DEBUG)
        printf( "BARESIP_STATUS [%d]\n", BARESIP_STATUS );

    switch(BARESIP_STATUS)
    {
        case IDLE:
            if(strlen(exten) == 0) 
            {
                BARESIP_STATUS = IDLE;
                break;
            }
            
            get_line(line_id);
            if(strcmp(onekey_line,"auto") == 0)
            {
                if(DEBUG)
                    printf("ACCOUNT1 is %d, ACCOUNT2 is %d, ACCOUNT3 is %d\n",ACCOUNT1_REG,ACCOUNT2_REG,ACCOUNT3_REG);
                if(ACCOUNT1_REG == REGISTER_OK)
                {
                    if(line_id[1] == -1) break;
                    sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",exten, line_id[1]);
                }
                else if(ACCOUNT2_REG == REGISTER_OK)
                {
                    if(line_id[2] == -1) break;
                    sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",exten, line_id[2]);
                }
                else if(ACCOUNT3_REG == REGISTER_OK)
                {
                    if(line_id[3] == -1) break;
                    sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",exten, line_id[3]);
                }
                else
                {
                    break;
                }
            }
            else if (strcmp(onekey_line, "account_info_1") == 0)
            {
                if(line_id[1] == -1 || ACCOUNT1_REG != REGISTER_OK) break;
                sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",exten, line_id[1]);
            }
            else if (strcmp(onekey_line, "account_info_2") == 0)
            {
                if(line_id[2] == -1 || ACCOUNT2_REG != REGISTER_OK) break;
                sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",exten, line_id[2]);
            }
            else if (strcmp(onekey_line, "account_info_3") == 0)
            {
                if(line_id[3] == -1 || ACCOUNT3_REG != REGISTER_OK) break;
                sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",exten, line_id[3]);
            }
            else if(strcmp(onekey_line,"p2p") == 0)
            {
                sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s\"}",exten);
            }
            
            if(DEBUG)
                printf( "dial [%s]\n", cmd );
            control_cmd(cmd);
            sprintf(strtmp, "%s <%s>", exten, onekey_line);
            writeLog( FUN, "AI Call", strtmp );
            break;
    }
}

void action_url(char *url)
{
    char cmd[320];
    sprintf(cmd,"curl -k --connect-timeout 2 '%s' 2>/dev/null &",url);
    if(DEBUG)
        printf( "Command: %s\n", cmd);
    system(cmd);
    writeLog( FUN, "HTTP Request", url );
}

int conf_parse(ai_conf *ev_action, unsigned char event)
{
    char conf_str[256], strtmp[32];
    int state = OFF;
    //if(event < 0x0f)
    sprintf(strtmp, "ai_settings:ai_%02X", event);
    // else
    //     sprintf(strtmp, "call_settings:ai_%02X", event);
    GetCmdValue(SPK_CONF, strtmp, conf_str, sizeof(conf_str));
    if(DEBUG) printf("[%s]\n",conf_str);
    cJSON *pJson =  cJSON_Parse(conf_str);
    if(pJson == NULL)
    {
        cJSON_Delete(pJson);
        return state;
    }
    cJSON *call = cJSON_GetObjectItem(pJson, "call");
    if(cJSON_IsObject(call))
    {
        cJSON *num = cJSON_GetObjectItem(call, "num");
        cJSON *line = cJSON_GetObjectItem(call, "line");
        if(!cJSON_IsNull(num) && !cJSON_IsNull(line))
        {
            ev_action->call_en = ON;
            strcpy(ev_action->call_num, num->valuestring);
            strcpy(ev_action->call_line, line->valuestring);
            state = ON;
        }
    }
    cJSON *http = cJSON_GetObjectItem(pJson, "http");
    if(!cJSON_IsNull(http))
    {
        ev_action->http_en = ON;
        strcpy(ev_action->http_url, cJSON_GetArrayItem(http,0)->valuestring);
        state = ON;
    }

    cJSON *relay = cJSON_GetObjectItem(pJson, "relay");
    if(!cJSON_IsNull(relay))
    {
        ev_action->relay_en = ON;
        ev_action->relay_duration = relay->valueint;
        state = ON;
    }

    cJSON *screen = cJSON_GetObjectItem(pJson, "screen");
    if(cJSON_IsObject(screen))
    {
        cJSON *id = cJSON_GetObjectItem(screen, "id");
        cJSON *duration = cJSON_GetObjectItem(screen, "duration");
        if(!cJSON_IsNull(id) && !cJSON_IsNull(duration))
        {
            ev_action->screen_en = ON;
            ev_action->screen_id = id->valueint;
            ev_action->screen_duration = duration->valueint;
            state = ON;
        }
    }
    cJSON_Delete(pJson);
    return state;
}

//gpio延时控制
void *gpioDelayControl()
{
    char cmd[128];
    usleep(delay*1000*1000);
    outputControl(OFF);
    if(DEBUG)
        printf( "gpio135 set off\n" );
}

//srceen延时控制
void *screenDelayControl(void *arg)
{
    char strtmp[64];
    ai_conf *ev = arg;
    usleep(ev->screen_duration*1000*1000);
    
    sprintf(strtmp, "{\"action\": \"off\", \"id\": %d}", ev->screen_id);
    screen_control(strtmp);
    if(DEBUG)
        printf( "screen set off\n" );
    free(ev);
}

void event_action(unsigned char event)
{
    char cmd[2048];
//    int line_id[4];
//	int year, month, hour, otherId;
//	time_t nSeconds;
//	struct tm *pTM;
    ai_conf *ev_action = malloc(sizeof(ai_conf));

    memset(ev_action, 0, sizeof(ai_conf));

    writeLog( FUN, "AI Detect", getAlarmStr(event) );
    if(conf_parse(ev_action, event) == OFF)
    {
        free(ev_action);
        return;
    }

    writeLog( FUN, "AI Trigger", getAlarmStr(event) );

    if(ev_action->call_en)
    {
        outbound_call(ev_action->call_num, ev_action->call_line);
    }

    if(ev_action->http_en)
    {
        action_url(ev_action->http_url);
    }

    if(ev_action->relay_en)
    {
        outputControl(ON);
        if(ev_action->relay_duration > 0)
        {
            int ret_thrd_delay;
            pthread_t thread_delay;
            delay = ev_action->relay_duration;
            ret_thrd_delay = pthread_create(&thread_delay, NULL, gpioDelayControl, NULL);
            if (ret_thrd_delay != 0) {
                printf("create thread_delay gpioDelayControl failed\n");
            }
        }
    }

    if(ev_action->screen_en)
    {
        int ret_thrd_delay;
        pthread_t thread_delay;
        char strtmp[64];
        sprintf(strtmp,"{\"action\": \"on\", \"id\": %d}",ev_action->screen_id);
        screen_control(strtmp);
        ret_thrd_delay = pthread_create(&thread_delay, NULL, screenDelayControl, ev_action);
        if (ret_thrd_delay != 0) {
            printf("create thread_delay screenDelayControl failed\n");
        }
    }
    else
        free(ev_action);
}

/*
    GetCmdValue(SPK_CONF, "ai_settings:url", url, sizeof(url));
    GetCmdValue(SPK_CONF, "ai_settings:username", username, sizeof(username));
    GetCmdValue(SPK_CONF, "ai_settings:password", password, sizeof(password));
    GetCmdValue(SPK_CONF, "ai_settings:location", location, sizeof(location));
    if(strlen(url) == 0) return;

	time(&nSeconds);
	pTM = localtime(&nSeconds);
	year = pTM->tm_year + 1900;
	month = pTM->tm_mon + 1;
	sprintf(datetime, "%d-%02d-%02d %02d:%02d:%02d", year, month, pTM->tm_mday, pTM->tm_hour, pTM->tm_min, pTM->tm_sec);

    otherId = 10000 + event;

    sprintf(cmd,"curl -H \"Accept: application/json\" -H \"Content-type: application/json\" \
-X POST -u %s:%s -k --connect-timeout 1 '%s/open/receiveApi/other/receiveData' -d \
'{\
\"otherId\":\"%d\",\
\"eventType\":\"190001\",\
\"eventName\":\"霸凌检测\",\
\"eventAddr\":\"%s\", \
\"deviceIndexCode\":\"%s\",\
\"alarmTime\":\"%s\",\
\"alarmWord\":\"%s\"\
}' 2>/dev/null &",username, password, url, otherId, location, deviceId, datetime, getAlarmStr(event));
    if(DEBUG)
        printf( "Command: %s\n", cmd);
    system(cmd);
    
    if(BARESIP_STATUS != IDLE) return;
    GetCmdValue(SPK_CONF, "input_detect:trigger_num", trigger_num, sizeof(trigger_num));
    GetCmdValue(SPK_CONF, "input_detect:trigger_line", trigger_line, sizeof(trigger_line));
    if(strlen(trigger_num) == 0) 
    {
        return;
    }
    get_line(line_id);
    if(strcmp(trigger_line,"auto") == 0)
    {
        if(DEBUG)
            printf("ACCOUNT1 is %d, ACCOUNT2 is %d, ACCOUNT3 is %d\n",ACCOUNT1_REG,ACCOUNT2_REG,ACCOUNT3_REG);
        if(ACCOUNT1_REG == REGISTER_OK)
        {
            if(line_id[1] == -1) return;
            sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",trigger_num, line_id[1]);
        }
        else if(ACCOUNT2_REG == REGISTER_OK)
        {
            if(line_id[2] == -1) return;
            sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",trigger_num, line_id[2]);
        }
        else if(ACCOUNT3_REG == REGISTER_OK)
        {
            if(line_id[3] == -1) return;
            sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",trigger_num, line_id[3]);
        }
        else
        {
            return;
        }
    }
    else if (strcmp(trigger_line, "account_info_1") == 0)
    {
        if(line_id[1] == -1 || ACCOUNT1_REG != REGISTER_OK) return;
        sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",trigger_num, line_id[1]);
    }
    else if (strcmp(trigger_line, "account_info_2") == 0)
    {
        if(line_id[2] == -1 || ACCOUNT2_REG != REGISTER_OK) return;
        sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",trigger_num, line_id[2]);
    }
    else if (strcmp(trigger_line, "account_info_3") == 0)
    {
        if(line_id[3] == -1 || ACCOUNT3_REG != REGISTER_OK) return;
        sprintf(cmd,"{\"cmd\":\"dial\",\"data\":\"%s %d\"}",trigger_num, line_id[3]);
    }
    control_cmd(cmd);
    sprintf(strtmp, "%s <%s>", trigger_num, trigger_line);
    writeLog( FUN, "AI Trigger Call", strtmp );
}
*/


/*
*	@解析协议数据
*/
void AnalyseData(char *buf, int len)
{
	unsigned char data[8];
    char url[256];
    memset(data,'\0',sizeof(data));
    for(int i=0; i<len; i++)
    {
        data[i] = buf[i];
        if(buf[i] == 0xFE)
            break;
    }
    if(data[2] == 0x0B)
    {
        switch(data[1])
        {
            case 0x01:
                if(DEBUG) printf("=====> Intruder <=====\n");
                event_action(data[1]);
            break;
            case 0x02:
                if(DEBUG) printf("=====> Assault <=====\n");
                event_action(data[1]);
            break;
            case 0x03:
                if(DEBUG) printf("=====> Code Gray <=====\n");
                event_action(data[1]);
            break;
            case 0x04:
                if(DEBUG) printf("=====> Lockdown <=====\n");
                event_action(data[1]);
            break;
            case 0x05:
                if(DEBUG) printf("=====> Shooter <=====\n");
                event_action(data[1]);
            break;
            case 0x06:
                if(DEBUG) printf("=====> Code Silver <=====\n");
                event_action(data[1]);
            break;
            case 0x07:
                if(DEBUG) printf("=====> Evacuare <=====\n");
                event_action(data[1]);
            break;
            case 0x08:
                if(DEBUG) printf("=====> Code Orange <=====\n");
                event_action(data[1]);
            break;
            case 0x09:
                if(DEBUG) printf("=====> Fire <=====\n");
                event_action(data[1]);
            break;
            case 0x0a:
                if(DEBUG) printf("=====> Code Red <=====\n");
                event_action(data[1]);
            break;
            case 0x0b:
                if(DEBUG) printf("=====> Injure <=====\n");
                event_action(data[1]);
            break;
            case 0x0c:
                if(DEBUG) printf("=====> Medical Emergency <=====\n");
                event_action(data[1]);
            break;
            case 0x0d:
                if(DEBUG) printf("=====> Code Blue <=====\n");
                event_action(data[1]);
            break;
            case 0x0e:
                if(DEBUG) printf("=====> Code Yellow <=====\n");
                event_action(data[1]);
            break;
            case 0x0f:
                if(DEBUG) printf("=====> Code Black <=====\n");
                event_action(data[1]);
            break;
            case 0x10:
                if(DEBUG) printf("=====> Code Green <=====\n");
                event_action(data[1]);
            break;
            //dial extension
            case 0x11:
                if(DEBUG) printf("=====> Nine one one <=====\n");
                event_action(data[1]);
            break;
            case 0x12:
                if(DEBUG) printf("=====> One one Two <=====\n");
                event_action(data[1]);
            break;
            case 0x13:
                if(DEBUG) printf("=====> Nine nine nine <=====\n");
                event_action(data[1]);
            break;
            case 0x14:
                if(DEBUG) printf("=====> SOS <=====\n");
                event_action(data[1]);
            break;
            case 0x15:
                if(DEBUG) printf("=====> ABC <=====\n");
                event_action(data[1]);
            break;
            case 0x00:
                if(DEBUG) printf("=====> Hey Z-echo <=====\n");
                event_action(data[1]);
            break;
            case 0x16:
                if(DEBUG) printf("=====> Call One-O-One <=====\n");
                event_action(data[1]);
            break;
            case 0x17:
                if(DEBUG) printf("=====> Call One-O-Two <=====\n");
                event_action(data[1]);
            break;
            case 0x18:
                if(DEBUG) printf("=====> Call One-O-Three <=====\n");
                event_action(data[1]);
            break;
            case 0x19:
                if(DEBUG) printf("=====> Call One-O-Four <=====\n");
                event_action(data[1]);
            break;
            case 0x1a:
                if(DEBUG) printf("=====> Call One-O-Five <=====\n");
                event_action(data[1]);
            break;
            case 0x1b:
                if(DEBUG) printf("=====> Call One-O-Six <=====\n");
                event_action(data[1]);
            break;
            case 0x1c:
                if(DEBUG) printf("=====> Call One-O-Seven <=====\n");
                event_action(data[1]);
            break;
            case 0x1d:
                if(DEBUG) printf("=====> Call One-O-Eight <=====\n");
                event_action(data[1]);
            break;
            case 0x1e:
                if(DEBUG) printf("=====> Call One-O-Nine <=====\n");
                event_action(data[1]);
            break;
            case 0x1f:
                if(DEBUG) printf("=====> Call Security <=====\n");
                event_action(data[1]);
            break;
            case 0x20:
                if(DEBUG) printf("=====> Play Audio One <=====\n");
                event_action(data[1]);
            break;
            case 0x21:
                if(DEBUG) printf("=====> Play Audio Two <=====\n");
                event_action(data[1]);
            break;
            case 0x22:
                if(DEBUG) printf("=====> Play Audio Three <=====\n");
                event_action(data[1]);
            break;
            case 0x23:
                if(DEBUG) printf("=====> Play Audio Four <=====\n");
                event_action(data[1]);
            break;
            case 0x24:
                if(DEBUG) printf("=====> Play Audio Five <=====\n");
                event_action(data[1]);
            break;
        }
        if(data[1] > 0x0e)
        {
            //led_control("LED_OFF");
        }
    }
    else if(data[2] == 0x0B)
    {
        switch(data[1])
        {
            case 0x01:
                if(DEBUG) printf("=====> 小智小智 <=====\n");
                system("/etc/scripts/pa_mute.sh 0");
                control_cmd("{\"cmd\":\"play\",\"data\":\"callwaiting.wav\"}");
                //led_control("LED_FAST");
            break;
            case 0x02:
                if(DEBUG) printf("=====> 你好智科 <=====\n");
                system("/etc/scripts/pa_mute.sh 0");
                control_cmd("{\"cmd\":\"play\",\"data\":\"callwaiting.wav\"}");
                //led_control("LED_FAST");
            break;
            case 0x00:
                if(DEBUG) printf("=====> 退出唤醒 <=====\n");
                //led_control("LED_OFF");
            break;
        }
    }

}

void consoleRead(int fd)
{
    char buff[128];   
    int nread, i;
    while(1)  
    {  
        if((nread = read(fd, buff, 128)) > 0)
        { 
            if(DEBUG){ 
                printf("Len: %d\n",nread);
                for(i=0; i<nread; i++)
                    printf("buff[%d] = %02x\n",i, buff[i]);
            }
            if(buff[0] == 0xFF && buff[3] == 0xFE)
            {
                AnalyseData(buff, nread);
            }
        }
    }
}
  
int main(int argc, char *argv[])  
{
    int ret_thrd1;
    pthread_t thread1;
    char macaddr[16];
    int fd;
    if (argc == 2 && strcmp(argv[1], "debug") == 0)
        DEBUG = ON;

	fd = open("/dev/ttyS4", O_RDWR); 
    if(fd == -1) {  
        printf("serialport error\n");  
    }  
    else {  
        printf("open %s succesfully\n", ttyname(fd));  
    }  
  
    set_speed(fd,9600);
      
    if (set_Parity(fd,8,1,'N') == FALSE)  {  
        printf("Set Parity Error\n");  
        exit (0);  
    }


    pctlContext = redisConnect("127.0.0.1", 6379);

    if (NULL == pctlContext || pctlContext->err == 1)
    {
        printf("%s\n", pctlContext->errstr);
        return 0;
    }


 //   if(get_mac(macaddr))
 //       strcpy(deviceId, macaddr);

    //启动线程订阅BARESIP实时状态
    ret_thrd1 = pthread_create(&thread1, NULL, baresip_status, NULL);
    if (ret_thrd1 != 0) {
        printf("create thread1 baresip_status failed");
        return 0;
    }

    //按键和灯的控制
    consoleRead(fd);
    
    close(fd); 
    redisFree( pctlContext );
    return 0;  
} 
