/*
 ============================================================================
 Name        : fp1user.c
 Author      : Stephanie Cahail
 Version     :
 Copyright   : Your copyright notice
 Description : User space of final project that resembles pet collar entity
 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <fcntl.h> //for O_RDWR
#include <math.h>
#include <string.h>

#define MSG_SIZE 70			// message size
#define R2VAL 	 10000		// constant resistor value
#define VIN	     5			// input voltage value
int flag = 0; 				// when flag is set write flag to kernel via fifo
double thermVal = 0;		// thermistor value
double temperature = 0;		// thermistor temperature
double oldTemperature = 0;	// previous thermistor temperature

char hostname[64], IP[16];
char warningMessage[MSG_SIZE];
char petNames[5];
char buffer[MSG_SIZE];	// to store received messages or messages to be sent.
int n;
struct sockaddr_in addr, from;
socklen_t fromlen;
//prints error message and exits when socket errors occur
void error(const char *msg)
{
    perror(msg);
    exit(0);
}
//converts analog voltage to digital voltage and converts digital voltage to temperature in Fahrenheit
double ADCr(void){
	double temp = 0;
    /*define variables */
    int fd = open("/dev/mem", O_RDWR|O_SYNC);

    char* control_register = (char*)mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x10F00000);
    char* reg2240 = (char*)mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x22400000);
    char* complete = (char*)mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x10800000);

    volatile int  AD_complete;
    int bit_mask_complete = 0x80, AD_installed;
    short *read_value;
    short myValue;
    read_value = (short *)control_register;
    AD_installed = *(reg2240) & 0x01;

	if(AD_installed == 0x01){

		printf("AD installed.\n");
		fflush(stdout);

		//perform ADC
		while(flag == 0){
			*control_register = 0x40; //0100 0000

			AD_complete = bit_mask_complete & *complete;


			while(AD_complete != 0x00 && flag == 0){  //wait, bit 7 = 0 on complete.
				//prevent_optimizer();
				AD_complete = bit_mask_complete & *complete;

			}

			/*conversion complete */
			myValue = *read_value;
			printf("myValue is: %d \n", myValue);
			/*convert digital voltage value to temperature in Fahrenheit via Steinhart-Hart equation*/
			//the resistance and temperature values are inversely proportional w/the thermistor
			//so that needs to be accounted for.
			temp = log(10000.0/(1024.0/myValue - 1));
			temp = 1/(0.001129148 + (0.000234125 + (0.0000000876741 * temp * temp))* temp);
			temp = temp - 273.15;//convert K to C
			temp = (temp * 9.0)/5.0 + 32.0;//convert C to F
			printf("Temperature is: %.2f\n", temp);
			return temp;
			usleep(1000000); //1s sleep
		}
	}
	else{
		printf("AD not installed.\n");
		fflush(stdout);

	}
}

int main(int argc, char* argv[]) {
   int sock, newsock, length, i;
   int permisson = 1;			// broadcast permission value
   struct hostent *hp;
   sock = socket(AF_INET, SOCK_DGRAM, 0); // Creates socket. Connectionless.
   if (sock < 0)
	   error("socket");
   length = sizeof(addr);			// length of structure
   bzero(&addr,length);		    // sets all values to zero.
   addr.sin_family = AF_INET;		// symbol constant for Internet domain
   addr.sin_addr.s_addr = INADDR_ANY;		// IP address of the machine on which
											 //the server is running
   addr.sin_port = htons(2000);
   gethostname(hostname, 64);		//get IP address
   hp = gethostbyname(hostname);
   strcpy(IP, inet_ntoa(*((struct in_addr *)hp->h_addr)));
   printf("HP name:%s\n", hp->h_name);
   printf("IP Address: %s\n", IP);

   //binds the socket to the address of the host and the port number
   if (bind(sock, (struct sockaddr *)&addr, length) < 0)
	   error("binding");
   // change socket permissions to allow broadcast
   if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &permisson, sizeof(permisson)) < 0)
	{
		printf("error setting socket options\n");
		exit(-1);
	}
   fromlen = sizeof(struct sockaddr_in);	// size of structure
   	//fifo initialization
   	int fifo1 = open("/dev/rtf/1", O_RDWR);
   	if(fifo1 == -1){
   		printf("error.\n");
   		exit(-1);
   	}
   while (1)
   {
	    bzero(buffer, MSG_SIZE); //clear buffer
		temperature = ADCr(); //obtain temperature
       //obtain initialization message from client
	    n = recvfrom(sock, buffer, MSG_SIZE, 0, (struct sockaddr *)&addr, &fromlen);
	    if (n < 0)
		   error("recvfrom");
	    printf("%s\n", buffer);
	    }
        //if temperature is below 100.5 degrees send low temp warning message to client
	    if(temperature < 100.5){
	       bzero(buffer, MSG_SIZE);
		   sprintf(buffer, "%s %s", IP, "has low body heat. Take immediate action. ");
		   addr.sin_addr.s_addr = inet_addr("10.3.52.255");		// broadcast address
		   n = sendto(sock, buffer, MSG_SIZE, 0, (struct sockaddr *)&addr, fromlen);
		   if (n < 0)
			   error("sendto");
	    }
        //if temperature is above 102.5 degrees send high temp warning message to client
	    else if(temperature > 102.5){
	       bzero(buffer, MSG_SIZE);
		   sprintf(buffer, "%s %s", IP, "has high body heat. Take immediate action. ");
		   addr.sin_addr.s_addr = inet_addr("10.3.52.255");		// broadcast address
		   n = sendto(sock, buffer, MSG_SIZE, 0, (struct sockaddr *)&addr, fromlen);
		   if (n < 0)
			   error("sendto");
	    }
        //if temperature is within range send regular temp message to client
	    else{
	    	bzero(buffer, MSG_SIZE);
	    	sprintf(buffer, "%s %s", IP, "has a regular temperature. ");
		    n = sendto(sock, buffer, MSG_SIZE, 0, (struct sockaddr *)&addr, fromlen);
		    if (n < 0)
			   error("sendto");
	    }
   }
   return 0;
}



