#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 <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <unistd.h>
#include "../../define.h"

//#define Debug


struct SysConfigAndInfo			*ShmSysConfigAndInfo;
struct StatusCodeData 			*ShmStatusCodeData;
struct PsuData 				*ShmPsuData ;
pid_t						CANReceiverPid;
int 							CanFd;


#ifdef SystemLogMessage
int StoreLogMsg(unsigned char *DataString)
{
	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/SystemLog/[%04d.%02d]SystemLog",
			tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,tm->tm_hour,tm->tm_min,tm->tm_sec,
			DataString,
			tm->tm_year+1900,tm->tm_mon+1);
	system(Buf);
	#ifdef Debug
	printf("%s \n",DataString);
	#endif
}		
#endif

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;
}	
	
/**************************************************************************************/
/**************************Init all share memory *********************************/
/**************************************************************************************/
int InitShareMemory()
{
	int MeterSMId;
	
	//creat ShmSysConfigAndInfo
	if ((MeterSMId = shmget(ShmSysConfigAndInfoKey, sizeof(struct SysConfigAndInfo),  0777)) < 0) 
    	{
		#ifdef SystemLogMessage	
		StoreLogMsg("[PsuCOmm]InitShareMemory:shmget ShmSysConfigAndInfo NG");
		#endif			
		return 0;
	}
    	else if ((ShmSysConfigAndInfo = shmat(MeterSMId, NULL, 0)) == (void *) -1) 
    	{
    		#ifdef SystemLogMessage	
		StoreLogMsg("[PsuCOmm]InitShareMemory:shmat ShmSysConfigAndInfo NG");
		#endif		
		return 0;
   	 }
   	 //creat ShmStatusCodeData
   	 if ((MeterSMId = shmget(ShmStatusCodeKey, sizeof(struct StatusCodeData),  0777)) < 0) 
    	{
		#ifdef SystemLogMessage	
		StoreLogMsg("[PsuCOmm]InitShareMemory:shmget ShmStatusCodeData NG");
		#endif		
		return 0;	
	}
    	else if ((ShmStatusCodeData = shmat(MeterSMId, NULL, 0)) == (void *) -1) 
    	{
    		#ifdef SystemLogMessage	
		StoreLogMsg("[PsuCOmm]InitShareMemory:shmat ShmStatusCodeData NG");
		#endif		
		return 0;
   	 }

   	 //creat ShmPsuData
   	 if ((MeterSMId = shmget(ShmPsuKey, sizeof(struct PsuData),  0777)) < 0) 
    	{
		#ifdef SystemLogMessage	
		StoreLogMsg("[PsuCOmm]InitShareMemory:shmget ShmPsuData NG");
		#endif			
		return 0;
	}
    	else if ((ShmPsuData = shmat(MeterSMId, NULL, 0)) == (void *) -1) 
    	{
    		#ifdef SystemLogMessage	
		StoreLogMsg("[PsuCOmm]InitShareMemory:shmat ShmPsuData NG");
		#endif		
		return 0;
   	 }
   	memset(ShmPsuData,0,sizeof(struct PsuData));
    	return 1;
}

int InitCanBus()
{
	int 					s0,nbytes;
	struct timeval			tv;
	struct ifreq 			ifr0;
	struct sockaddr_can	addr0;
	
	system("/sbin/ip link set can1 type can bitrate 500000 restart-ms 100");				  
	system("/sbin/ip link set can1 up");
	
	s0 = socket(PF_CAN, SOCK_RAW, CAN_RAW);
	
	tv.tv_sec = 0; 
    	tv.tv_usec = 10000; 
   	 if (setsockopt(s0, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct	timeval)) < 0) 
    	{
	       	#ifdef SystemLogMessage	
		StoreLogMsg("[PsuCOmm]InitCanBus:Set SO_RCVTIMEO NG");
		#endif		
    	}
    	nbytes=40960;
    	if (setsockopt(s0, SOL_SOCKET,  SO_RCVBUF, &nbytes, sizeof(int)) < 0) 
	{
		#ifdef SystemLogMessage	
		StoreLogMsg("[PsuCOmm]InitCanBus:Set SO_RCVBUF NG");
		#endif	
	}
    	nbytes=40960;
    	if (setsockopt(s0, SOL_SOCKET, SO_SNDBUF, &nbytes, sizeof(int)) < 0) 
    	{
       		#ifdef SystemLogMessage	
		StoreLogMsg("[PsuCOmm]InitCanBus:Set SO_SNDBUF NG");
		#endif	
    	}
    
   	strcpy(ifr0.ifr_name, "can1" );
	ioctl(s0, SIOCGIFINDEX, &ifr0); /* ifr.ifr_ifindex gets filled with that device's index */
	addr0.can_family = AF_CAN;
	addr0.can_ifindex = ifr0.ifr_ifindex;
	bind(s0, (struct sockaddr *)&addr0, sizeof(addr0));
	return s0;
}


/**************************************************************/
/************** Receiving Task*******************************/
/*************************************************************/
void CANReceiver(int fd)
{
	pid_t tmp=0;
	struct can_frame frame;
	struct timeb StartTime,EndTime;
	int nbytes;
	unsigned char FanspeedGetTime=0;
	
	if(CANReceiverPid==0)
	{
		tmp=fork();
		if(tmp>0)
		{
			CANReceiverPid=tmp;	
			{
				unsigned char buf[64];
				memset(buf,0,sizeof(buf));
				sprintf(buf,"renice -20 -p %d",tmp);
				system(buf);
			}
			return;
		}
	}
	
	while(1)
	{
		memset(&frame,0,sizeof(struct can_frame));
		nbytes = read(fd, &frame, sizeof(struct can_frame));
		//handle received packet
	}
}

/**************************************************************/
/************** main function***********************************/
/*************************************************************/
int main(int argc,char *argv[])
{
	int CanFd;
	struct can_frame frame;

	
	//Initialization
	if(InitShareMemory()==0)
	{
		#ifdef SystemLogMessage	
		StoreLogMsg("[PsuCOmm]main:InitShareMemory NG");
		#endif		
		if(ShmStatusCodeData!=NULL)
		{
			ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FailToCreateShareMemory=1;
		}	
		sleep(5);
		return 0;
	}	
	CanFd=InitCanBus();
	CANReceiverPid=0;
	CANReceiver(CanFd);

	//main loop
	while(1)
	{
		//processing
	}
	
EndProcess:	
	if(CANReceiverPid>0)
	{
		char Buf[32];
		memset(Buf,0,32);
		sprintf(Buf,"kill %d",CANReceiverPid);
		system(Buf);
	}
	close(CanFd); 
	system("/sbin/ip link set can1 down");
	system("/sbin/ip link set can1 type can bitrate 500000 restart-ms 100");
	system("/sbin/ip link set can1 up");
	system("/sbin/ip link set can1 down");
	system("killall PsuComm");
}