#include <stdio.h>
#include <sys/socket.h>
#include <signal.h>

#include "pcap.h"

#include "node.h"
#include "hash.h"
#include "geom.h"

#define MAX_BUFF_LEN	1024

#define WLAN_DEVNAMELEN_MAX 16

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
typedef unsigned long long uint64_t;
/*typedef long int32_t;
*/
typedef struct {
        uint32_t did __attribute__ ((packed));
        uint16_t status __attribute__ ((packed));
        uint16_t len __attribute__ ((packed));
        uint32_t data __attribute__ ((packed));
    } p80211item_uint32_t;

    typedef struct {
        uint32_t msgcode __attribute__ ((packed));
        uint32_t msglen __attribute__ ((packed));
        uint8_t devname[WLAN_DEVNAMELEN_MAX] __attribute__ ((packed));
        p80211item_uint32_t hosttime __attribute__ ((packed));
        p80211item_uint32_t mactime __attribute__ ((packed));
        p80211item_uint32_t channel __attribute__ ((packed));
        p80211item_uint32_t rssi __attribute__ ((packed));
        p80211item_uint32_t sq __attribute__ ((packed));
        p80211item_uint32_t signal __attribute__ ((packed));
        p80211item_uint32_t noise __attribute__ ((packed));
        p80211item_uint32_t rate __attribute__ ((packed));
        p80211item_uint32_t istx __attribute__ ((packed));
        p80211item_uint32_t frmlen __attribute__ ((packed));
    } wlan_ng_prism2_header;


/* Current hash */
static Hash curWifi;
/* Calibrated hash */
static Hash clbrWifi;

/* Message buffer */
static char msgBuf[MAX_BUFF_LEN];


int sendMsg(const char* msg){
	fprintf(stdout,"%s\n", msgBuf);	
return 0;
}

int rcvMsg(char* msg){
  int bufLen;

	fgets(msg, MAX_BUFF_LEN, stdin);

	if( feof(stdin) )
		return E_END;

	bufLen = strlen(msg);
	/* Get rid of possible eol */
	if( msg[bufLen-1] == '\n' )
		msg[bufLen-1] = 0;
return 0;
}


void gotPacket(u_char* args, const struct pcap_pkthdr *header, const u_char* packet){
int offset;
wlan_ng_prism2_header *hdr;
signed char* buf;
WifiPair pair;
	
	memset(&pair, 0, sizeof(WifiPair));

	offset = sizeof(wlan_ng_prism2_header)+4+6;
	hdr = (wlan_ng_prism2_header*)packet;

	pair.S = hdr->signal.data;
	pair.tx.mac.str[0] = *((unsigned char*)hdr+offset);
	pair.tx.mac.str[1] = *((unsigned char*)hdr+offset+1);
	pair.tx.mac.str[2] = *((unsigned char*)hdr+offset+2);
	pair.tx.mac.str[3] = *((unsigned char*)hdr+offset+3);
	pair.tx.mac.str[4] = *((unsigned char*)hdr+offset+4);
	pair.tx.mac.str[5] = *((unsigned char*)hdr+offset+5);

	upsertHash(&curWifi, &pair);
/*
	buf = (char*)&hdr->signal.data;
	printf("\nPacket len %i, signal %i mac ", header->len, hdr->signal.data);
	while(offset<sizeof(wlan_ng_prism2_header)+4+6+6){
		printf("%02X:",*((unsigned char*)hdr+offset));
		++offset;
	}
*/
}

int buildMsg(char* msg, const WifiPair* pair){

	sprintf(msgBuf,"%X %02X:%02X:%02X:%02X:%02X:%02X %f %f %f %i %02X:%02X:%02X:%02X:%02X:%02X %f %f %f %hu %i %f %f %hu %f %hu | %f %f %f" ,
		pair->type, 
		pair->tx.mac.str[0],
		pair->tx.mac.str[1],
		pair->tx.mac.str[2],
		pair->tx.mac.str[3],
		pair->tx.mac.str[4],
		pair->tx.mac.str[5],
		pair->tx.X,
		pair->tx.Y,
		pair->tx.Z,
		pair->tx.Gain,
		pair->rx.mac.str[0],
                pair->rx.mac.str[1],
                pair->rx.mac.str[2],
                pair->rx.mac.str[3],
                pair->rx.mac.str[4],
                pair->rx.mac.str[5],
                pair->rx.X,
                pair->rx.Y,
                pair->rx.Z,
                pair->rx.Gain,
		pair->time,
		pair->nPow,
		pair->S,
		pair->numS,
		pair->R,
		pair->numR ,
		pair->ErMax,
		pair->ErMin,
		pair->ErM );
return 0;
}

int parseMsg(const char* msg, WifiPair* pair){

	if(*msgBuf=='#' || *msgBuf==0)
		return 0;

	sscanf(msgBuf,"%X %02X:%02X:%02X:%02X:%02X:%02X %f %f %f %i %02X:%02X:%02X:%02X:%02X:%02X %f %f %f %hu %i %f %f %hu %f %hu",
		&pair->type, 
		&pair->tx.mac.str[0],
		&pair->tx.mac.str[1],
		&pair->tx.mac.str[2],
		&pair->tx.mac.str[3],
		&pair->tx.mac.str[4],
		&pair->tx.mac.str[5],
		&pair->tx.X,
		&pair->tx.Y,
		&pair->tx.Z,
		&pair->tx.Gain,
		&pair->rx.mac.str[0],
                &pair->rx.mac.str[1],
                &pair->rx.mac.str[2],
                &pair->rx.mac.str[3],
                &pair->rx.mac.str[4],
                &pair->rx.mac.str[5],
                &pair->rx.X,
                &pair->rx.Y,
                &pair->rx.Z,
                &pair->rx.Gain,
		&pair->time,
		&pair->nPow,
		&pair->S,
		&pair->numS,
		&pair->R,
		&pair->numR);

	if( pair->type & (C_RXYZ | C_TXYZ) ){
	  pair->R = sqrt( (pair->rx.X-pair->tx.X)*(pair->rx.X-pair->tx.X) +
			  (pair->rx.Y-pair->tx.Y)*(pair->rx.Y-pair->tx.Y) +
			  (pair->rx.Z-pair->tx.Z)*(pair->rx.X-pair->tx.Z) );
	  pair->type |= C_RADIUS;
	}

return 0;
}


void outputResult(int sig){
int stat;
Iterator it;
WifiPair* pair;

	/*printf("\n#Results\n");*/

	/* Save current records */
	if( (stat=getFirstHash(&curWifi, &it)) ){
		if( stat != E_END )
			exit(1);
	}else
	while(1){
	
		pair = (WifiPair*) it.ptr;

		buildMsg(msgBuf, pair);
		sendMsg(msgBuf);

		if( (stat = getNextHash(&curWifi, &it)) )
			if( stat != E_END )
				exit(1);
			else
				break;
	};

	/* Save calibrated records */
	if( (stat=getFirstHash(&clbrWifi, &it)) ){
		if( stat != E_END )
			exit(1);
	}else
	while(1){
	
		pair = (WifiPair*) it.ptr;
		
		buildMsg(msgBuf, pair);
		sendMsg(msgBuf);

		if( (stat = getNextHash(&clbrWifi, &it)) )
			if( stat != E_END )
				exit(1);
			else
				break;
	};

exit(0);
}


int initLoad(){
int stat;
WifiPair pair;	

	while( !(stat = rcvMsg(msgBuf)) ){
		/* if this message is not valid - no problem - read next one */
		if( !parseMsg(msgBuf, &pair) ){
			if( !pair.type )
				stat = upsertHash(&curWifi, &pair);
			else
				stat = upsertHash(&clbrWifi, &pair);

			if(stat)
				return stat;
		}
	}

	if( stat != E_END )
		return stat;

return 0;
}


int calibrateNmaxR(){
int stat;
WifiPair* pMin;
WifiPair* pMax;
WifiPair* pCur;
WifiPair radPair;
Iterator it;

	/* Find calibrated records with known radius */
	memset( &radPair, 0, sizeof(WifiPair) );
	radPair.type = C_RADIUS | C_SIGNAL;

	if( (stat = getFirstHashFilter(&clbrWifi, &radPair, isEqType, &it)) )
		return stat;
	
	pMin = (WifiPair*)it.ptr;
	pMax = (WifiPair*)it.ptr;

	while(1){
		pCur = (WifiPair*)it.ptr;

		/* Find record with min and max radius - 
		it will give us minimal deviation */	
		if( pMin->R > pCur->R )
			pMin = pCur;

		if( pMax->R < pCur->R )
                        pMax = pCur;
	
 		if( (stat = getNextHashFilter(&clbrWifi, &radPair, isEqType, &it)) )
			if( stat == E_END )
				break;
			else
                		return stat;		
	} 

	if( pMax == pMin || !pMin->R )
		return E_NORESULT;

	/* Calculation of n */
	radPair.nPow = ( pMin->S - pMax->S + 
			pMin->tx.Gain - pMax->tx.Gain + 
			pMin->rx.Gain - pMax->rx.Gain ) / 
			(10 * log10( pMax->R / pMin->R ));

	radPair.type = C_NPOW;

	stat = upsertHash( &clbrWifi, &radPair );

return stat;
}

int calcRmaxDS(WifiPair* p, float n){
int stat;
WifiPair* pMaxDS;
WifiPair* pCur;
WifiPair radPair;
Iterator it;

	if( !p )
		return E_BADINPUT;

	/* Find calibrated records with known radius */
	memcpy( &radPair, p, sizeof(WifiPair) );
	radPair.type = C_SIGNAL;

	if( (stat = getFirstHashFilter(&clbrWifi, &radPair, isEqTypeNoSelf, &it)) )
		return stat;

	pMaxDS = (WifiPair*)it.ptr;

	while(1){
		
		pCur = (WifiPair*)it.ptr;

		if( p->R / pCur->R > p->R / pMaxDS->R )
			pMaxDS = pCur;

 		if( (stat = getNextHashFilter(&clbrWifi, &radPair, isEqTypeNoSelf, &it)) )
			if( stat == E_END )
				break;
			else
                		return stat;		
	}
	
	p->R = pow(10, (pMaxDS->S - p->S + pMaxDS->rx.Gain - p->rx.Gain + pMaxDS->tx.Gain - p->tx.Gain )/(10*n)) * pMaxDS->R;

return 0;
}

int calcRminDS(WifiPair* p, float n){
int stat;
WifiPair* pMinDS;
WifiPair* pCur;
WifiPair radPair;
Iterator it;

	if( !p )
		return E_BADINPUT;

	/* Find calibrated records with known radius */
	memcpy( &radPair, p, sizeof(WifiPair) );
	radPair.type = C_SIGNAL;

	if( (stat = getFirstHashFilter(&clbrWifi, &radPair, isEqTypeNoSelf, &it)) )
		return stat;

	pMinDS = (WifiPair*)it.ptr;

	while(1){
		
		pCur = (WifiPair*)it.ptr;

		if( p->R / pCur->R < p->R / pMinDS->R )
			pMinDS = pCur;

 		if( (stat = getNextHashFilter(&clbrWifi, &radPair, isEqTypeNoSelf, &it)) )
			if( stat == E_END )
				break;
			else
                		return stat;		
	}
	
	p->ErMin = p->R - pow(10, (pMinDS->S - p->S + pMinDS->rx.Gain - p->rx.Gain + pMinDS->tx.Gain - p->tx.Gain )/(10*n)) * pMinDS->R;

return 0;
}

int calcRmean(WifiPair* p, float n){
int stat;
WifiPair* pCur;
WifiPair radPair;
Iterator it;

	if( !p )
		return E_BADINPUT;

	/* Find calibrated records with known radius */
	memcpy( &radPair, p, sizeof(WifiPair) );
	radPair.type = C_SIGNAL;

	if( (stat = getFirstHashFilter(&clbrWifi, &radPair, isEqTypeNoSelf, &it)) )
		return stat;

	while(1){
		
		pCur = (WifiPair*)it.ptr;

		p->ErM = ( p->ErM * p->numErM + p->R - pow(10, (pCur->S - p->S + pCur->rx.Gain - p->rx.Gain + pCur->tx.Gain - p->tx.Gain )/(10*n)) * pCur->R) / ++p->numErM;

 		if( (stat = getNextHashFilter(&clbrWifi, &radPair, isEqTypeNoSelf, &it)) )
			if( stat == E_END )
				return 0;
			else
                		return stat;		
	}	

return 0;
}

int calcR(){
int stat;
WifiPair* pMaxDS;
WifiPair* pCur;
WifiPair nPair;
Iterator it;
float n;

	/* Find calibrated record with n */
	memset( &nPair, 0, sizeof(WifiPair) );
	nPair.type = C_NPOW;

	if( (stat = getFirstHashFilter(&clbrWifi, &nPair, isEqType, &it)) )
		return stat;

	pCur = (WifiPair*)it.ptr;
	n = pCur->nPow;	


	/* Iterarte throu all calibrated records with known S and calculate R */
	nPair.type = C_SIGNAL;
	if( (stat = getFirstHashFilter(&clbrWifi, &nPair, isEqType, &it)) )
		return stat;

	while(1){
		
		pCur = (WifiPair*)it.ptr;
		
		if( (stat = calcRmaxDS(pCur, n)) )
			return stat; 	

		if( (stat = calcRminDS(pCur, n)) )
			return stat; 
	
		if( (stat = calcRmean(pCur, n)) )
			return stat;
 
 		if( (stat = getNextHashFilter(&clbrWifi, &nPair, isEqType, &it)) )
			if( stat == E_END )
				return 0;
			else
                		return stat;		
	}

return 0;
}


int triangulateDraft(Point* loc){
int stat;
WifiPair rPair, *pair1, *pair2, *pair3;
Iterator it;
Circle cir1, cir2, cir3;

	if( !loc )
		return E_BADINPUT;

	rPair.type = C_TXYZ | C_SIGNAL;
	if( (stat = getFirstHashFilter(&clbrWifi, &rPair, isEqType, &it)) )
		return stat;

	pair1 = (WifiPair*)it.ptr;
	cir1.R = pair1->R;
	cir1.C.X = pair1->tx.X;
	cir1.C.Y = pair1->tx.Y;
	cir1.C.Z = pair1->tx.Z;

	if( (stat = getNextHashFilter(&clbrWifi, &rPair, isEqType, &it)) )
                return stat;

	pair2 = (WifiPair*)it.ptr;
	cir2.R = pair2->R;
        cir2.C.X = pair2->tx.X;
        cir2.C.Y = pair2->tx.Y;
        cir2.C.Z = pair2->tx.Z;

	if( (stat = getNextHashFilter(&clbrWifi, &rPair, isEqType, &it)) )
                return stat;

        pair3 = (WifiPair*)it.ptr;
	cir3.R = pair3->R;
        cir3.C.X = pair3->tx.X;
        cir3.C.Y = pair3->tx.Y;
        cir3.C.Z = pair3->tx.Z;

	/* Calculate the result position by first 3 base points */
	stat = triangulate( &cir1, &cir2, &cir3, loc );

return stat;
}


int triangulateFine(Point* loc){
int stat;
WifiPair rPair, *pair1, *pair2, *pair3, *pCur;
Iterator it;
Circle cir1, cir2, cir3;
Point locDrft;
Line lCur;
float R2_12, R2_23, R2_13, curR2;

	if( !loc )
		return E_BADINPUT;

	/* Calculate a draft position */
	if( (stat = triangulateDraft(&locDrft)) )
		return stat;

	/* Choose first base */
	rPair.type = C_TXYZ | C_SIGNAL;
	if( (stat = getFirstHashFilter(&clbrWifi, &rPair, isEqType, &it)) )
		return stat;

	pair1 = (WifiPair*)it.ptr;
	cir1.R = sqrt( (pair1->tx.X-locDrft.X)*(pair1->tx.X-locDrft.X) +
			(pair1->tx.Y-locDrft.Y)*(pair1->tx.Y-locDrft.Y) ); /*pair1->R;*/
	cir1.C.X = pair1->tx.X;
	cir1.C.Y = pair1->tx.Y;
	cir1.C.Z = pair1->tx.Z;

	/* Find another base with minimal miss of the draft position */
	pair2 = pair1;
	curR2 = 1.0E+99;
	while(1){
		if( (stat = getNextHashFilter(&clbrWifi, &rPair, isEqType, &it)) )
			if( stat == E_END )
				break;
			else                	
				return stat;

		pCur = (WifiPair*)it.ptr;
		cir2.R = sqrt( (pair2->tx.X-locDrft.X)*(pair2->tx.X-locDrft.X) +
				(pair2->tx.Y-locDrft.Y)*(pair2->tx.Y-locDrft.Y) ); /*pair2->R;*/
        	cir2.C.X = pCur->tx.X;
        	cir2.C.Y = pCur->tx.Y;
        	cir2.C.Z = pCur->tx.Z;

		/* If you cant calculate the miss, just try another base */
		if( (stat = cirNcir2line( &cir1, &cir2, &lCur )) )
			continue;

		if( (stat = lineNpoint2R2( &lCur, &locDrft, &R2_12)) )
			continue;

		/* Memorize the minimal miss base */
		if( curR2 > R2_12 ){
			pair2 = pCur;
			curR2 = R2_12;
		}
	}



	/* Find third base with minimal miss of the draft position */

	/* Skip the first base */
	if( (stat = getFirstHashFilter(&clbrWifi, &rPair, isEqType, &it)) )
		return stat;

	pair3 = pair1;
	curR2 = 1.0E+99;
	while(1){
		if( (stat = getNextHashFilter(&clbrWifi, &rPair, isEqType, &it)) )
			if( stat == E_END )
				break;
			else                	
				return stat;

		pCur = (WifiPair*)it.ptr;
		cir3.R = sqrt( (pair3->tx.X-locDrft.X)*(pair3->tx.X-locDrft.X) +
				(pair3->tx.Y-locDrft.Y)*(pair3->tx.Y-locDrft.Y) ); /*pair3->R;*/
        	cir3.C.X = pCur->tx.X;
        	cir3.C.Y = pCur->tx.Y;
        	cir3.C.Z = pCur->tx.Z;

		/* If you cant calculate the miss, just try another base */
		if( (stat = cirNcir2line( &cir2, &cir3, &lCur )) )
			continue;

		if( (stat = lineNpoint2R2( &lCur, &locDrft, &R2_23)) )
			continue;
	
		if( (stat = cirNcir2line( &cir1, &cir3, &lCur )) )
                        continue;

                if( (stat = lineNpoint2R2( &lCur, &locDrft, &R2_13)) )
                        continue;


		/* Memorize the minimal miss base */
		if( curR2 > R2_23 + R2_13 ){
			pair3 = pCur;
			curR2 = R2_23 + R2_13;
		}
	}


	/* Find if tehre is another first base with minimal miss of the draft position */

	/* Skip the first base */
	if( (stat = getFirstHashFilter(&clbrWifi, &rPair, isEqType, &it)) )
		return stat;

	curR2 = R2_12 + R2_13;
	while(1){
		if( (stat = getNextHashFilter(&clbrWifi, &rPair, isEqType, &it)) )
			if( stat == E_END )
				break;
			else                	
				return stat;

		pCur = (WifiPair*)it.ptr;
		cir1.R = sqrt( (pair1->tx.X-locDrft.X)*(pair1->tx.X-locDrft.X) +
				(pair1->tx.Y-locDrft.Y)*(pair1->tx.Y-locDrft.Y) ); /*pair1->R;*/
        	cir1.C.X = pCur->tx.X;
        	cir1.C.Y = pCur->tx.Y;
        	cir1.C.Z = pCur->tx.Z;

		/* If you cant calculate the miss, just try another base */
		if( (stat = cirNcir2line( &cir1, &cir3, &lCur )) )
			continue;

		if( (stat = lineNpoint2R2( &lCur, &locDrft, &R2_13)) )
			continue;
	
		if( (stat = cirNcir2line( &cir1, &cir2, &lCur )) )
                        continue;

                if( (stat = lineNpoint2R2( &lCur, &locDrft, &R2_12)) )
                        continue;


		/* Memorize the minimal miss base */
		if( curR2 > R2_12 + R2_13 ){
			pair1 = pCur;
			curR2 = R2_12 + R2_13;
		}
	}


	stat = triangulate( &cir1, &cir2, &cir3, loc );

return stat;
}


int calibrateR0S0(){
int stat;
WifiPair* pCur;
WifiPair rsPair;
Iterator it;
float Rmin=99999, Smin;

  /* Find calibrated record with n */
  memset( &rsPair, 0, sizeof(WifiPair) );
  rsPair.type = C_RADIUS | C_SIGNAL;

  /* use isEqMacRxNType to calibrate particular receiver */
  if( (stat = getFirstHashFilter(&clbrWifi, &rsPair, isEqType, &it)) )
    return stat;

  /* Iterarte throu all calibrated (S, R set) records and find shortest R */
  while(1){

    pCur = (WifiPair*)it.ptr;
   
    if( pCur->R < Rmin ){
      Rmin = pCur->R;
      Smin = pCur->S;
    }

    if( (stat = getNextHashFilter(&clbrWifi, &rsPair, isEqType, &it)) )
      if( stat == E_END )
	break;
      else
	return stat;		
  }


  /* use isEqMacRxNType to calibrate particular receiver */
  if( (stat = getFirstHashFilter(&clbrWifi, &rsPair, isEqType, &it)) )
    return stat;

  /* Iterarte throu all calibrated (S, R set) records and update R0 and S0 */
  while(1){

    pCur = (WifiPair*)it.ptr;
   
    pCur->R0 = Rmin;
    pCur->S0 = Smin;
    pCur->type |= C_R0S0;

    if( (stat = upsertHash( &clbrWifi, pCur )) )
      return stat;


    if( (stat = getNextHashFilter(&clbrWifi, &rsPair, isEqType, &it)) )
      if( stat == E_END )
	return 0;
      else
	return stat;		
  }

return 0;
}


int leastSqK(void* _p){
int stat;
WifiPair* pCur;
WifiPair rsPair;
Iterator it;
float sumDS=0, sumLogR=0, sumR=0;

  /* Find calibrated record with n */
  memset( &rsPair, 0, sizeof(WifiPair) );
  rsPair.type = C_R0S0;

  /* use isEqMacRxNType to calibrate particular receiver */
  if( (stat = getFirstHashFilter(&clbrWifi, &rsPair, isEqType, &it)) )
    return stat;

  /* Iterarte throu all calibrated ( S0, R0 set) records and calculate ;east squares of k coefficient */
  while(1){

    pCur = (WifiPair*)it.ptr;

    if( pCur->R0 ){
      sumDS += pCur->S0 - pCur->S;	
      sumLogR += log10(pCur->R / pCur->R0);
      sumR += pCur->R - pCur->R0;
    }

    if( (stat = getNextHashFilter(&clbrWifi, &rsPair, isEqType, &it)) )
      if( stat == E_END )
	break;
      else
	return stat;		
  }

  if( sumR )
    *((float*)_p) = (sumDS - 20 * sumLogR) / (10 * log10(exp(1)) * sumR);
  else
    return 1;

return 0;
}



int leastSqN(void* _p){
int stat;
WifiPair* pCur;
WifiPair rsPair;
Iterator it;
float sumDS=0, sumLogR=0;

  /* Find calibrated record with n */
  memset( &rsPair, 0, sizeof(WifiPair) );
  rsPair.type = C_R0S0;

  /* use isEqMacRxNType to calibrate particular receiver */
  if( (stat = getFirstHashFilter(&clbrWifi, &rsPair, isEqType, &it)) )
    return stat;

  /* Iterarte throu all calibrated ( S0, R0 set) records and calculate ;east squares of k coefficient */
  while(1){

    pCur = (WifiPair*)it.ptr;

    if( pCur->R0 ){
      sumDS += pCur->S0 - pCur->S;	
      sumLogR += log10(pCur->R / pCur->R0);
    }

    if( (stat = getNextHashFilter(&clbrWifi, &rsPair, isEqType, &it)) )
      if( stat == E_END )
	break;
      else
	return stat;		
  }

  if( sumLogR )
    *((float*)_p) = sumDS / (10 * sumLogR);
  else
    return 1;

return 0;
}



int main(int argc, char* argv[]){
  int stat;
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];

struct sigaction act;

Point loc;
/*
struct pcap_pkthdr header;
const u_char* packet;
wlan_ng_prism2_header *hdr;
int offset;*/

 float k, n;

	if(argc<3){
		fprintf(stderr, "Usage: awacs <interface> <timeout> (awacs wlan0 1)\n");
		exit(-1);
	}

	act.sa_handler = outputResult;
	if( sigaction(SIGALRM, &act, NULL) )
		fprintf(stderr, "Can't set SIGALARM handler\n");


	/* Initialize current hash */
	curWifi.hFn = getTxHashFn;
	curWifi.eqFn = isEqTx;
	curWifi.newFn = newWifiPair;
	curWifi.cpFn = ctorWifiPairLoad;
	
	/* Initialize calibrated hash */
	clbrWifi.hFn = getTxHashFn;
	clbrWifi.eqFn = isEqTxTime;
	clbrWifi.newFn = newWifiPair;
	clbrWifi.cpFn = ctorWifiPairLoad;

	if( (stat = initLoad()) )
		return stat;

	stat = calibrateR0S0();

	stat = leastSqK( &k );
	stat = leastSqN( &n );

#if 0
	if( (stat = calibrateNmaxR()) )
		return stat;

	calcR();

	triangulateFine(&loc);

	/* Assign mean strength calculation cctor */
	curWifi.cpFn = ctorWifiPairCur;


	handle = pcap_open_live(argv[1], BUFSIZ, 1, 0, errbuf);
	
	alarm(atol(argv[2]));

	pcap_loop( handle, -1, gotPacket, NULL);
#endif
/*
	while(1){
		offset = sizeof(wlan_ng_prism2_header)+4+6;
		packet = pcap_next(handle, &header);
		hdr = (wlan_ng_prism2_header*)packet;
		printf("\nPacket len %i, signal %i, channel %i, mac ", header.len, hdr->signal.data, hdr->channel.data);
		while(offset<sizeof(wlan_ng_prism2_header)+4+6+6){
			printf("%02X:",*((unsigned char*)hdr+offset));
			++offset;
		}
		sleep(5);
	}
*/

#if 0
	pcap_close(handle);
#endif

return 0;
}

