/***************************************************************************
	DeltaT_StoreData.c by Jeff J Patterson, 21JUN06
   Imagenex Technology Corp.

   Command Prompt test program for communicating with the DeltaT sonar
   via TCP/IP functions.

   - add x_offset, y_offset and z_offset to 837 file .............. 21JUN06

***************************************************************************/
#define _WINSOCK2API_	//tell windows to include winsock2.h, not winsock.h

#include <windows.h>
#include <windowsx.h>
#include <winbase.h>
#include <stdio.h>
#include <conio.h>
#include <dir.h>
#include <string.h>
#include <sys\timeb.h>
#include <time.h>
#include <winsock2.h>

#define IPADDR "192.168.0.2"
#define PORT 4040

void SetSwitches(void);
void ErrorFunction(void);
void OpenRecordFile(void);
void CloseRecordFile(void);
void MakeAuto837File(void);
void WritePingToFile(void);
void GetDateTime(void);
void ReadINIFile(void);
void WriteINIFile(void);
void CalcPeriod(void);

char ip_addr[20];
char ser_sw_tcp[27];
char ser_buf_tcp[1100];
char ser_buf[8192];

char hdr_type;
int nToRead;
int nToRead_tcp;
int send_packet_number;
int recv_packet_number;
int ping_number;

WORD wVersionRequested;
WSADATA wsaData;
SOCKET sock;
SOCKADDR_IN sin;

unsigned short int port = PORT;

char filebuf[256];

char RecordFileName[256] = "";
HANDLE RecordFileHandle;
int  RecordFileOpen = FALSE;
char disk_date[20];
char disk_time[20];
char date_time[40];
char clock_hundreths_buf[6];
int clock_sec;
int old_clock_sec;
int nRecBytes = 0;
int rep_rate;

int range = 30;
int gain = 3;
int pulse_length = 180;

float x_offset = 0.0;
float y_offset = 0.0;
float z_offset = 0.0;

BOOL record_to_file = FALSE;

int main(void) {
   register int i;
	int return_val;

	ReadINIFile();

	printf("IP Address: %s\n",ip_addr);
	printf("Port:       %d\n",port);
   printf("Range:      %dm\n",range);
   printf("Gain:       %ddB\n",gain);

	wVersionRequested = MAKEWORD(1, 1);

   return_val = WSAStartup(wVersionRequested, &wsaData);

   if(return_val!=0) {
   	printf("WSAStartup() failed!\n");
		ErrorFunction();
      return 1;
   }

   sock = socket(PF_INET, SOCK_STREAM, 0);
   if (sock == INVALID_SOCKET) {
   	printf("socket() failed!\n");
		ErrorFunction();
      return 1;
   }

   sin.sin_family = AF_INET;
   sin.sin_addr.s_addr = inet_addr(ip_addr);
   sin.sin_port = htons(port);
   return_val = connect(sock, (LPSOCKADDR)&sin, sizeof(sin));
   if (return_val == SOCKET_ERROR) {
   	printf("\nconnect() failed!\n");
		ErrorFunction();
      return 1;
   }

	hdr_type = 'U';
	nToRead_tcp = 1033;
	send_packet_number = 0;
	recv_packet_number = 0;
	ping_number = 0;

	if(record_to_file) OpenRecordFile();

	while(!kbhit()) {

		GetDateTime();

		SetSwitches();
      printf("\n\nSend Switches...    %dm, %ddB\n",range,gain);
	   return_val = send(sock, ser_sw_tcp, 27, 0);
	   if (return_val == SOCKET_ERROR) {
   		printf("send() failed!\n");
			ErrorFunction();
      	return 1;
	   }

      do {
   		return_val = recv(sock, ser_buf_tcp, nToRead_tcp, MSG_PEEK);
	   	if (return_val == SOCKET_ERROR) {
   			printf("recv() failed!\n");
				ErrorFunction();
      		return 1;
		   }
		} while(return_val!=nToRead_tcp);

		if(return_val==nToRead_tcp) {
         return_val = recv(sock, ser_buf_tcp, nToRead_tcp, 0);
			if(return_val>0) {
				if(ser_buf_tcp[0]=='I' && ser_buf_tcp[1]==hdr_type &&
   	      	ser_buf_tcp[2]=='X' && ser_buf_tcp[return_val-1]==(char)(0xFC)) {

         	   recv_packet_number = ser_buf_tcp[5]&0x07;
            	for(i=0;i<12;i++) ser_buf[i] = ser_buf_tcp[i];
					for(i=0;i<1000;i++) ser_buf[12+(recv_packet_number*1000)+i] = ser_buf_tcp[12+20+i];

		   		printf("Header            = %c%c%c\n",(BYTE)ser_buf_tcp[0],
   	      									      		  (BYTE)ser_buf_tcp[1],
            	                            		     (BYTE)ser_buf_tcp[2]);
					printf("Packet Number     = %d\n",recv_packet_number);
		   		printf("ser_buf_tcp[%d] = 0x%02X",return_val-1,(BYTE)ser_buf_tcp[return_val-1]);
	   			if(recv_packet_number==send_packet_number) send_packet_number++;
   	   		if(send_packet_number>7) {
                  ser_buf[12+8000] = ser_buf_tcp[return_val-1];
						nToRead = 8013;
            		send_packet_number = 0;
						ping_number++;
			   		printf(" --> Ping %d\n",ping_number);

               	CalcPeriod();

						if(RecordFileOpen) {
      		      	WritePingToFile();
							printf("\nWriting to file: %s - %d kbytes",RecordFileName,nRecBytes/1024);
		            }
      	      }
            }
   	   }
      	else printf("No Data\n");
      }
	}

	if(record_to_file) CloseRecordFile();

   return_val = closesocket(sock);
   if (return_val == SOCKET_ERROR) {
   	printf("closesocket() failed!\n");
		ErrorFunction();
      return 1;
   }

   WSACleanup();

   getch();
   printf("\n\nPress any key to exit.");
   getch();

   WriteINIFile();

   return 0;
}

void SetSwitches(void)
{
   pulse_length = 6 * range;

	ser_sw_tcp[0]  = 0xFE;
	ser_sw_tcp[1]  = 0x44;
	ser_sw_tcp[2]  = 0x10;						//Head ID
	ser_sw_tcp[3]  = range;						//Range
	ser_sw_tcp[4]  = 0;   						//Range Offset
	ser_sw_tcp[5]  = 0;
	ser_sw_tcp[6]  = 0;
	ser_sw_tcp[7]  = 0;
	ser_sw_tcp[8]  = gain;						//Gain
	ser_sw_tcp[9]  = 1;							//LOGF
	ser_sw_tcp[10] = 10;							//Absorption
	ser_sw_tcp[11] = 0;
	ser_sw_tcp[12] = 0;
	ser_sw_tcp[13] = send_packet_number;	//0-7
	ser_sw_tcp[14] = pulse_length/10;		//Pulse Length
	ser_sw_tcp[15] = 0;
	ser_sw_tcp[16] = 0;
	ser_sw_tcp[17] = 0;
	ser_sw_tcp[18] = 0;
	ser_sw_tcp[19] = 8;							//8 = 8000 data points (IUX mode)
	ser_sw_tcp[20] = 8;							//8 Data Bits
	ser_sw_tcp[21] = 0;
	ser_sw_tcp[22] = 0;
	ser_sw_tcp[23] = 0;
	ser_sw_tcp[24] = 0;							//Switch Delay
	ser_sw_tcp[25] = 86;							//Frequency, 86 = 260kHz
	ser_sw_tcp[26] = 0xFD;
}

void ErrorFunction(void)
{
   printf("\n\nPress any key to exit.");
   getch();
}

void OpenRecordFile(void)
{
	OPENFILENAME SaveFileName;

	// We first initialize all elements to zero
	memset(&SaveFileName, 0, sizeof(OPENFILENAME));

	RecordFileName[0] = '\0';
	// Now we will elements of the structure
	SaveFileName.hwndOwner         = NULL;
	SaveFileName.nFilterIndex      = 1;
	SaveFileName.lpstrFile         = (LPSTR)RecordFileName;
	SaveFileName.nMaxFile          = sizeof(RecordFileName);
	SaveFileName.Flags             = OFN_HIDEREADONLY | \
												OFN_EXTENSIONDIFFERENT | \
												OFN_OVERWRITEPROMPT | \
												OFN_PATHMUSTEXIST;
	SaveFileName.lpstrDefExt       = "837";
	SaveFileName.lStructSize       = sizeof(OPENFILENAME);

   MakeAuto837File();
   SaveFileName.nFileExtension = (WORD)(strlen(RecordFileName)-3);

   RecordFileHandle = CreateFile(SaveFileName.lpstrFile,
         								GENERIC_WRITE,
      		            			0,                    // exclusive access
            		      		 	NULL,                 // no security attrs
                  				 	CREATE_ALWAYS,
                  				 	FILE_ATTRIBUTE_NORMAL,
      		            		 	NULL );

   if(RecordFileHandle==(HANDLE)-1) RecordFileOpen = FALSE;
   else RecordFileOpen = TRUE;
}

void CloseRecordFile(void)
{
	CloseHandle(RecordFileHandle);
	RecordFileOpen = FALSE;
}

void MakeAuto837File(void)
{
	register int i;
   char ftype[256];
   struct ffblk ffblk;
   int done;
   unsigned long num,nummax;
   char *ptr;
   char buf[256];

   for(i=0;i<256;i++) RecordFileName[i] = 0;

   GetDateTime();

   RecordFileName[0] = date_time[0];
   RecordFileName[1] = date_time[1];
   RecordFileName[2] = date_time[3];
   RecordFileName[3] = date_time[4];
   RecordFileName[4] = date_time[5];
   RecordFileName[5] = date_time[7];
   RecordFileName[6] = date_time[8];
   RecordFileName[7] = date_time[9];
   RecordFileName[8] = date_time[10];
	strcat((LPSTR)RecordFileName,"-");
	strcat((LPSTR)RecordFileName,"????");
	strcat((LPSTR)RecordFileName,".837");

   num = 0;
   nummax = 0;
   strcpy(ftype,(LPSTR)RecordFileName);
   done = findfirst(ftype,&ffblk,0);
   while(!done) {
		strcpy(buf,ffblk.ff_name);
      ptr = &buf[10];
      buf[14] = 0;
      num = atol(ptr);
      if(num>nummax) nummax = num;
      done = findnext(&ffblk);
   }
   nummax++;
   if(nummax>9999) nummax = 9999;
   sprintf(buf,"%04lu",nummax);

   RecordFileName[10] = buf[0];
   RecordFileName[11] = buf[1];
   RecordFileName[12] = buf[2];
   RecordFileName[13] = buf[3];
}

void WritePingToFile(void)
{
	PBYTE pbBuf;
	register int i;
	int pbctr,nBytes,temp;
	DWORD dwBytesWritten;
   float *fptr;

	nBytes = 8192;

	pbBuf = (PBYTE)LocalAlloc(LMEM_FIXED,nBytes);
	for(i=0;i<nBytes;i++) pbBuf[i] = 0;

	pbBuf[0] = '8';
	pbBuf[1] = '3';
	pbBuf[2] = '7';
	pbBuf[3] = 10;
	pbBuf[4] = (BYTE)((nBytes&0xFF00)>>8);
	pbBuf[5] = (BYTE)(nBytes&0x00FF);

	pbBuf[6] = (BYTE)((nToRead&0xFF00)>>8);
	pbBuf[7] = (BYTE)(nToRead&0x00FF);
	pbctr = 8;
	for(i=0;i<12;i++) pbBuf[pbctr++] = disk_date[i];
	for(i=0;i<9;i++) pbBuf[pbctr++] = disk_time[i];

   pbBuf[29] = clock_hundreths_buf[0];
   pbBuf[30] = clock_hundreths_buf[1];
   pbBuf[31] = clock_hundreths_buf[2];
   pbBuf[32] = 0;

	pbBuf[37] = 0x80;
	pbBuf[38] = gain;
	pbBuf[42] = 10;
	pbBuf[44] = pulse_length/10;

	temp = (int)(1500.0*10.0);
	pbBuf[46] = (BYTE)(0x80 | ((temp&0x7F00)>>8));
   pbBuf[47] = (BYTE)(temp&0x00FF);

	pbBuf[80] = (BYTE)((260&0xFF00)>>8);
	pbBuf[81] = (BYTE)(260&0x00FF);

   pbBuf[88] = (BYTE)((rep_rate&0xFF00)>>8);
   pbBuf[89] = (BYTE)(rep_rate&0x00FF);
   pbBuf[90] = 50;

	pbctr = 100;
	for(i=0;i<nToRead;i++) pbBuf[pbctr++] = ser_buf[i];

   fptr = &pbBuf[8113];
   *fptr = x_offset;

   fptr = &pbBuf[8117];
   *fptr = y_offset;

   fptr = &pbBuf[8121];
   *fptr = z_offset;			//sonar depth

   WriteFile(RecordFileHandle,(PBYTE) &pbBuf[0],nBytes,&dwBytesWritten,NULL);
   nRecBytes += dwBytesWritten;

	LocalFree((HLOCAL)pbBuf);
}

void GetDateTime(void)
{
	struct tm *timeptr;
	struct timeb t;
	time_t secsnow;
	char *month;
   int clock_hundreths;

	time(&secsnow);
	timeptr = localtime(&secsnow);
	ftime(&t);
   clock_hundreths = t.millitm/10;
	clock_sec = timeptr->tm_sec;

	if(clock_sec!=old_clock_sec) {
		old_clock_sec = clock_sec;
		switch(timeptr->tm_mon) {
			case (0)  : month = "JAN"; break;
			case (1)  : month = "FEB"; break;
			case (2)  : month = "MAR"; break;
			case (3)  : month = "APR"; break;
			case (4)  : month = "MAY"; break;
			case (5)  : month = "JUN"; break;
			case (6)  : month = "JUL"; break;
			case (7)  : month = "AUG"; break;
			case (8)  : month = "SEP"; break;
			case (9)  : month = "OCT"; break;
			case (10) : month = "NOV"; break;
			case (11) : month = "DEC"; break;
		}

		sprintf(disk_date,"%02d-%s-%04d",timeptr->tm_mday,month,
      											1900+timeptr->tm_year);
		sprintf(disk_time,"%02d:%02d:%02d",timeptr->tm_hour,timeptr->tm_min,timeptr->tm_sec);
		strcpy(date_time,disk_date);
		strcat(date_time,"  ");
		strcat(date_time,disk_time);
	}

   sprintf(clock_hundreths_buf,".%02d",clock_hundreths);
}

void ReadINIFile(void)
{
	char szBuf[80];
	int temp;

	getcwd(filebuf, MAXPATH);
	if(filebuf[strlen(filebuf)-1] != 0x5C) strcat(filebuf,"\\");
	strcat(filebuf,"DeltaT_StoreData.INI");

	GetPrivateProfileString("Settings", "IPAddress",
		 "192.168.0.2", szBuf, sizeof(szBuf), filebuf);
   strcpy(ip_addr,szBuf);
   if(strlen(ip_addr)==0) strcpy(ip_addr,"192.168.0.2");

	GetPrivateProfileString("Settings", "Range",
		 "30", szBuf, sizeof(szBuf), filebuf);
	temp = atoi(szBuf);
   switch(temp) {
   	case   5: range =   5; break;
   	case  10: range =  10; break;
   	case  20: range =  20; break;
   	case  30: range =  30; break;
   	case  40: range =  40; break;
   	case  50: range =  50; break;
   	case  60: range =  60; break;
   	case  80: range =  80; break;
   	case 100: range = 100; break;
		default:  range =  30; break;
   }

	GetPrivateProfileString("Settings", "Gain",
		 "3", szBuf, sizeof(szBuf), filebuf);
	gain = atoi(szBuf);
	if(gain<0 || gain>20) gain = 3;
}

void WriteINIFile(void)
{
	char buf[20];

	WritePrivateProfileString("Settings","IPAddress", ip_addr, filebuf);

	itoa(range,buf,10);
	WritePrivateProfileString("Settings","Range", buf, filebuf);

	itoa(gain,buf,10);
	WritePrivateProfileString("Settings","Gain", buf, filebuf);
}

struct timeb tbuf_t;
unsigned long tbuf_time,old_tbuf_time;
unsigned long tbuf_milli,old_tbuf_milli;
unsigned long period,avg_period;
int CP_ctr = 0;
void CalcPeriod(void)
{
	old_tbuf_time = tbuf_time;
	old_tbuf_milli = tbuf_milli;
	ftime(&tbuf_t);
	tbuf_time = tbuf_t.time;
	tbuf_milli = tbuf_t.millitm;
	period = tbuf_time - old_tbuf_time;
	period = 1000 * period;
	period = period + tbuf_milli - old_tbuf_milli;

	avg_period += period;
	CP_ctr++;
	if(CP_ctr>=10) {
		CP_ctr = 0;
		avg_period = avg_period/10;
		if(avg_period>10000) avg_period = 0;
		rep_rate = (int)(avg_period);
      if(rep_rate>2000) rep_rate = 2000;
		avg_period = 0;
	}
}
