#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 <sys/time.h> 
#include <sys/timeb.h> 
#include <netinet/in.h>
#include <unistd.h>
#include "define.h"

//#define debug		
#define CheckModemInterval		30	//sec
#define CheckSimInterval			10 	//sec
#define CheckConnectionInterval		5 	//sec
#define DisconnInterval				60 	//sec




struct SysConfigAndInfo			*ShmSysConfigAndInfo;
struct StatusCodeData 			*ShmStatusCodeData;
struct FanModuleData			*ShmFanModuleData;


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


int Check4GModem()
{
	//return 0: No 4G modem equipped
	//return 1: Qutel 4G modem equipped
	//return 2: ublox 4G modem equipped
	
	int Rtn1,Rtn2;
	
	//check Qutel 4G modem
	Rtn1=Rtn2=-1;
	Rtn1=access("/dev/ttyUSB0",R_OK);
	if(Rtn1==0)
	{
		Rtn2=access("/dev/ttyUSB2",R_OK);
		if(Rtn2==0)
		{
			#ifdef SystemLogMessage	
			StoreLogMsg("[4gModem]Check4GModem: Qutel 4G modem be found");
			#endif	
			return 1;
		}
	}	
	//check ublox 4G modem
	Rtn1=Rtn2=-1;
	Rtn1=access("/dev/ttyACM0",R_OK);
	if(Rtn1==0)
	{
		Rtn2=access("/dev/ttyACM2",R_OK);
		if(Rtn2==0)
		{
			#ifdef SystemLogMessage	
			StoreLogMsg("[4gModem]Check4GModem: ublox 4G modem be found");
			#endif	
			return 2;
		}
	}	
	#ifdef SystemLogMessage	
	StoreLogMsg("[4gModem]Check4GModem: No 4G modem be found");
	#endif	
	return 0;	
}

int InitComPort(unsigned char ModemModel)
{
	int UsbFd;
	struct termios tios;
	
	if(ModemModel==1)	//Qutel 4G modem equipped
		UsbFd = open("/dev/ttyUSB2", O_RDWR|O_NOCTTY);
	else if(ModemModel==2)	//ublox 4G modem equipped
		UsbFd = open("/dev/ttyACM2", O_RDWR|O_NOCTTY);
	else
	{
		#ifdef SystemLogMessage	
		StoreLogMsg("[4gModem]InitComPort: Unknow ModemModel ");
		#endif		
		return -1;
	}	
	
	if(UsbFd<0)
	{
		#ifdef SystemLogMessage	
		StoreLogMsg("[4gModem]InitComPort:  UsbFd open failed");
		#endif	
		return -1;
	}	
	ioctl (UsbFd, TCGETS, &tios);
	tios.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
	tios.c_lflag = 0;
	tios.c_iflag = 0;
	tios.c_oflag = 0;
  	tios.c_cc[VMIN]=0;   
	tios.c_cc[VTIME]=100; 
	tios.c_lflag=0;  
	tcflush(UsbFd, TCIFLUSH);
	ioctl (UsbFd, TCSETS, &tios);
	return UsbFd;
	
}

void GetModelName(int Fd, unsigned char *ModelName)
{
	//AT command processing
}

void GetModelVersion(int Fd, unsigned char *ModelVersion)
{
	//AT command processing
}

void GetModelImei(int Fd, unsigned char *ModelImei)
{
	//AT command processing
}

void GetSimImsi(int Fd, unsigned char *SimImsi)
{
	//AT command processing
}

unsigned char GetModemMode(int Fd)
{
	int Mode;
	//AT command processing
	return Mode;
}

int GetSignalRssi(int Fd)
{
	int RssiValue;
	//AT command processing
	return RssiValue;
}

int GetPPP0Info(unsigned char *IPaddress)
{
    	int fd,rd=0;
	unsigned int address;
	char buf[128],addr[32],*sptr,*eptr;
	

    	system("ifconfig ppp0 | grep \"inet addr:\" > /mnt/GetPPP0Info");
	fd = open("/mnt/GetPPP0Info", O_RDONLY);
    	if(fd<0)
   	{
    		system("rm -f /mnt/GetPPP0Info");
	        return 0;
    	}
    
    	memset(addr,0,sizeof(addr));
    	memset(buf,0,sizeof(buf));
    	rd=read(fd,buf,sizeof(buf));	
    	if(rd<=0)
    	{
    		close(fd);
    		system("rm -f /mnt/GetPPP0Info");
        	return 0;
   	}
    	close(fd);
    	if((sptr=strstr(buf,"inet addr:"))==NULL)
    	{
    		close(fd);
    		system("rm -f /mnt/GetPPP0Info");
        	return 0;
    	}
    	sptr+=strlen("inet addr:");
    	if((eptr=strstr(buf,"  P-t-P:"))==NULL)
    	{
    		close(fd);
    		system("rm -f /mnt/GetPPP0Info");
        	return 0;
    	}
    	memset(IPaddress,0,strlen(IPaddress));
    	strncpy(IPaddress,sptr,eptr-sptr);   
    	#ifdef SystemLogMessage	
	{
		unsigned char Buffer[128];
		memset(Buffer,0,sizeof(Buffer));
		sprintf(Buffer,"[4gModem]GetPPP0Info: 4G IP Address = %s",IPaddress);
		StoreLogMsg(Buffer);
	}
	#endif		
    	return 1;
}
int  Load4gConfiguration()
{
	unsigned char CopyTmp[128];
	
	if(strlen(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomApn)<=0)
		return 0;
	system("cat /dev/null > /root/ppp/auto-apn.conf");
	system("chmod 777 /root/ppp/auto-apn.conf");  
	system("cat /dev/null > /etc/ppp/options"); 
	system("chmod 777 /etc/ppp/options"); 
	system("cat /dev/null > /etc/ppp/pap-secrets"); 
	system("chmod 777 /etc/ppp/pap-secrets"); 
	system("cat /dev/null > /etc/ppp/chap-secrets"); 
	system("chmod 777 /etc/ppp/chap-secrets"); 
	memset(CopyTmp,0,sizeof(CopyTmp));
	sprintf(CopyTmp,"echo \"APN=\"%s\"\" > /root/ppp/auto-apn.conf",ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomApn);
	system(CopyTmp);
	system("echo \"ACCOUNT=\" >> /root/ppp/auto-apn.conf");
	system("echo \"PASSWORD=\" >> /root/ppp/auto-apn.conf");
	
	if(strlen(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapId)>0)
	{	
		memset(CopyTmp,0,sizeof(CopyTmp));
		sprintf(CopyTmp,"echo \"name %s \" > /etc/ppp/options",ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapId);
		system(CopyTmp);
		
		memset(CopyTmp,0,sizeof(CopyTmp));
		sprintf(CopyTmp,"echo \"%s * %s \" > /etc/ppp/pap-secrets",
		ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapId,
		((strlen(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapPwd)>0)?ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapPwd : " "));
		system(CopyTmp);

		memset(CopyTmp,0,sizeof(CopyTmp));
		sprintf(CopyTmp,"echo \"%s * %s \" > /etc/ppp/chap-secrets",
		ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapId,
		((strlen(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapPwd)>0)?ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomChapPapPwd : " "));
		system(CopyTmp);
	}	
	return 1;
}
void ResetModem()
{
	//power cycle modem by GPIO
}
/**************************************************************/
/************** main function********************************/
/*************************************************************/
int main(int argc,char *argv[])
{
	unsigned char ModuleModel=0;//0: None, 1: Qutel, 2: ublox SARA-U201
	int UsbFd=-1;
	unsigned int StartTime,EndTime,Tmp; 
	unsigned char TmpIpAddr[16];
	
	//Initialization
	if(InitShareMemory()==0)
	{
		#ifdef SystemLogMessage	
		StoreLogMsg("[4gModem]main:InitShareMemory NG");
		#endif		
		if(ShmStatusCodeData!=NULL)
		{
			ShmStatusCodeData->AlarmCode.AlarmEvents.bits.FailToCreateShareMemory=1;
		}	
		sleep(5);
		return 0;
	}	
	ResetModem();
	
ReCheckModem:    
	//ResetModem();
	UsbFd=-1;
	ModuleModel=0;
	Load4gConfiguration();

	while(1)
	{
		ModuleModel=Check4GModem();
		if(ModuleModel<=0)
		{
			sleep(CheckModemInterval);
			continue;
		}	
		if(UsbFd>0)
			close(UsbFd);
		UsbFd=InitComPort(ModuleModel);
		if(UsbFd<0)
		{
			sleep(CheckModemInterval);
			continue;
		}
		/**** Record some modem information and dial up if SIM card ready ****/
		memset(&ShmSysConfigAndInfo->SysConfig.TelecomInterface,0,sizeof(struct TeleConfigData));
		while(1)
		{
			if(strlen(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModelName)<=0)
				GetModelName(UsbFd,ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModelName);
			if(strlen(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSoftwareVer)<=0)
				GetModelVersion(UsbFd,ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSoftwareVer);	
			if(strlen(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModemImei)<=0)
				GetModelImei(UsbFd,ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModemImei);		
			GetSimImsi(UsbFd,ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSimImsi);		
			if(strlen(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSimImsi)<=0)
			{	
				ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSimStatus=0;
				sleep(CheckSimInterval);	
				if(Check4GModem()<=0)
					goto ReCheckModem;
			}
			else
			{
				ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomSimStatus=1;
				if(strlen(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomApn)<=0)
				{
					sleep(DisconnInterval);
					goto ReCheckModem;		
				}
				system("killall 4GDetection");	
				sleep(2);
				if(ModuleModel==1)
					system("/root/ppp/4GDetection /dev/ttyUSB0 &");	
				else if(ModuleModel==2)
					system("/root/ppp/4GDetection /dev/ttyACM0 &");
				break;	
			}			
		}
		/***** Periodically check RSSI and connection*****/
		StartTime=time((time_t*)NULL);
		EndTime=time((time_t*)NULL);
		while(1)
		{
			if((time((time_t*)NULL)-StartTime)>=CheckConnectionInterval)
			{	
				//check IP address 
				memset(TmpIpAddr,0,sizeof(TmpIpAddr));
				if(GetPPP0Info(TmpIpAddr)<=0)
				{
					ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomNetworkConn=0;
					if((time((time_t*)NULL)-EndTime)>=DisconnInterval)
						goto ReCheckModem; 
				}	
				else
				{
					ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomNetworkConn=1;
					if(strstr(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomIpAddress,TmpIpAddr)==NULL)
					{
						#ifdef SystemLogMessage	
						{
							unsigned char Buffer[128];
							memset(Buffer,0,sizeof(Buffer));
							sprintf(Buffer,"[4gModem]main:  4G IP Address changed from %s to %s",ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomIpAddress,TmpIpAddr);
							StoreLogMsg(Buffer);
						}
						#endif		
						memset(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomIpAddress,0,sizeof(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomIpAddress));
						strcpy(ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomIpAddress,TmpIpAddr);
						system("route del default");
						system("route add default dev ppp0");
					}
					EndTime=time((time_t*)NULL);
				}	
				//check RSSI
				Tmp=GetSignalRssi(UsbFd);
				if(abs(Tmp-ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomRssi)>=5)
				{
					#ifdef SystemLogMessage	
					{
						unsigned char Buffer[128];
						memset(Buffer,0,sizeof(Buffer));
						sprintf(Buffer,"[4gModem]main: RSSI changed from %d to %d",ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomRssi,Tmp);
						StoreLogMsg(Buffer);
					}
					#endif		
					ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomRssi=Tmp;
				}	
				//check Mode
				Tmp=GetModemMode(UsbFd);
				if(Tmp!=ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModemMode)
				{
					#ifdef SystemLogMessage	
					{
						unsigned char Buffer[128];
						memset(Buffer,0,sizeof(Buffer));
						sprintf(Buffer,"[4gModem]main: Modem mode changed from %d to %d",ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModemMode,Tmp);
						StoreLogMsg(Buffer);
					}
					#endif
					ShmSysConfigAndInfo->SysConfig.TelecomInterface.TelcomModemMode=Tmp;
				}	
				StartTime=time((time_t*)NULL);
			}
		}
	}//main while loop
}