/*
 ============================================================================
 Name        : UserSpace Main Board.c
 Author      : Ning, Guanghan
 Version     :
 Copyright   : University of Missouri
 Description : Hello World in C, Ansi-style
 ============================================================================
 */
//======================================================
//For TCP image transmit
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <time.h>
//=========================================================

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>    //header for creating threads
#include <sys/time.h>   //header for time
#include <unistd.h>
#include <fcntl.h>
#include "serial_ece4220.h"  //header for Reading from Serial Program

#include <semaphore.h>  //header for semaphores
#include "rtai.h"       //headers for rtai
#include "rtai_lxrt.h"
#include "rtai_sched.h"
#include "sys/time.h"    //header for time

//#include "stdafx.h"
#include "chenLeeCV.h"
#include "segment.h"

#define MAXSIZE 14

int kernel_pressed= 0;
int segment_finished= 0;
int flag= -1, flag1= -1; flag2= -1;
//int flag_num_received= 0;
int flag_num1_received= 0;
int flag_num2_received= 0;
int flag_num4_received= 0;
int first_time= 1;
int N_img= 1;
ClImage* segmentImg;

unsigned char rect1[MAXSIZE];
unsigned char rect2[MAXSIZE];
unsigned char rect3[MAXSIZE];
unsigned char rect4[MAXSIZE];

int digit1, digit2, digit4;
typedef struct Plate
{
	unsigned char segment1[MAXSIZE];
	unsigned char segment2[MAXSIZE];
	unsigned char segment3[MAXSIZE];
	unsigned char segment4[MAXSIZE];
}plate;
//unsigned char shared_memory[];
//==============================================================================
//Computer Vision Functions
void Read_image()
{
   free(segmentImg);

   char *imgName; //int save_success;
   sprintf(imgName, "%d%s", N_img, ".bmp");
   printf("...\n");
   segmentImg = clLoadImage(imgName);
   printf("An image has been successfully read!\n");
   printf("...\n");
   clSaveImage("result2.bmp", segmentImg);
   printf("...\n");

   //if(save_success)

   N_img++;
   if(N_img==6) N_img= 1;  //there are only 6 plate images
   kernel_pressed= 0;
}

void Segmentation(unsigned char* s1, unsigned char* s2, unsigned char* s3, unsigned char*s4)
{
	
	    KMeanType * KM;
		KM = (KMeanType *)malloc(sizeof(KMeanType));
		//KM->nKMeanClusters = 2;
		//allocate memmory for it
		kMeanInit(KM);

	    int widthStep;
	    widthStep= (segmentImg->channels)*(segmentImg->width);

		int xxx= 0, sss= 0;
		int *xx, *ss;
		xx= &xxx; ss= &sss;
	    segments( (unsigned char *)segmentImg->imageData, widthStep, 0, 0, 0, 0, KM, xx,ss);
		free(KM);

		   //resize each segment patch and recognize
			double q= 2.5;  //a character is q times the length of a "."
			int s, x;          //the scale of "."  : the number of pixels a "." occupies
			int space= 2;
			s= (*ss);
			x= (*xx);


		    //standard segment
			ClImage* standards;
		   //Get character ROIs
			CVRect rect_for_character[7];   //express with xx and ss
		    int result; int k; int more= 0;
		   for (k=0; k<7; k++)                   //from k = 2, to ignore the chinese characters before the numbers
		   {
			    //printf("This is segmentation of the %d rect of character\n", k);
				rect_for_character[k].x = x+ k* ((q*s) )+ more;
				rect_for_character[k].y = 0;
				if(k>1) rect_for_character[k].x += s;
				rect_for_character[k].height= segmentImg->height;
				rect_for_character[k].width=  q*s;

				standards = (ClImage*)malloc(sizeof(ClImage));
				standards->width= q*s;
				standards->height= segmentImg->height;
				int widStep= (standards->channels)*(standards->width);
				int wid= standards->width;
				int ht= standards->height;   //printf("WidStep, wid, ht is: %d, %d, %d\n", widStep, wid, ht);
				int i,j;
				for (i=0; i<ht; i++)
					for (j=0; j<wid; j++)
				{
					standards->imageData[i*widStep+ j*3+ k] =   segmentImg->imageData[(i+ rect_for_character[k].y)* widthStep+ (j+ rect_for_character[k].x)*3+ k];
				}
				if(k== 0) s1= standards;
				if(k== 1) s2= standards;
				if(k== 3) s4= standards;
			}
    printf("Segmentation done!\n");
}
//===============================================================================
//helpful small functions
int receive(char* msg, char* buffer, int q)
{
	int same;
	same= strncmp(msg, buffer, q);  //note that the length should be the same!!!
	if(same== 0) //means (msg == buffer)
	{
	printf("%s received!\n", msg);
	return 1;
	}
	else
	{
	//printf("%s not received!\n", msg);
	return 0;
	}
}
//================================================================================
//Functions in threads
void SendSegment4(unsigned char* s)
{
	         //send recognized number to the main board(as server)
		     int sockfd, new_fd;
		     struct sockaddr_in my_addr;
		     struct sockaddr_in their_addr;
		     unsigned int sin_size,myport,listnum;
		     myport = 2012;
		     listnum = 10; //maximum listening number > number of characters in a plate

		     if((sockfd = socket(PF_INET,SOCK_STREAM, 0)) == -1 )
		     {
		         perror("socket is error/n;");
		         exit(1);
		     }
		     my_addr.sin_family = PF_INET;
		     my_addr.sin_port = htons(myport);
		     my_addr.sin_addr.s_addr = INADDR_ANY;  //my ip address
		     bzero(&(my_addr.sin_zero),0);

		     //=====================================================
		     their_addr.sin_family = PF_INET;
		     their_addr.sin_port = htons(myport);
		     their_addr.sin_addr.s_addr =  inet_addr("10.3.52.15");  //all ip address can be clients
			 bzero(&(their_addr.sin_zero),0);
	         //========================================================

		      if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr)) == -1)
		     {
		         perror("bind is error\n");
		         exit(1);
		     }

		     if(listen(sockfd,listnum) == -1)
		     {
		         perror("listen is error\n");
		         exit(1);
		     }
		     //printf("HELLO?!\n");
		     printf("start to listen for child Board <4>\n");


		     while(1)
		     {
		         sin_size = sizeof(struct sockaddr_in);

		         if((new_fd = accept(sockfd,(struct sockaddr *)&their_addr,&sin_size)) == -1)
		         {
		             perror("accept is error\n");
		             continue;

		         }
		         printf("Main board server to send segment<4>:\n got connection from child board %s\n",inet_ntoa(their_addr.sin_addr));
               int connected = 1;

		                 char *p;
		                 char sock_buf[1024];
		                 bzero(sock_buf, 1024);
		                 p = sock_buf;

		         time_t t;  int rand_n;


		         while(connected)
		         {
		        	 if(flag>=0)
		        	 {
		        		 flag1= flag; //copy flag for another sendsegments
		        		 flag2= flag; //copy flag for another sendsegments
		        		 usleep(1000000); //wait for 1s
		        		                
		        		 printf("send 4th segment!\n");
						 if(send(new_fd, &s, MAXSIZE, 0) == -1)    //send the segment to corresponding child board
						 {
							 perror("send is error\n");
							 close(new_fd);
							 exit(0);
						 }
						 flag= -1;

		        	 }
		         }
		     }
}
void SendSegment1(unsigned char* s)
{
	         //send recognized number to the main board(as server)
		     int sockfd, new_fd;
		     struct sockaddr_in my_addr;
		     struct sockaddr_in their_addr;
		     unsigned int sin_size,myport,listnum;
		     myport = 2013;
		     listnum = 10; //maximum listening number > number of characters in a plate

		     if((sockfd = socket(PF_INET,SOCK_STREAM, 0)) == -1 )
		     {
		         perror("socket is error/n;");
		         exit(1);
		     }
		     my_addr.sin_family = PF_INET;
		     my_addr.sin_port = htons(myport);
		     my_addr.sin_addr.s_addr = INADDR_ANY;  //my ip address
		     bzero(&(my_addr.sin_zero),0);

		     //=====================================================
		     their_addr.sin_family = PF_INET;
		     their_addr.sin_port = htons(myport);
		     their_addr.sin_addr.s_addr =  inet_addr("10.3.52.14");  //all ip address can be clients
			 bzero(&(their_addr.sin_zero),0);
	         //========================================================

		      if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr)) == -1)
		     {
		         perror("bind is error\n");
		         exit(1);
		     }

		     if(listen(sockfd,listnum) == -1)
		     {
		         perror("listen is error\n");
		         exit(1);
		     }
		     //printf("HELLO?!\n");
		     printf("start to listen for child Board <1>\n");


		     while(1)
		     {
		         sin_size = sizeof(struct sockaddr_in);

		         if((new_fd = accept(sockfd,(struct sockaddr *)&their_addr,&sin_size)) == -1)
		         {
		             perror("accept is error\n");
		             continue;

		         }
		         printf("Main board server to send segment<1>:\n got connection from child board %s\n",inet_ntoa(their_addr.sin_addr));
               int connected = 1;

		                 char *p;
		                 char sock_buf[1024];
		                 bzero(sock_buf, 1024);
		                 p = sock_buf;

		         time_t t;  int rand_n;


		         while(connected)
		         {
		        	 if(flag1>=0)
		        	 {
		        		 usleep(1000000); //wait for 1s
		        		 printf("send 1st segment!\n");
						 if(send(new_fd, &s,MAXSIZE, 0) == -1)    //send the segment to corresponding child board
						 {
							 perror("send is error\n");
							 close(new_fd);
							 exit(0);
						 }
						 flag1= -1;
						 /*Only one sendsegment thread clears the flag*/
		        	 }
		         }
		     }
}
void SendSegment2(unsigned char* s)
{
	         //send recognized number to the main board(as server)
		     int sockfd, new_fd;
		     struct sockaddr_in my_addr;
		     struct sockaddr_in their_addr;
		     unsigned int sin_size,myport,listnum;
		     myport = 2014;
		     listnum = 10; //maximum listening number > number of characters in a plate

		     if((sockfd = socket(PF_INET,SOCK_STREAM, 0)) == -1 )
		     {
		         perror("socket is error/n;");
		         exit(1);
		     }
		     my_addr.sin_family = PF_INET;
		     my_addr.sin_port = htons(myport);
		     my_addr.sin_addr.s_addr = INADDR_ANY;  //my ip address
		     bzero(&(my_addr.sin_zero),0);

		     //=====================================================
		     their_addr.sin_family = PF_INET;
		     their_addr.sin_port = htons(myport);
		     their_addr.sin_addr.s_addr =  inet_addr("10.3.52.13");  //all ip address can be clients
			 bzero(&(their_addr.sin_zero),0);
	         //========================================================

		      if(bind(sockfd,(struct sockaddr *)&my_addr,sizeof(struct sockaddr)) == -1)
		     {
		         perror("bind is error\n");
		         exit(1);
		     }

		     if(listen(sockfd,listnum) == -1)
		     {
		         perror("listen is error\n");
		         exit(1);
		     }
		     printf("start to listen for child Board <2>\n");


		     while(1)
		     {
		         sin_size = sizeof(struct sockaddr_in);

		         if((new_fd = accept(sockfd,(struct sockaddr *)&their_addr,&sin_size)) == -1)
		         {
		             perror("accept is error\n");
		             continue;

		         }
		         printf("Main board server to send segment<2>:\n got connection from child board %s\n",inet_ntoa(their_addr.sin_addr));
               int connected = 1;

		                 char *p;
		                 char sock_buf[1024];
		                 bzero(sock_buf, 1024);
		                 p = sock_buf;

		         time_t t;  int rand_n;


		         while(connected)
		         {
		        	 if(flag2>=0)
		        	 {
		        		 usleep(1000000); //wait for 1s
		        		 printf("send 2nd segment!\n");
						 if(send(new_fd, &s, MAXSIZE, 0) == -1)    //send the segment to corresponding child board
						 {
							 perror("send is error\n");
							 close(new_fd);
							 exit(0);
						 }
						 flag2= -2;
						 /*Only one sendsegment thread clears the flag*/
		        	 }
		         }
		     }
}
void ReceiveNumber1(int* p_num)
{
	//Client of receiving numbers
	//Receive numbers from child boards: TCP protocal
	int sockfd;
		char buffer[1024];
		struct sockaddr_in server_addr;
		struct hostent *host;
		int portnumber,nbytes;

		if((host=gethostbyname("10.3.52.14"))==NULL)
		{
		printf("Gethostname error\n");
		exit(1);
		}
		if((portnumber=atoi("2001"))<0)
		{
		printf("Port number error\n");
		exit(1);
		}
		if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
		{
		printf("Socket Error:%s\a\n",strerror(errno));
		exit(1);
		}
		bzero(&server_addr,sizeof(server_addr));
		server_addr.sin_family=AF_INET;
		server_addr.sin_port=htons(portnumber);
		server_addr.sin_addr=*((struct in_addr *)host->h_addr);
		if(connect(sockfd,(struct sockaddr *)(&server_addr),
		sizeof(struct sockaddr))==-1)
		{
		printf("Connect Error:%s\a\n",strerror(errno));
		exit(1);
		}

		while(1)
		{
			if((nbytes=read(sockfd,buffer,1024))==-1)
			{
			printf("Read Error:%s\n",strerror(errno));
			exit(1);
			}
			buffer[nbytes]='\0';
			printf("Received number from child board(1):  %s\n",buffer);

			//Send received numbers to main thread by named pipes
			//*p_num= buffer[nbytes-1]-'0';
			*p_num= buffer[0] -'0';
			 //printf("*p_num= %d\n", *p_num);
			//Send received numbers to main thread by named pipes
			// int pipe1;
			// pipe1= open("Number1",O_WRONLY);
		    // write(pipe1, p_num, sizeof(int));
			//num1= *p_num;
			digit1= *p_num;
			flag_num1_received= 1;


			 usleep(2000000); //wait for 0.1s
		}
		 close(sockfd);

}
void ReceiveNumber2(int* p_num)
{
	//Receive numbers from child boards: TCP protocal
	int sockfd;
			char buffer[1024];
			struct sockaddr_in server_addr;
			struct hostent *host;
			int portnumber,nbytes;

			if((host=gethostbyname("10.3.52.13"))==NULL)
			{
			printf("Gethostname error\n");
			//exit(1);
			}

			if((portnumber=atoi("2002"))<0)
			{
			printf("Port number error\n");
			//exit(1);
			}
			if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
			{
			printf("Socket Error:%s\a\n",strerror(errno));
			//exit(1);
			}
			bzero(&server_addr,sizeof(server_addr));
			server_addr.sin_family=AF_INET;
			server_addr.sin_port=htons(portnumber);
			server_addr.sin_addr=*((struct in_addr *)host->h_addr);
			if(connect(sockfd,(struct sockaddr *)(&server_addr),
			sizeof(struct sockaddr))==-1)
			{
			printf("Connect Error:%s\a\n",strerror(errno));
			//exit(1);
			}

			while(1)
			{
				if((nbytes=read(sockfd,buffer,1024))==-1)
				{
				printf("Read Error:%s\n",strerror(errno));
				//exit(1);
				}
				buffer[nbytes]='\0';
				printf("Received number from child board(2):  %s\n",buffer);

				//Send received numbers to main thread by named pipes
				//*p_num= buffer[nbytes-1]-'0';
				*p_num= buffer[0] -'0';
				 //printf("*p_num= %d\n", *p_num);
				//Send received numbers to main thread by named pipes
				// int pipe1;
				// pipe1= open("Number1",O_WRONLY);
			    // write(pipe1, p_num, sizeof(int));
				//num1= *p_num;
				 digit2= *p_num;
				 flag_num2_received= 1;


				 usleep(2000000); //wait for 0.1s
			}
			 close(sockfd);

}
void ReceiveNumber4(int* p_num)
{

	//Receive numbers from child boards: TCP protocal as client
	int sockfd;
	char buffer[1024];
	struct sockaddr_in server_addr;
	struct hostent *host;
	int portnumber,nbytes;

	if((host=gethostbyname("10.3.52.15"))==NULL)
	{
	printf("Gethostname error\n");
	//exit(1);
	}

	//segmentation fault here

	if((portnumber=atoi("2004"))<0)
	{
	printf("Port number error\n");
	//exit(1);
	}
	if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
	{
	printf("Socket Error:%s\a\n",strerror(errno));
	//exit(1);
	}
	bzero(&server_addr,sizeof(server_addr));
	server_addr.sin_family=AF_INET;
	server_addr.sin_port=htons(portnumber);
	server_addr.sin_addr=*((struct in_addr *)host->h_addr);
	if(connect(sockfd,(struct sockaddr *)(&server_addr),
	sizeof(struct sockaddr))==-1)
	{
	printf("Connect Error:%s\a\n",strerror(errno));
	//exit(1);
	}

	while(1)
	{
		if((nbytes=read(sockfd,buffer,1024))==-1)
		{
		printf("Read Error:%s\n",strerror(errno));
		//exit(1);
		}
		buffer[nbytes]='\0';
		printf("Received number from child board(4):  %s\n",buffer);

		//Send received numbers to main thread by named pipes
		//*p_num= buffer[nbytes-1]-'0';
		*p_num= buffer[0] -'0';
		 //printf("*p_num= %d\n", *p_num);
		// int pipe4;
		// pipe4= open("Number4",O_WRONLY);
		// write(pipe4, p_num, sizeof(int));
		//num4= *p_num;
		 digit4= *p_num;
		 flag_num4_received= 1;
		 usleep(2000000); //wait for 0.1s
	}
	 close(sockfd);

}
void ReadImage(plate *detected_plate)
{

	int check;
	pthread_t     num1_thread;
    pthread_t     num2_thread;
    pthread_t     num3_thread;
    pthread_t     num4_thread;
    int num1, num2, num3, num4;

	int fd_fifo_in;
	fd_fifo_in= open("/dev/rtf/1", O_RDWR);  //1 is fifo_write from kernel. then it is fifo_in for user space

    //int pipe1;
   // pipe1= open("prints",O_WRONLY);
	first_time= 1;
	  while(1)
	{
		  usleep(250000);
		//read from fifo to see if button is pressed
		flag = read(fd_fifo_in, &kernel_pressed, sizeof(kernel_pressed));
		printf("\n Button is pressed!\n");
		if ((flag>=0)&&(first_time== 1))
		{
			     printf("Begin to receive number from child boards!\n");

			    check = pthread_create(&num1_thread, NULL, (void *)&ReceiveNumber1, (void *)(&num1));
				  if (check!=0)  printf("num1_thread error\n");
				check = pthread_create(&num2_thread, NULL, (void *)&ReceiveNumber2, (void *)(&num2));
				  if (check!=0)  printf("num2_thread error\n");
				//check = pthread_create(&num3_thread, NULL, (void *)&ReceiveNumber3, (void *)(&num3));
				 // if (check!=0)  printf("num3_thread error\n");*/
				check = pthread_create(&num4_thread, NULL, (void *)&ReceiveNumber4, (void *)(&num4));
				  if (check!=0)  printf("num4_thread error\n");

			     first_time= 0;
			     usleep(250000);
			     flag= -1;
		}
		if(flag>= 0)
		{
			segment_finished= 0;
			Read_image();
		    Segmentation((*detected_plate).segment1,(*detected_plate).segment2, (*detected_plate).segment3, (*detected_plate).segment4 );
		    segment_finished= 1;   //flag to indicate this for the other 2 set of threads
		    usleep(250000);
		    flag= -1;
		} else;
	}
}

//=================================================================================

int main(void)
{
	//--------------------------------------------------------------------------//
	printf("----------------------------------------------------------------\n");
	printf("---------Plate segmentation and recognition---------------------\n");
	printf("-----------------Main Board Program-----------------------------\n");
	printf("----------------------------------------------------------------\n");
	printf("\n\n\n\n\n\n\n");


   //------------------------Declaration of variables--------------------------//
   int check;
   int pipe1, pipe2, pipe3, pipe4;
   pthread_t     ReadImage_thread;

   pthread_t     seg1_thread;
   pthread_t     seg2_thread;
   pthread_t     seg3_thread;
   pthread_t     seg4_thread;

   pthread_t     num1_thread;
   pthread_t     num2_thread;
   pthread_t     num3_thread;
   pthread_t     num4_thread;
 
   plate *detected_plate= (plate*)malloc(sizeof(plate));

   int fd_fifo_in, fd_fifo_out;
   fd_fifo_in= open("/dev/rtf/1", O_RDWR);  //1 is fifo_write from kernel. then it is fifo_in for user space
   fd_fifo_out= open("/dev/rtf/0", O_RDWR);

   system("mkfifo Number1 >& /dev/null");     //create a pipe file
   system("mkfifo Number2 >& /dev/null");     //create another pipe file
   system("mkfifo Number3 >& /dev/null");     //create a pipe file
   system("mkfifo Number4 >& /dev/null");     //create another pipe file

   //Create the thread to read images from memory and do extraction and segmentation
   check = pthread_create(&ReadImage_thread, NULL, (void *)&ReadImage, (void *)(detected_plate));
   if (check!=0)  printf("ReadImage_thread error\n");
   //wait until this is finished
   //pthread_join(ReadImage_thread, NULL);

   //Create the thread to read images from memory
    check = pthread_create(&seg1_thread, NULL, (void *)&SendSegment1, (void *)((*detected_plate).segment1));
     if (check!=0)  printf("seg1_thread error\n");
   check = pthread_create(&seg2_thread, NULL, (void *)&SendSegment2, (void *)((*detected_plate).segment2));
     if (check!=0)  printf("seg2_thread error\n");
  //  check = pthread_create(&seg3_thread, NULL, (void *)&SendSegment, (void *)((*detected_plate).segment3));
   //    if (check!=0)  printf("seg3_thread error\n");
   check = pthread_create(&seg4_thread, NULL, (void *)&SendSegment4, (void *)((*detected_plate).segment4));
	 if (check!=0)  printf("seg4_thread error\n");


	  while(1)
   {
	     //exhibit the recognized numbers when button is pressed
		  if((flag_num1_received)&&(flag_num2_received)&&(flag_num4_received))
	   {
		   printf("The plate number is: ** *%d*%d%d\n", digit4, digit2, digit1);
		   flag_num1_received= 0;
		   flag_num2_received= 0;
		   flag_num4_received= 0;
	   }
   }

	  pthread_join(ReadImage_thread, NULL);

   return EXIT_SUCCESS;
}

