/*
 *      SendCMD_ACK_server.c
 *      
 *      Il programma fa scegliere all'utente il nodo da comandare e il comando da far eseguire, stampa il pacchetto inviato al nodo, rimane in attesa  	*	dell'ACK e stampa "ACK!" quando arriva il pacchetto di ack spedito dal nodo.
 *	
 *
 *	Struttura del pacchetto da trasmettere: 00 FF FF 00 00 04 22 08 XX YY YY ZZ	(vedere README)
 *
 *	E' presente ache un Time-out nel caso in cui non arrivi l'ACK.
 * 
 *      Per la parte di spedizione del comando si è preso spunto dal programma sfsend.c e per la parte di ricezione dell'ACK si è preso spunto dal
 *	programma sflisten.c
 * 	
 *	Vengono sfruttate 3 funzioni implementate in sfsource.c:
 *		- open_sf_source
 *		- write_sf_packet
 *		- read_sf_packet
 * 	
 *	
 *
 *	AGGIORNAMENTO: Architettura client-server: il client permette di scegliere il comando da inviare al nodo e il server lo riceve, lo inoltra
 *			alla wsn tramite sf, attende la risposta e la gira al client.
 *		N.B. E' presente un controllo per stabilire se il pacchetto arrivato è un ACK o un comando ritrasmesso in Broadcast
 *		 
 */



#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include "sfsource.h"					//libreria per la comunicazione con i mote


#define dim 12						//fisso la dimensione del pacchetto



void timeout(int s)
{
	printf("TIMEOUT\n");
	exit(1);
} 

int main(int argc, char** argv)
{
	int fd_sf;
	
	
	signal(SIGALRM, timeout);
	
	
	int 				fd;
	int				newfd;
	int				clen;
	struct sockaddr_in		saddr;
	struct sockaddr_in		caddr;
	int				nodeID;
	int				command;
	char 				buff[10];
	int				seqno = 0;
	int				flag;
	
	if (argc != 3) {
		printf( "Numero di parametri errato\n");		// localhost: 9002
		exit(1);
	}
	
	fd = socket(AF_INET, SOCK_STREAM, 0);
	
	saddr.sin_family		= AF_INET;
	saddr.sin_addr.s_addr	= INADDR_ANY;				
	saddr.sin_port			= htons(1745);
	
	bind(fd,(struct sockaddr *) &saddr, sizeof(saddr));
	listen (fd,5);

	



	while(1) {
		
		printf( "Server in ascolto\n");

		flag = 1;
		
		newfd = accept ( fd, (struct sockaddr *) &caddr, &clen );

		recv(newfd, &nodeID, 1, 0);		//ricevo l'ID del nodo da comandare

		recv(newfd, &command, 1, 0);		//ricevo il comando da spedire

	

		fd_sf = open_sf_source(argv[1],atoi(argv[2]));		//apro una connessione con il sf
	
		if(fd_sf<0)
		{
			fprintf(stderr,"Couldn't open serial forwarder at %s : %s \n",argv[1],argv[2]);
			exit(1);
			}


	
			
	

		unsigned char Byte[dim];			
	

		// riempio il pacchetto
	
		Byte[0]=0x00;					// indica che si tratta di un AM packet

		Byte[1]=0xff;					// destination address
		Byte[2]=0xff;					

		Byte[3]=0x00;					// link source address
		Byte[4]=0x00;

		Byte[5]=0x04;					// message length
	
		Byte[6]=0x22;					// group ID

		Byte[7]=0x08;					// handler ID
	
		
		if(command==1)
		{
			Byte[8]=0x01;				
		}
	
		else  Byte[8]=0x02;				


		Byte[9] = 0x00;

		Byte[10] = nodeID;

		seqno++;

		Byte[11] = seqno;

		
	
		int i;


		fprintf(stderr,"Sending to SerialForwarder");
	  	for (i = 0; i < dim; i++)

	   	 fprintf(stderr, " %02x", Byte[i]); 
	  	fprintf(stderr, "\n");	


		write_sf_packet(fd_sf,Byte,dim); 		//spedisco il pacchetto al sf

	
		alarm(5);
	
		
		
		printf("In attesa di una risposta\n");
		
		const unsigned char* packet;
	
		int len;

		while(flag) {
	
			packet = read_sf_packet(fd_sf,&len);		//leggo un qualsiasi pacchetto proveniente dalla BS
		
			if(!packet)
				exit(0);


			if(packet[8]==0)			// se è un pacchetto di ACK procedi, altrimenti rifai il ciclo
								// N.B. Non c'è bisogno di un controllo sugli Ack doppioni perchè arrivato un ACK con 
				flag=0;				// seqno pari a X, la flag viene posta a 0, il ciclo while(1) viene completato e si 
								// ricomincia solo se viene inviato un nuovo comando con seqno = X+1
			}
			

		for(i=0;i<dim;i++)
		printf("%02x ",packet[i]);
		putchar('\n');


			
		strcpy(buff,"ACK!");


		send(newfd, buff, sizeof(buff),0);	
		
		printf( "Dati spediti al client\n");	
		
		alarm(0);		
		
		close(newfd);
		
		fflush(stdout);
		free((void*)packet);
				
	
				
		close(fd_sf);
		
		}
		
		

	return 0;
	
	
} 
