/*************************************************************
 * 	Thickness Measurement TCP/IP Control Example program
 *      Broadsens Corporation
 * 
 *   Tested under Linux environment
 *   To compile:  gcc control.c -o control
 *   To run:   ./control	 
 * Contact:	support@broadsens.com
 *   Copyright protected. Shall not be distributed to 3rd parties
 *   without written consent from Broadsens Corporation
 * 			10/8/2020
 * **********************************************************/
// 6/8/2021: Added hardware trigger support 
// 6/21/2021: Added analysis window
// 8/3/2021: Added DAQ delay

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>

// Maximum number of bytes to transfer in a packet
#define MAXLINE 4096

// UT200S TCP port
#define SERVERPORT 8877

// UT200S TCP address. Please change the following to the correct ip address
#define TCPSERADDR1 "192.168.1.216" 

// Function to receive result data file from UT200S
// fsize is the number of bytes to be received
void receivedata(int sockfd, uint32_t fsize);

int main(int argc, char* argv[])
{
	int n; // Number of bytes received
    char buff[MAXLINE] = {0};	
	uint16_t  wavespeed=6072;	// Default wave speed
	uint32_t fsize;   // Data size to be transferred from UT200S
	uint8_t VGC1=0x0,VGC2=0x0,VGC3=0x0,VGC4=0x0;
	// TCP socket 
	int sockfd;
	struct sockaddr_in serveraddr;
	memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(SERVERPORT);
    if (inet_pton(AF_INET, TCPSERADDR1, &serveraddr.sin_addr) < 0)
    {
        perror("IPaddress Convert Error");
        exit(1);
    }


	while(1)	
	{
		printf("Please input command (c or d or x)\n");
		printf("c: configuration (Auto VGC); s: single-step  m: multiple (60) steps t: trigger (60 times); x: exit\n");
		
		// Obtain user selection
		char c=getchar();
		
		// configuration command (auto VGC command)
		if(c=='c')  
		{
			// Need to create socket for each command
		    sockfd = socket(AF_INET, SOCK_STREAM, 0);
			if (sockfd < 0) 
			{
				perror("Can't allocate sockfd");
				exit(1);
			}
			if (connect(sockfd, (const struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0)
			{
				perror("Connect to server Error");
				exit(1);
			}
			bzero(buff,MAXLINE);
			
			// Command start bytes
			buff[0]=0xAA; buff[1]=0x55;
			
			// Configuration parameters
			buff[2]=0x11;
			
			// Command end bytes
			buff[3]=0xAA;buff[4]=0x55;
			
			// Send configuration commands to UT200S	
			if (send(sockfd, buff, MAXLINE, 0) == -1)
			{
				perror("Can't send configuration command\n");
				exit(1);
			}
			printf("configuration command (Auto VGC) sent\n");
			
			// Receive response from UT200S
			bzero(buff,MAXLINE);
			n = recv(sockfd, buff, MAXLINE, 0);
			// correct response
			if(buff[0]==0xAA && buff[1]==0x55 && buff[12]==0xAA && buff[13]==0x55)
			{
				printf("received confirmation from device %x:%x:%x:%x:%x:%x\n",buff[2],buff[3],buff[4],buff[5],buff[6],buff[7]);
				VGC1=buff[8];
				VGC2=buff[9];
				VGC3=buff[10];
				VGC4=buff[11];
				printf("VGC gains are %d %d %d %d\n",VGC1,VGC2,VGC3,VGC4);
			}
			else   // error in response. Print out data received
			{
				printf("received confirmation from device %x:%x:%x:%x:%x:%x\n",buff[2],buff[3],buff[4],buff[5],buff[6],buff[7]);
				VGC1=buff[8];
				VGC2=buff[9];
				VGC3=buff[10];
				VGC4=buff[11];
				printf("VGC gains are %d %d %d %d\n",VGC1,VGC2,VGC3,VGC4);
				printf("Ending bytes are %d %d\n",buff[12],buff[13]);
			}
			  
			close(sockfd);  // close socket after configuration
		}
		
		// single-step measurement
		if(c=='s')		
		{
			// Need to create socket for each command
			sockfd = socket(AF_INET, SOCK_STREAM, 0);
			if (sockfd < 0) 
			{
				perror("Can't allocate sockfd");
				exit(1);
			}
			if (connect(sockfd, (const struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0)
			{
				perror("Connect to server Error");
				exit(1);
			}
			bzero(buff,MAXLINE);
			buff[0]=0xAA; buff[1]=0x55;  //starting bytes
			buff[2]=0x01;			// mode
			buff[3]=(uint8_t)(wavespeed>>8);  // wavespeed high byte
			buff[4]=(uint8_t)wavespeed;		//wavespeed low byte
			buff[5]=1; buff[6]=11; buff[7]=20;  // probe 1 delay: 1.1120
			buff[8]=1; buff[9]=65;buff[10]=03;    // probe 2 delay: 1.6503
			buff[11]=1; buff[12]=0;buff[13]=20;   // probe 3 delay: 1.0020
			buff[14]=1; buff[15]=0;buff[16]=10;  // probe 4 delay: 1.0010
			buff[17]=0x01;	 // Default value is 0x01: 4096 points. 0x02: 8192 points; 0x00: 2048 points
			buff[18]=VGC1;   // Ch1 VGC gain
			buff[19]=VGC2;   // Ch2 VGC gain
			buff[20]=VGC3;   // Ch3 VGC gain
			buff[21]=VGC4;   // Ch3 VGC gain
			buff[22]=0x01;	 // Ch1 enable
			buff[23]=0x01;	 // Ch2 enable
			buff[24]=0x01;	 // Ch3 enable
			buff[25]=0x01;	 // Ch4 enable
			buff[26]=0x00;	 // 0: transfer thickness plus data; 1: only send thickness results, no data
			buff[27]=0x00;	 // External trigger disabled
			buff[28]=0x01;   // Analysis window starting point high byte. In this example, starting point is 300 (256+44)
			buff[29]=0x2C;   // Analysis window starting point low byte. 
			buff[30]=0x08;	 // Analysis window ending point high byte. In this example, ending point is 2048 
			buff[31]=0x00;	 // Analysis window ending point low byte. 
			buff[32]=0x15;	 // DAQ delay of 21 us. 
			buff[33]=0;
			buff[34]=0;
			buff[35]=0;
			buff[36]=0xAA;buff[37]=0x55;  // ending bytes
			
			if (send(sockfd, buff, MAXLINE, 0) == -1)
			{
				perror("Can't send command\n");
				exit(1);
			}
			printf("Data acquisition & measurement starting command sent\n");
			
			usleep(1000);   // Attention. This one needs longer delay
			
			// Start receiving response from UT200S
			bzero(buff,MAXLINE);
			n=recv(sockfd,buff,MAXLINE,0);
			if(n>0 && buff[0]==0xAA && buff[1]==0x55 && buff[6]==0xAA && buff[7]==0x55)
			{
				fsize=(uint32_t)buff[2]<<24|(uint32_t)buff[3]<<16|(uint32_t)buff[4]<<8|(uint32_t)buff[5];
				printf("Data size to be received is %d\n",fsize);
			}

			receivedata(sockfd,fsize);
			// send "stop" command to disconnect from UT200S
			bzero(buff,MAXLINE);
			buff[0]=0xAA; buff[1]=0x55;
			buff[2]=0x88;
			buff[3]=0xAA;buff[4]=0x55;

			if (send(sockfd, buff, MAXLINE, 0) == -1)
			{
				perror("Can't send configuration command\n");
				exit(1);
			}
			printf("stop command sent\n");
			close(sockfd);  // close socket connection.
			
		}
		
		 // multiple-step continuous measurement. In the following example, continuously taking data for 60 times
		if(c=='m') 
		{
			// Only need to create socket once in continuous mode 
			sockfd = socket(AF_INET, SOCK_STREAM, 0);
			if (sockfd < 0) 
			{
				perror("Can't allocate sockfd");
				exit(1);
			}
			if (connect(sockfd, (const struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0)
			{
				perror("Connect to server Error");
				exit(1);
			}
			
			// In the following, we continuously take data for 60 times
			for (int j=0;j<60;j++)
			{
				bzero(buff,MAXLINE);
				buff[0]=0xAA; buff[1]=0x55;  //starting bytes
				buff[2]=0x01;			// mode
				buff[3]=(uint8_t)(wavespeed>>8);  // wavespeed high byte
				buff[4]=(uint8_t)wavespeed;		//wavespeed low byte
				buff[5]=1; buff[6]=11; buff[7]=20;  // probe 1 delay: 1.1120
				buff[8]=1; buff[9]=65;buff[10]=03;    // probe 2 delay: 1.6503
				buff[11]=1; buff[12]=0;buff[13]=20;   // probe 3 delay: 1.0020
				buff[14]=1; buff[15]=0;buff[16]=10;  // probe 4 delay: 1.0010
				buff[17]=0x00;	 // 2048 points. 
				buff[18]=VGC1;   // Ch1 VGC gain
				buff[19]=VGC2;   // Ch2 VGC gain
				buff[20]=VGC1;   // Ch3 VGC gain
				buff[21]=VGC2;   // Ch4 VGC gain
				buff[22]=0x01;	 // Ch1 enable
				buff[23]=0x01;	 // Ch2 enable
				buff[24]=0x01;	 // Ch3 enable
				buff[25]=0x01;	 // Ch4 enable
				buff[26]=0x00;	 // 0: Transfer result plus  data; 1: transfer only thickness results
				buff[27]=0x00;	 // External trigger disabled
				buff[28]=0x01;   // Analysis window starting point high byte. In this example, starting point is 300 (256+44)
				buff[29]=0x2C;   // Analysis window starting point low byte. 
				buff[30]=0x08;	 // Analysis window ending point high byte. In this example, ending point is 2048 
				buff[31]=0x00;	 // Analysis window ending point low byte. 
				buff[32]=0x08;	 // DAQ delay of 8 us
				buff[33]=0;
				buff[34]=0;
				buff[35]=0;
				buff[36]=0xAA;buff[37]=0x55;  // ending bytes
				
				// Send out start command
				if (send(sockfd, buff, MAXLINE, 0) == -1)
					perror("Can't send command\n");
				
				printf("Data acquisition & measurement starting command sent\n");
				usleep(200); // Attention: wait for 200us. Can't wait too long since data may be lost
				// Start receiving confirmation about data file length
				bzero(buff,MAXLINE);
				n=recv(sockfd,buff,MAXLINE,0);
				if(n>0 && buff[0]==0xAA && buff[1]==0x55 && buff[6]==0xAA && buff[7]==0x55)
				{
					fsize=(uint32_t)buff[2]<<24|(uint32_t)buff[3]<<16|(uint32_t)buff[4]<<8|(uint32_t)buff[5];
					printf("Data size to be received is %d\n",fsize);
				}
				
				// Call receivedata function to receive the result data file
				receivedata(sockfd,fsize);
			}
			
			// After continous mode is finished, send "stop" command to disconnect from UT200S
			bzero(buff,MAXLINE);
			buff[0]=0xAA; buff[1]=0x55;
			buff[2]=0x88;	// Disconnect command
			buff[3]=0xAA;buff[4]=0x55;
			// Send out stop command
			if (send(sockfd, buff, MAXLINE, 0) == -1)
			{
				perror("Can't send stop command\n");
				exit(1);
			}
			printf("stop command sent\n");
			close(sockfd);  // close socket connection after finishing continuous mode
			
			
		}
		
		// trigger measurement (Multiple measurements) 
		if(c=='t') 
		{
			// Only need to create socket once in continuous mode 
			sockfd = socket(AF_INET, SOCK_STREAM, 0);
			if (sockfd < 0) 
			{
				perror("Can't allocate sockfd");
				exit(1);
			}
			if (connect(sockfd, (const struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0)
			{
				perror("Connect to server Error");
				exit(1);
			}
			
			bzero(buff,MAXLINE);
			buff[0]=0xAA; buff[1]=0x55;  //starting bytes
			buff[2]=0x01;			// mode
			buff[3]=(uint8_t)(wavespeed>>8);  // wavespeed high byte
			buff[4]=(uint8_t)wavespeed;		//wavespeed low byte
			buff[5]=1; buff[6]=11; buff[7]=20;  // probe 1 delay: 1.1120
			buff[8]=1; buff[9]=65;buff[10]=03;    // probe 2 delay: 1.6503
			buff[11]=1; buff[12]=0;buff[13]=20;   // probe 3 delay: 1.0020
			buff[14]=1; buff[15]=0;buff[16]=10;  // probe 4 delay: 1.0010
			buff[17]=0x00;	 // 2048 points. 
			buff[18]=VGC1;   // Ch1 VGC gain
			buff[19]=VGC2;   // Ch2 VGC gain
			buff[20]=VGC1;   // Ch3 VGC gain
			buff[21]=VGC2;   // Ch4 VGC gain
			buff[22]=0x01;	 // Ch1 enable
			buff[23]=0x01;	 // Ch2 enable
			buff[24]=0x01;	 // Ch3 enable
			buff[25]=0x01;	 // Ch4 enable
			buff[26]=0x00;	 // Transfer all data
			buff[27]=0x01;	 // External trigger enabled
			buff[28]=0x01;   // Analysis window starting point high byte. In this example, starting point is 300 (256+44)
			buff[29]=0x2C;   // Analysis window starting point low byte. 
			buff[30]=0x08;	 // Analysis window ending point high byte. In this example, ending point is 2048 
			buff[31]=0x00;	 // Analysis window ending point low byte. 
			buff[32]=0x20;	 // DAQ delay of 32 us
			buff[33]=0;
			buff[34]=0;
			buff[35]=0;
			buff[36]=0xAA;buff[37]=0x55;  // ending bytes
			
			// Send out start command
			if (send(sockfd, buff, MAXLINE, 0) == -1)
				perror("Can't send command\n");
			printf("Data acquisition & measurement starting command sent\n");
			usleep(200); // Attention: wait for 200us. Can't wait too long since data may be lost
			// Start receiving confirmation about data file length
			bzero(buff,MAXLINE);
			n=recv(sockfd,buff,MAXLINE,0);
			if(n>0 && buff[0]==0xAA && buff[1]==0x55 && buff[6]==0xAA && buff[7]==0x55)
			{
				fsize=(uint32_t)buff[2]<<24|(uint32_t)buff[3]<<16|(uint32_t)buff[4]<<8|(uint32_t)buff[5];
				printf("Data size to be received is %d\n",fsize);
			}
			
			// Call receivedata function to receive the result data file
			receivedata(sockfd,fsize);			
			
			// In the following, we continuously take data for 60 times
			for (int j=0;j<60;j++)
			{
				bzero(buff,MAXLINE);
				buff[0]=0xAA; 
				buff[1]=0x55;  //starting bytes
				buff[2]=0x99;			// continue command in trigger mode
				buff[3]=0xAA;
				buff[4]=0x55;  // ending bytes
				
				// Send out start command
				if (send(sockfd, buff, MAXLINE, 0) == -1)
				{
					perror("Can't send command\n");
					exit(1);
				}
				printf("Data acquisition & measurement starting command sent\n");
				usleep(300); // Attention: wait for 200us. Can't wait too long since data may be lost
				// Start receiving confirmation about data file length
				bzero(buff,MAXLINE);
				n=recv(sockfd,buff,MAXLINE,0);
				if(n>0 && buff[0]==0xAA && buff[1]==0x55 && buff[6]==0xAA && buff[7]==0x55)
				{
					fsize=(uint32_t)buff[2]<<24|(uint32_t)buff[3]<<16|(uint32_t)buff[4]<<8|(uint32_t)buff[5];
					printf("Data size to be received is %d\n",fsize);
				}
				
				// Call receivedata function to receive the result data file
				receivedata(sockfd,fsize);
			}
			// After continous mode is finished, send "stop" command to disconnect from UT200S
			bzero(buff,MAXLINE);
			buff[0]=0xAA; buff[1]=0x55;
			buff[2]=0x88;	// Disconnect command
			buff[3]=0xAA;buff[4]=0x55;
			// Send out stop command
			if (send(sockfd, buff, MAXLINE, 0) == -1)
				perror("Can't send stop command\n");
			else
				printf("stop command sent\n");
			close(sockfd);  // close socket connection after finishing continuous mode					
			
		}
		// Exit command
		if(c=='x')
		{

		
			break;
			
		}
	

	} //while(1)
	
    return 0;
}

// This function will receive the result file from UT200S.
// The function checks the total number of bytes until all data are received from the UT200S
// The data will be saved into a file called "data.dat"

void receivedata(int sockfd, uint32_t fsize)
{
	struct timeval begin , now;
	double timediff;
    ssize_t n;
	int total=0;
    char buff[MAXLINE];
    bzero(buff,MAXLINE);
    char *filename = "data.dat";   // Receive file name
	FILE *fp = fopen(filename, "wb");
	if (fp == NULL) 
	{
		perror("Can't open file to write");
		exit(1);
	}
    
    while ( total< fsize) // total is the size of data received
    {
	    n = recv(sockfd, buff, MAXLINE, 0);
        if (n == -1)
        {
            perror("Receive data Error");
            
        }
        
        if (fwrite(buff, sizeof(char), n, fp) != n)
        {
            perror("Write File Error");
           
        }
        bzero(buff,MAXLINE);
        total=total+n;
    }
    printf("Total bytes received is:%d\n",total);
    fclose(fp);
}
