/*===========================================================================
                    Combined Charging System (CCS): SECC
                             EventLogging.c

                        initiated by Vern, Joseph
                           (since 2019/07/19)
=============================================================================*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/termios.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <linux/sockios.h>
#include <linux/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <math.h>//for pow
#include <unistd.h>
#include "define.h"
#include "EventLogging.h"

//#define Debug

struct SysConfigAndInfo         *ShmSysConfigAndInfo;
struct StatusCodeData           *ShmStatusCodeData;
unsigned char buf_log_eventlogging[SIZE_OF_LOG_BUFFER];

/**************************************************************************************/
/**************************Alarm Share memory**************************************/
/***************************************************************************************
	Status Code	A			B				C									D	E	F
				0: Issue		1: From EVSE 		1: Fault (unrecoverable)					001 ~ 999 serial number
			    								e.g., hardware broken, system latch
				1: Recovered	2: From EV		2: Alarm (recoverable)
			   								e.g., OTP, OVP
							3: From Backend	3: Information
			  								e.g., swipe card to stop charging

according to XXX.Revxx
***************************************************************************************/
/**************************************************************************************/
char FaultStatusCode[32][6]=
{
	"011001",	//CHAdeMO output fuse blew
	"011002",	//CCS output fuse blew
	"011003",	//GB output fuse blew
	"011004",	//RCD/CCID self-test fail
	"011005",	//AC input contactor 1 welding
	"011006",	//AC input contactor 1 driving fault
	"011007",	//AC input contactor 2 welding
	"011008",	//AC input contactor 2 driving fault
	"011009",	//AC output relay welding
	"011010",	//AC output relay  driving fault
	"011011",	//CHAdeMO output relay welding
	"011012",	//CHAdeMO output relay driving fault
	"011013",	//CCS output relay welding
	"011014",	//CCS output relay driving fault
	"011015",	//GB output relay welding
	"011016",	//GB output relay driving fault
	"011017",	//AC connector temperature sensor broken
	"011018",	//CHAdeMO connector temperature sensor broken
	"011019",	//CCS connector temperature sensor broken
	"011020",	//GB connector temperature sensor broken
	"011021",	//WiFi module broken
	"011022",	//3G/4G module broken
	"011023",	//Aux. power module broken
	"011024",	//Relay control module /smart box broken
	"011025",	//CHAdeMO connector lock fail
	"011026",	//GB connector lock fail
	"011027",	//AC connector lock fail
	"011028",	//CHAdeMO module broken
	"011029",	//CCS module broken
	"011030",	//GBT module broken
	"011031",	//PSU module broken
	"011032"	//Reserved
};

char AlarmStatusCode[64][6]=
{
	"012200",	//System L1 input OVP
	"012201",	//System L2 input OVP
	"012202",	//System L3 input OVP
	"012203",	//System L1 input UVP
	"012204",	//System L2 input UVP
	"012205",	//System L3 input UVP
	"012206",	//PSU L1 input OVP
	"012207",	//PSU L2 input OVP
	"012208",	//PSU L3 input OVP
	"012209",	//PSU L1 input UVP
	"012210",	//PSU L2 input UVP
	"012211",	//PSU L3 input UVP
	"012212",	//System L1 input drop
	"012213",	//System L2 input drop
	"012214",	//System L3 input drop
	"012215",	//System AC output OVP
	"012216",	//System AC output OCP
	"012217",	//System CHAdeMO output OVP
	"012218",	//System CHAdeMO output OCP
	"012219",	//System CCS output OVP
	"012220",	//System CCS output OCP
	"012221",	//System GB output OVP
	"012222",	//System GB output OCP
	"012223",	//System ambient/inlet OTP
	"012224",	//System critical point OTP
	"012225",	//PSU ambient/inlet OTP
	"012226",	//PSU critical point OTP
	"012227",	//Aux. power module OTP
	"012228",	//Relay board/smart box OTP
	"012229",	//CHAdeMO connector OTP
	"012230",	//CCS connector OTP
	"012231",	//GB connector OTP
	"012232",	//AC connector OTP
	"012233",	//RCD/CCID trip
	"012234",	//CHAdeMO GFD trip
	"012235",	//CCS GFD trip
	"012236",	//GB GFD trip
	"012237",	//SPD trip
	"012238",	//Main power breaker trip
	"012239",	//Aux. power breaker trip
	"012240",	//PSU communication fail
	"012241",	//WiFi module communication fail
	"012242",	//3G/4G module communication fail
	"012243",	//RFID module communication fail
	"012244",	//Bluetooth module communication fail
	"012245",	//LCM module communication fail
	"012246",	//Aux. power module communication fail
	"012247",	//Relay control boaed/smart box communication fail
	"012248",	//CCS module communication fail
	"012249",	//CHAdeMO module communication fail
	"012250",	//GBT module communication fail
	"012251",	//Emergency stop
	"012252",	//Door open
	"012253",	//System fan decay
	"012254",	//Fail to create share memory
	"012255",	//CSU initialization failed
	"012256",	//Reserved
	"012257",	//Reserved
	"012258",	//Reserved
	"012259",	//Reserved
	"012260",	//Reserved
	"012261",	//Reserved
	"012262",	//Reserved
	"012263"	//Reserved
};

char InfoStatusCode[64][6]=
{
	//Information comes from EVSE
	"013600",	//Normal stop charging by user
	"013601",	//Charging Time's up
	"013602",	//Replace system air filter
	"013603",	//Reach to CHAdeMO max. plugging times.
	"013604",	//Reach to CCS max. plugging times.
	"013605",	//Reach to GB max. plugging times.
	"013606",	//Reach to AC max. plugging times.
	"013607",	//CSU fimrware update fail
	"013608",	//CHAdeMO Module fimrware update fail
	"013609",	//CCS Module fimrware update fail
	"013610",	//GB Module fimrware update fail
	"013611",	//Aux. power module fimrware update fail
	"013612",	//Relay control module fimrware update fail
	"013613",	//LCM module fimrware update fail
	"013614",	//Bluetooth module fimrware update fail
	"013615",	//WiFi module fimrware update fail
	"013616",	//3G/4G module fimrware update fail
	"013617",	//SMR fimrware update fail
	"013618",	//RFID module fimrware update fail
	"013619",	//configured by USB flash drive
	"013620",	//configured by backend
	"013621",	//configured by webpage
	"013622",	//disconnected from Internet through Ethernet
	"013623",	//disconnected from Internet through WiFi
	"013624",	//disconnected from Internet through 3G/4G
	"013625",	//disconnected from AP through WiFi
	"013626",	//disconnected from APN through 3G/4G
	"013627",	//Reserved
	"013628",	//Reserved
	"013629",	//Reserved
	"013630",	//Reserved
	"013631",	//Reserved
	//Information comes from EV
	"023700",	//CHAdeMO EV communication Fail
	"023701",	//CCS EV communication Fail
	"023702",	//GB EV communication Fail
	"023703",	//AC: pilot fault
	"023704",	//CHAdeMO:  battery malfunction
	"023705",	//CHAdeMO:  no charging permission
	"023706",	//CHAdeMO:  battery incompatibility
	"023707",	//CHAdeMO:  battery OVP
	"023708",	//CHAdeMO:  battery UVP
	"023709",	//CHAdeMO:  battery OTP
	"023710",	//CHAdeMO:  battery current difference
	"023711",	//CHAdeMO:  battery voltage difference
	"023712",	//CHAdeMO:  shift position
	"023713",	//CHAdeMO:  battery other fault
	"023714",	//CHAdeMO:  charging system error
	"023715",	//CHAdeMO:  EV normal stop
	"023716",	//Reserved
	"023717",	//Reserved
	"023718",	//Reserved
	"023719",	//Reserved
	"023720",	//Reserved
	"023721",	//Reserved
	"023722",	//Reserved
	"023723",	//Reserved
	 //Information comes from Backend
	"033900",	//disconnected from backend through Ethernet
	"033901",	//disconnected from backend through WiFi
	"033902",	//disconnected from backend through 3G/4G
	"033903",	//Remote start charging by backend
	"033904",	//Remote stop charging by backend
	"033905",	//Remote reset by backend
	"033906",	//Reserved
	"033907",	//Reserved
};

/*===========================================================================
FUNCTION: StoreLogMsg
DESCRIPTION:
PRE-CONDITION:
INPUT:
OUTPUT:
GLOBAL VARIABLES:
=============================================================================*/
#if SAVE_SYS_LOG_MSG_EVENTLOG_SWITCH == ENABLE
int StoreLogMsg(unsigned char *DataString)
{
    static unsigned char Buf[1024];
    static time_t CurrentTime;
    static struct tm *tm;
    static struct timeval tv;

    memset(Buf, 0, sizeof(Buf));
    CurrentTime = time(NULL);
    tm = localtime(&CurrentTime);
    gettimeofday(&tv, NULL); // get microseconds, 10^-6

    sprintf(Buf, "echo \"[%04d%02d%02d: %02d:%02d:%02d.%06d][EventLogging]%s\" >> /Storage/SystemLog/[%04d.%02d]SystemLog",
            tm->tm_year + 1900,
            tm->tm_mon + 1,
            tm->tm_mday,
            tm->tm_hour,
            tm->tm_min,
            tm->tm_sec,
            tv.tv_usec,
            DataString,
            tm->tm_year + 1900,
            tm->tm_mon + 1);
    system(Buf);

    DEBUG_PRINTF_EVENTLOG_SYSTEM_LOG("[%02d:%02d:%02d.%06d][EventLogging]%s \n",
            tm->tm_hour,
            tm->tm_min,
            tm->tm_sec,
            tv.tv_usec,
            DataString);

    //Reset the buf_log_eventlogging Buffer, i.e. DataString
    memset(buf_log_eventlogging, 0, SIZE_OF_LOG_BUFFER);
}
#endif

int StoreEventLogMsg(unsigned char *EventCodeString)
{
    unsigned char Buf[256];
    time_t CurrentTime;
    struct tm *tm;

    memset(Buf, 0, sizeof(Buf));
    CurrentTime = time(NULL);
    tm = localtime(&CurrentTime);
    sprintf(Buf, "echo \"%04d.%02d.%02d %02d:%02d:%02d - %s\" >> /Storage/EventLog/[%04d.%02d]EventLog",
            tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
            EventCodeString,
            tm->tm_year + 1900, tm->tm_mon + 1);
    system(Buf);

    DEBUG_PRINTF_EVENTLOG_DETAIL("%s \n", Buf);
}

double DiffTimeb(struct timeb ST, struct timeb ET)
{
	//return milli-second
    double StartTime, EndTime;
    double t_diff;

    StartTime = ((double)ST.time)*1000 + (double)ST.millitm;
    EndTime = ((double)ET.time)*1000 + (double)ET.millitm;
    t_diff = EndTime - StartTime;

    //printf("%.02lf - %.02lf = %.02lf\n", EndTime, StartTime, t_diff);

    if (t_diff < 0)
    {
        #if 0
        if (t_diff < -1000)   //1000ms
        {
            sprintf(buf_log_eventlogging,
                    "[Warning]StartTime(%.02lf) > EndTime(%.02lf), d(%.02lf)",
                    StartTime,
                    EndTime,
                    t_diff);
            SAVE_SYS_LOG_MSG_EVENTLOG(buf_log_eventlogging);
        }
        #endif

        return -1;
    }
    return t_diff;
}

/**************************************************************************************/
/**************************Init all share memory *********************************/
/**************************************************************************************/
int ShareMemory_Init()
{
    int MeterSMId;

    //create ShmSysConfigAndInfo
    if((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo),  0777)) < 0)
    {
        StoreLogMsg("[EventLogging]ShareMemory_Init:shmget ShmSysConfigAndInfo NG");

        return 0;
    }
    else if((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *)-1)
    {
        StoreLogMsg("[EventLogging]ShareMemory_Init:shmat ShmSysConfigAndInfo NG");

        return 0;
    }

    //create ShmStatusCodeData
    if((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData),  0777)) < 0)
    {
        StoreLogMsg("[EventLogging]ShareMemory_Init:shmget ShmStatusCodeData NG");

        return 0;
    }
    else if((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *)-1)
    {
        StoreLogMsg("[EventLogging]ShareMemory_Init:shmat ShmStatusCodeData NG");

        return 0;
    }

    return 1;
}

void FlashPresentStatusCode(unsigned char *NewCode)
{
    unsigned char CodeIndex, SaveIndex = 0;
    unsigned char StatusCodeTmp[10][6];

    memset(StatusCodeTmp, 0, sizeof(StatusCodeTmp));

    for(CodeIndex = 0; CodeIndex < (sizeof(ShmStatusCodeData->PresentStatusCode) / 6); CodeIndex++)
    {
        if(strlen(ShmStatusCodeData->PresentStatusCode[CodeIndex]) <= 0)
        {
            memcpy(StatusCodeTmp[SaveIndex++], NewCode, 6);
            memset(ShmStatusCodeData->PresentStatusCode, 0, sizeof(ShmStatusCodeData->PresentStatusCode));
            memcpy(ShmStatusCodeData->PresentStatusCode, StatusCodeTmp, sizeof(StatusCodeTmp));
            return;
        }
        else if(strstr(ShmStatusCodeData->PresentStatusCode[CodeIndex], NewCode + 1) != NULL)
        {
            if((CodeIndex + 1) < 10)
            {
                memcpy(StatusCodeTmp[SaveIndex], ShmStatusCodeData->PresentStatusCode[CodeIndex + 1], (9 - CodeIndex) * 6);
            }

            memset(ShmStatusCodeData->PresentStatusCode, 0, sizeof(ShmStatusCodeData->PresentStatusCode));
            memcpy(ShmStatusCodeData->PresentStatusCode, StatusCodeTmp, sizeof(StatusCodeTmp));
            return;
        }
        else
        {
            memcpy(StatusCodeTmp[SaveIndex++], ShmStatusCodeData->PresentStatusCode[CodeIndex], 6);
        }
    }
}

int main(int argc, char *argv[])
{
    int ByteCount, BitCount;
    unsigned char tmp, EventCodeTmp[7];

    //Initialization
    if(ShareMemory_Init() == 0)
    {
        StoreLogMsg("[EventLogging]main:ShareMemory_Init NG");

        if(ShmStatusCodeData != NULL)
        {
            ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FailToCreateShareMemory = 1;
        }

        sleep(5);
        return 0;
    }

    while(1)
    {
        //check Fault Status
        for(ByteCount = 0; ByteCount < 4; ByteCount++)
        {
            if(ShmStatusCodeData->FaultCode.FaultEvents.FaultVal[ByteCount] != ShmStatusCodeData->FaultCode.PreviousFaultVal[ByteCount])
            {
                tmp = ShmStatusCodeData->FaultCode.FaultEvents.FaultVal[ByteCount]; //prevent be modified during following process

                for(BitCount = 0; BitCount < 8; BitCount++)
                {
                    if(((tmp >> BitCount) & 0x01) != ((ShmStatusCodeData->FaultCode.PreviousFaultVal[ByteCount] >> BitCount) & 0x01))
                    {
                        memset(EventCodeTmp, 0, sizeof(EventCodeTmp));
                        memcpy(EventCodeTmp, FaultStatusCode[ByteCount * 8 + BitCount], sizeof(EventCodeTmp) - 1);

                        if(((tmp >> BitCount) & 0x01) == 0)//Recovered
                        {
                            EventCodeTmp[0] = 1;
                            ShmStatusCodeData->FaultCode.PreviousFaultVal[ByteCount] &= (0 << BitCount);
                        }
                        else
                        {
                            ShmStatusCodeData->FaultCode.PreviousFaultVal[ByteCount] |= (1 << BitCount);
                        }

                        FlashPresentStatusCode(EventCodeTmp);
                        StoreEventLogMsg(EventCodeTmp);
                    }
                }
            }
        }

        //check Alarm Status
        for(ByteCount = 0; ByteCount < 8; ByteCount++)
        {
            if(ShmStatusCodeData->AlarmCode.AlarmEvents.AlarmVal[ByteCount] != ShmStatusCodeData->AlarmCode.PreviousAlarmVal[ByteCount])
            {
                tmp = ShmStatusCodeData->AlarmCode.AlarmEvents.AlarmVal[ByteCount]; //prevent be modified during following process

                for(BitCount = 0; BitCount < 8; BitCount++)
                {
                    if(((tmp >> BitCount) & 0x01) != ((ShmStatusCodeData->AlarmCode.PreviousAlarmVal[ByteCount] >> BitCount) & 0x01))
                    {
                        memset(EventCodeTmp, 0, sizeof(EventCodeTmp));
                        memcpy(EventCodeTmp, AlarmStatusCode[ByteCount * 8 + BitCount], sizeof(EventCodeTmp) - 1);

                        if(((tmp >> BitCount) & 0x01) == 0)//Recovered
                        {
                            EventCodeTmp[0] = 1;
                            ShmStatusCodeData->AlarmCode.PreviousAlarmVal[ByteCount] &= (0 << BitCount);
                        }
                        else
                        {
                            ShmStatusCodeData->AlarmCode.PreviousAlarmVal[ByteCount] |= (1 << BitCount);

                        }

                        FlashPresentStatusCode(EventCodeTmp);
                        StoreEventLogMsg(EventCodeTmp);
                    }
                }
            }
        }

        //check Info Status
        for(ByteCount = 0; ByteCount < 8; ByteCount++)
        {
            if(ShmStatusCodeData->InfoCode.InfoEvents.InfoVal[ByteCount] != ShmStatusCodeData->InfoCode.PreviousInfoVal[ByteCount])
            {
                tmp = ShmStatusCodeData->InfoCode.InfoEvents.InfoVal[ByteCount]; //prevent be modified during following process

                for(BitCount = 0; BitCount < 8; BitCount++)
                {
                    if(((tmp >> BitCount) & 0x01) != ((ShmStatusCodeData->InfoCode.PreviousInfoVal[ByteCount] >> BitCount) & 0x01))
                    {
                        memset(EventCodeTmp, 0, sizeof(EventCodeTmp));
                        memcpy(EventCodeTmp, InfoStatusCode[ByteCount * 8 + BitCount], sizeof(EventCodeTmp) - 1);

                        if(((tmp >> BitCount) & 0x01) == 0)//Recovered
                        {
                            EventCodeTmp[0] = 1;
                            ShmStatusCodeData->InfoCode.PreviousInfoVal[ByteCount] &= (0 << BitCount);
                        }
                        else
                        {
                            ShmStatusCodeData->InfoCode.PreviousInfoVal[ByteCount] |= (1 << BitCount);
                        }

                        FlashPresentStatusCode(EventCodeTmp);
                        StoreEventLogMsg(EventCodeTmp);
                    }
                }
            }
        }
    }//main while loop

}