#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "JsonParser.h" #include "hashmap.h" #include "HashTable.h" #include "SystemLogMessage.h" #include "ShareMemory.h" #include #include "MessageHandler.h" #include "sqlite3.h" #define Debug //#define ARRAY_SIZE(A) (sizeof(A) / sizeof(A[0])) #define PASS 1 #define FAIL -1 //========================================== // Function prototype //========================================== void trim(char *s); int mystrcmp(char *p1,char *p2); void substr(char *dest, const char* src, unsigned int start, unsigned int cnt); void getSubStr(char *dest, char* src, char *split, int idx); void split(char **arr, char *str, const char *del); int strpos(char *source, char *substr, int skip); int strposs(char *source, char *substr, int idx); char *random_uuid( char buf[37] ); static int OCPP16Callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); char * strchr(const char *p, int ch); void ClientCoreProfile(HashTable* HandleRequest, HashTable* Handleresponse); void createq(); int showfront(char *uuid, char *data); int addq(char *uuid, char *data) ; int delq(); int sentqueue(); void CheckTransactionPacket(char *uuid); int queue_operation(int type, char *frontUUID, char *frontData); //========================================== // Variables Annoucement //========================================== pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t lock_sentData = PTHREAD_MUTEX_INITIALIZER; HashTable *tableHandleRequest; HashTable *tableHandleresponse; HashTable *tableHandleError ; extern struct OCPP16Data *ShmOCPP16Data; struct lws *wsi_client; struct lws_context *context; static int sendbuffer = 0; extern int server_sign; extern int server_pending; extern void CheckSystemValue(void); unsigned char *SendBuffer; int SendBufLen=(1024*4);//(1024*3); int ConnectionEstablished=0; int defaultWaitingTime = 10; //10 second extern int BootNotificationInterval; map_t hashMap; data_struct_t* mapItem; sqlite3 *db; char *errMsg = NULL; struct _node { char uuid[37]; char data[2000]; struct node *next; }node; typedef struct _node *pnode; pnode front, rear; struct StartTime { unsigned int connect; unsigned int bootNotification; }startTime; static char *createsql = "CREATE TABLE IF NOT EXISTS log_buffer(" "idx integer primary key," "user_id text," "cmd_sn text," "charger_id text," "gun_type text," "gun_no text," "rfid_no text," "stime text," "etime text," "time_len text," "s_soc text," "e_soc text," "stop_reason text," "power text," "meter_before text," "meter_after text," "charge_price text," "reserve text," "surplus_before text," "surplus_after text," "service_price text," "is_pay text," "charge_strategy text," "charge_parameter text," "vin text," "vehicle_no text," "start_method text," "card_type text," "is_upload text," "guid text UNIQUE," "is_buf2OK text);"; static char *createsChargingRecordsql = "CREATE TABLE IF NOT EXISTS ChargingRecord(" "idx integer primary key," "gun_type text," "connectorId text," "idTag text," "transactionId text," "stime text," "etime text," "time_len text," "s_soc text," "e_soc text," "stop_reason text," "power text," "meter_before text," "meter_after text," "reservationId text," "guid text UNIQUE);"; //"is_buf2OK text);"; static char *sqlOcppAuthCache = "create table if not exists ocpp_auth_cache (idx integer primary key," "idtag text UNIQUE," "parent_idtag text," "expir_date text," "status text);"; static char *sqlOcppAuthLocal = "create table if not exists ocpp_auth_local (idx integer primary key," "idtag text UNIQUE," "parent_idtag text," "expir_date text," "status text," "version text);"; static char *sqlInitialOcppAuthLocal = "insert or replace into ocpp_auth_local(idtag, parent_idtag, expir_date, status, version) values('PaHdImHiOnNG','none','2099-12-31T23:59:59.999Z','Accepted','0')"; int DiffTimeb(struct timeb ST, struct timeb ET) { //return milli-second unsigned int StartTime,StopTime; StartTime=(unsigned int)ST.time; StopTime=(unsigned int)ET.time; return (StopTime-StartTime)*1000+ET.millitm-ST.millitm; } //================================= // Common routine //================================= void trim(char *s) { int i=0, j, k, l=0; while((s[i]==' ')||(s[i]=='\t')||(s[i]=='\n')) i++; j = strlen(s)-1; while((s[j]==' ')||(s[j]=='\t')||(s[j]=='\n')) j--; if(i==0 && j==strlen(s)-1) { } else if(i==0) s[j+1] = '\0'; else { for(k=i; k<=j; k++) s[l++] = s[k]; s[l] = '\0'; } } int mystrcmp(char *p1,char *p2) { while(*p1==*p2) { if(*p1=='\0' || *p2=='\0') break; p1++; p2++; } if(*p1=='\0' && *p2=='\0') return(PASS); else return(FAIL); } void substr(char *dest, const char* src, unsigned int start, unsigned int cnt) { strncpy(dest, src + start, cnt); dest[cnt] = 0; } void getSubStr(char *dest, char* src, char *split, int idx) { int start = (strposs(src,",",idx)+1); int cnt = (strposs(src,",",idx+1)-2)-(strposs(src,",",idx)+1); strncpy(dest, src + start, cnt); dest[cnt] = 0; } void split(char **arr, char *str, const char *del) { char *s = strtok(str, del); while(s != NULL) { *arr++ = s; s = strtok(NULL, del); } } int strpos(char *source, char *substr, int skip) { char stack[strlen(source)]; strncpy(stack, source+skip, strlen(source)-skip); char *p = strstr(stack, substr); if (p) return p - stack+skip; return -1; } int strposs(char *source, char *substr, int idx) { char stack[strlen(source)]; int result=0; int count=0; while(count<=idx) { memset(stack,0,sizeof stack); strncpy(stack, source+result, strlen(source)-result); int loc = strcspn(stack, substr); if(loc>0) result += (loc+1); else result = -1; count++; } return result; } char *random_uuid( char buf[37] ) { const char *c = "89ab"; char *p = buf; int n; for( n = 0; n < 16; ++n ) { int b = rand()%255; switch( n ) { case 6: sprintf(p, "4%x", b%15 ); break; case 8: sprintf(p, "%c%x", c[rand()%strlen(c)], b%15 ); break; default: sprintf(p, "%02x", b); break; } p += 2; switch( n ) { case 3: case 5: case 7: case 9: *p++ = '-'; break; } } *p = 0; return buf; } //========================================== // Web socket tranceive routine //========================================== int SendData(struct lws *wsi) { int n; int len; unsigned char *out = NULL; len = strlen((char *)SendBuffer); out = (unsigned char *)malloc(sizeof(char)*(LWS_SEND_BUFFER_PRE_PADDING + len + LWS_SEND_BUFFER_POST_PADDING)); memcpy (out + LWS_SEND_BUFFER_PRE_PADDING, SendBuffer, len ); n = lws_write(wsi, out + LWS_SEND_BUFFER_PRE_PADDING, len, LWS_WRITE_TEXT); free(out); out = NULL; return n; } static int OCPP16Callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { int MsgType; char UniqueId[37],Action[33],Payload[10241],ErrorCode[129],ErrorDescription[513]; switch (reason) { case LWS_CALLBACK_PROTOCOL_INIT: #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_PROTOCOL_INIT\n"); #endif break; case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH\n"); #endif break; case LWS_CALLBACK_CLOSED_CLIENT_HTTP: #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n"); #endif break; case LWS_CALLBACK_WSI_DESTROY: #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_WSI_DESTROY\n"); #endif server_sign = FALSE; break; case LWS_CALLBACK_LOCK_POLL: #ifdef SystemLogMessage //DEBUG_INFO("LWS_CALLBACK_LOCK_POLL\n"); #endif break; case LWS_CALLBACK_ADD_POLL_FD: #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_ADD_POLL_FD\n"); #endif break; case LWS_CALLBACK_DEL_POLL_FD: #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_DEL_POLL_FD\n"); #endif break; case LWS_CALLBACK_UNLOCK_POLL: #ifdef SystemLogMessage //DEBUG_INFO("LWS_CALLBACK_UNLOCK_POLL\n"); #endif break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: #ifdef SystemLogMessage //DEBUG_INFO("LWS_CALLBACK_CHANGE_MODE_POLL_FD\n"); #endif break; case LWS_CALLBACK_WSI_CREATE: #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_WSI_CREATE\n"); #endif break; case LWS_CALLBACK_GET_THREAD_ID: //#ifdef SystemLogMessage //DEBUG_INFO("LWS_CALLBACK_GET_THREAD_ID\n"); //#endif break; case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER\n"); #endif break; case LWS_CALLBACK_CLIENT_ESTABLISHED://3 #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_CLIENT_ESTABLISHED\n"); #endif //connected ConnectionEstablished=1; break; case LWS_CALLBACK_CLIENT_CONNECTION_ERROR://1 #ifdef Debug DEBUG_ERROR("LWS_CALLBACK_CLIENT_CONNECTION_ERROR:%s\n",in); #endif #ifdef SystemLogMessage DEBUG_ERROR("LWS_CALLBACK_CLIENT_CONNECTION_ERROR\n"); #endif //disconnected ConnectionEstablished=0; break; case LWS_CALLBACK_CLOSED://4 #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_CLOSED\n"); ConnectionEstablished=0; #endif //disconnected break; case LWS_CALLBACK_CLIENT_WRITEABLE://10 //if(need to send message and its relevant data already store into SendBuffer) #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_CLIENT_WRITEABLE\n"); #endif SendData(wsi); break; case LWS_CALLBACK_CLIENT_RECEIVE://8 ((char *)in)[len] = '\0'; #ifdef SystemLogMessage DEBUG_INFO("LWS_CALLBACK_CLIENT_RECEIVE, RX length: %d\n", (int)len); //DEBUG_INFO("Message: %s\n", (char *)in); #endif ReceivedMessage(in, len); break; default: #ifdef Debug DEBUG_INFO("OCPP16Callback:reason=%d\n", reason); #endif break; } return 0; } static struct lws_protocols protocols[] = { { "ocpp1.6", OCPP16Callback, 10240, 10240, }, { "ocpp1.6", OCPP16Callback, 10240, 10240, }, { NULL, NULL, 0 /* End of list */ } }; int ConnectWsServer() { int result = PASS; struct lws_context_creation_info ContextInfo; struct lws_client_connect_info ConnInfo; int use_ssl=0; //lws_set_log_level(LLL_PARSER | LLL_HEADER, NULL); if(context!=NULL) lws_context_destroy(context); memset(&ContextInfo, 0, sizeof(struct lws_context_creation_info)); ContextInfo.port = CONTEXT_PORT_NO_LISTEN; ContextInfo.iface = NULL; ContextInfo.ssl_private_key_password = NULL; ContextInfo.ssl_cert_filepath = NULL; ContextInfo.ssl_private_key_filepath = NULL; ContextInfo.ssl_ca_filepath = "/root/cacert.pem"; ContextInfo.ssl_cipher_list = NULL; //use default one ContextInfo.gid = -1; ContextInfo.uid = -1; if(use_ssl) ContextInfo.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; ContextInfo.protocols = protocols; ContextInfo.timeout_secs = 9999;//30; //if(ping pong enabled) ContextInfo.ws_ping_pong_interval = 30;//0 for none, else interval in seconds context = lws_create_context(&ContextInfo); if (context == NULL) { #ifdef SystemLogMessage DEBUG_ERROR("lws_create_context NG"); #endif result = FAIL; } memset(&ConnInfo,0,sizeof(struct lws_client_connect_info)); // fill up below information ConnInfo.context = context; ConnInfo.address=(const char *)GetOcppServerURL(); ConnInfo.port = GetOcppPort(); ConnInfo.path=(const char *)GetOcppPath(); ConnInfo.host=lws_canonical_hostname(context); ConnInfo.origin="origin"; ConnInfo.protocol = protocols[1].name; ConnInfo.ietf_version_or_minus_one = -1; if(use_ssl) ConnInfo.ssl_connection = LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;; wsi_client = lws_client_connect_via_info(&ConnInfo); if (!wsi_client) { #ifdef SystemLogMessage DEBUG_ERROR("lws_client_connect_via_info NG"); #endif result = FAIL; } printf("6-3\n"); return result; } void createq() { front = rear = (pnode)malloc(sizeof(node)); //front->next = rear->next = NULL; front = rear = NULL; } int showfront(char *uuid, char *data) { pnode p; p = front; if(p) { printf("\n uuid:%s", p->uuid); printf("\n data:%s", p->data); strcpy(uuid,p->uuid); strcpy(data,p->data); return 1; } else { printf("queue is null\n"); strcpy(uuid,""); strcpy(data,""); return 0; } } int addq(char *uuid, char *data) { pnode p = (pnode )malloc(sizeof(node)); if(p) { strcpy(p->uuid, uuid); strcpy(p->data, data); p->next = NULL; if(rear) { rear->next = p; rear = p; } else { front = rear = p; } } else { printf("無法取得記憶體空間新增資料\n"); } printf("addq\n"); return 0; } int delq() { pnode p; if(front) { p = front; if(front->next) front = front->next; else front = rear = NULL; printf("delete uuid: %s data: %s\n", p->uuid, p->data); free(p); } else { printf("queue is Empty\n"); printf("\n delete: queue is null"); } return 0; } int showqueue() { pnode p; p = front; while(p) { printf("uuid: %s data: %s\n", p->uuid, p->data); p = p->next; } return 0; } int sentqueue(){ pnode p; p = front; printf("sentqueue\n"); while(p) { printf("uuid: %s data: %s\n", p->uuid, p->data); LWS_Send(p->data); p = p->next; } printf("sentqueue end\n"); return 0; } int storequeue(){ //write queue to flash unsigned int i,Chk; unsigned char *ptr; int fd,wrd; // Save factory default setting value to flash backup setting block fd = open("/Storage/OCPP/queue.txt", O_RDWR); if (fd < 0) { #ifdef SystemLogMessage DEBUG_ERROR("open /Storage/OCPP/queue.txt NG"); #endif free(ptr); return 0; } wrd=write(fd, &front, sizeof(node)); close(fd); if(wrd!=(sizeof(node))) { #ifdef SystemLogMessage DEBUG_ERROR("write /Storage/OCPP/queue.txt NG"); #endif free(ptr); return 0; } return 0; } // void* processTransactionQueue(void* data) { while(1) { char *frontUUID = (char *)malloc(sizeof(char)* 100); char *frontData = (char *)malloc(sizeof(char)*1024*4); int queueNotEmpty = 0; printf("show front\n"); queueNotEmpty = queue_operation(1,frontUUID, frontData);//showfront(frontUUID, frontData); ---> remove temporally //showfront(); printf("processTransactionQueue\n"); if(queueNotEmpty == 1) { printf("processTransactionQueue queue is not empty!\n"); sendbuffer = 1; } free(frontUUID); free(frontData); sleep(30); // sleep for 30 seconds } pthread_exit(NULL); // ���}�l����� return 0; } void CheckTransactionPacket(char *uuid) { char *frontUUID = (char *)malloc(sizeof(char)* 100); char *frontData = (char *)malloc(sizeof(char)*1024*4); int queueNotEmpty = 0; int cmpResult = 0; printf("CheckTransactionPacket 0\n"); queue_operation(0,"","");//showqueue(); ---> remove temporally queueNotEmpty = queue_operation(1,frontUUID, frontData);//showfront(frontUUID, frontData); ---> remove temporally printf("CheckTransactionPacket 1\n"); if(queueNotEmpty == 1) { cmpResult = strcmp(frontUUID, uuid); if (cmpResult == 0) { printf("All right!\n"); queue_operation(2,"","");//delq(); ---> remove temporally } } free(frontUUID); free(frontData); } /* type: 0 (showqueue ); type: 1(showfront); type: 2(delq) type: 3 (sentqueue) type: 4 (addq) type: 5(store queue to /Storage/OCPP/ )*/ int queue_operation(int type, char *frontUUID, char *frontData) { pthread_mutex_lock(&lock_sentData); int result=0; if(type == 0) result = showqueue(); else if(type == 1) result = showfront(frontUUID, frontData); else if(type == 2) result = delq(); else if(type == 3) result = sentqueue(); else if(type == 4) result = addq(frontUUID, frontData); else if(type == 5) result = storequeue(); pthread_mutex_unlock(&lock_sentData); return result; } char * strchr (const char *p, int ch) { char c; c = ch; for (;; ++p) { if (*p == c) return ((char *)p); if (*p == '\0') return (NULL); } /* NOTREACHED */ } #define SystemLogMessage //================================================ // Main process //================================================ int main(void) { pthread_t t; void *ret; #ifdef SystemLogMessage DEBUG_INFO("Initialization...\n"); #endif if(ProcessShareMemory()== FAIL) { return FAIL; } if((SendBuffer=malloc(SendBufLen))==NULL) { #ifdef SystemLogMessage DEBUG_ERROR("malloc(SendBufLen) NG"); #endif sleep(5); return FAIL; } printf("2\n"); //inital HandleRequest/HandleResponce/HandleError map table tableHandleRequest = HashTableNew(3); tableHandleresponse = HashTableNew(3); tableHandleError = HashTableNew(3); printf("3\n"); ClientCoreProfile(tableHandleRequest, tableHandleresponse); //for uuid map table hashMap = hashmap_new(); mapItem = malloc(sizeof(data_struct_t)); //create queue createq(); //Create Process: Resend Transaction pthread_create(&t, NULL, processTransactionQueue, NULL); if(sqlite3_open("charger.db", &db)) { fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); sqlite3_close( db ); exit(0); } else { fprintf(stderr, "Opened database successfully\n"); } /* 建立 Table log buffer */ int rc =sqlite3_exec(db, createsql, 0, 0, &errMsg); if (SQLITE_OK != rc) { printf("%s\n",errMsg); return 0; } else { fprintf(stderr, "Opened log buffer table successfully\n"); } /* 建立 Table OcppAuthCache */ rc =sqlite3_exec(db, sqlOcppAuthCache, 0, 0, &errMsg); if (SQLITE_OK != rc) { printf("%s\n",errMsg); return 0; } else { fprintf(stderr, "Opened OcppAuthCache table successfully\n"); } /* 建立 Table OcppAuthLocal */ rc =sqlite3_exec(db, sqlOcppAuthLocal, 0, 0, &errMsg); if (SQLITE_OK != rc) { printf("%s\n",errMsg); return 0; } else { fprintf(stderr, "Opened OcppAuthLocal table successfully\n"); } initialConfigurationTable(); for(;;) { while(ConnectionEstablished==0) { if((time((time_t*)NULL)-startTime.connect)>=60) { #ifdef Debug DEBUG_INFO("Execute ConnectWsServer\n"); #endif ConnectWsServer(); startTime.connect=time((time_t*)NULL); } lws_service(context, 10000);//timeout_ms } if(( (BootNotificationInterval != 0 && ((time((time_t*)NULL)-startTime.bootNotification)>=BootNotificationInterval) ) || ((time((time_t*)NULL)- startTime.bootNotification)>=defaultWaitingTime) ) && ((server_sign == FALSE)/*|| (server_pending == TRUE)*/)) { sendBootNotificationRequest(); startTime.bootNotification=time((time_t*)NULL); } if(server_sign == TRUE) { printf("sign in 1\n"); if(sendbuffer == 1) { queue_operation(3, "", ""); sendbuffer = 0; queue_operation(5,"", ""); } // Check System Value CheckSystemValue(); printf("sign in 2\n"); } lws_service(context, 100);//timeout_ms } pthread_join(t, NULL); HashTableFree(tableHandleRequest); HashTableFree(tableHandleresponse); HashTableFree(tableHandleError); hashmap_free(hashMap); free(SendBuffer); return FAIL; }