1090 lines
29 KiB
C++
1090 lines
29 KiB
C++
#include "server.hh"
|
|
|
|
#define TEST
|
|
#define DEBUG // Décommenter pour avoir de l'affichage en plus.
|
|
#define DEBUG_2 // Décommenter pour avoir encore plus d'affichage.
|
|
|
|
|
|
|
|
|
|
/******* Misc. very usefull functions *******/
|
|
|
|
|
|
|
|
/* Explodes a string into substrings based on separator sep. Returns a string vector. */
|
|
inline vector<string> explode(const string &input, const char &sep)
|
|
{
|
|
vector<string> vs;
|
|
string tmp;
|
|
unsigned int i;
|
|
|
|
for (i = 0 ; i < input.size() ; i++)
|
|
if (input[i] == sep)
|
|
{
|
|
vs.push_back(tmp);
|
|
tmp.clear();
|
|
}
|
|
else
|
|
{
|
|
tmp.push_back(input[i]);
|
|
}
|
|
|
|
//Last entry, did not encounter a separator.
|
|
vs.push_back(tmp);
|
|
tmp.clear();
|
|
|
|
return vs;
|
|
}
|
|
|
|
|
|
|
|
/* Function to convert a string to an integer */
|
|
inline int string2int(const string &nb)
|
|
{
|
|
istringstream iss(nb);
|
|
|
|
int tmp;
|
|
iss >> tmp;
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|
|
/* Function to convert a string to an unsigned integer */
|
|
inline unsigned int string2uint(const string &nb)
|
|
{
|
|
istringstream iss(nb);
|
|
|
|
unsigned int tmp;
|
|
iss >> tmp;
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|
|
/* Function to convert a string to a float */
|
|
inline float string2float(const string &nb)
|
|
{
|
|
istringstream iss(nb);
|
|
|
|
float tmp;
|
|
iss >> tmp;
|
|
return tmp;
|
|
}
|
|
|
|
|
|
|
|
/* Function extracts ints from string */
|
|
inline vector<int> extractValues(string buff)
|
|
{
|
|
unsigned int ptr = 0;
|
|
vector<int> ret;
|
|
string tmp_field;
|
|
|
|
if (buff[buff.size()-1] != ';')
|
|
buff.push_back(';');
|
|
|
|
while (ptr < buff.size())
|
|
{
|
|
if (buff[ptr] != ';')
|
|
tmp_field.push_back(buff[ptr]);
|
|
else
|
|
{
|
|
ret.push_back(string2int(tmp_field));
|
|
tmp_field.clear();
|
|
}
|
|
ptr++;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
inline vector<string> extractReferencePointInfoFromBuffer(const string &buffer_in)
|
|
{
|
|
unsigned int i = 0;
|
|
string tmp_field;
|
|
vector<string> ret;
|
|
|
|
/* Extract coordinates */
|
|
/* x */
|
|
while (buffer_in[i] != ';')
|
|
{
|
|
tmp_field.push_back(buffer_in[i]);
|
|
i++;
|
|
}
|
|
ret.push_back(tmp_field);
|
|
tmp_field.clear();
|
|
i++; // go after the ';'
|
|
|
|
/* y */
|
|
while (buffer_in[i] != ';')
|
|
{
|
|
tmp_field.push_back(buffer_in[i]);
|
|
i++;
|
|
}
|
|
ret.push_back(tmp_field);
|
|
tmp_field.clear();
|
|
i++;
|
|
|
|
#ifndef FRED_CSV_FORMAT // Dans le format Fred, on n'a pas de coordonnée Z.
|
|
/* z */
|
|
while (buffer_in[i] != ';')
|
|
{
|
|
tmp_field.push_back(buffer_in[i]);
|
|
i++;
|
|
}
|
|
ret.push_back(tmp_field);
|
|
tmp_field.clear();
|
|
i++;
|
|
#endif // FRED_CSV_FORMAT
|
|
|
|
/* Extract direction (not used now) */
|
|
while (buffer_in[i] != ';')
|
|
{
|
|
tmp_field.push_back(buffer_in[i]);
|
|
i++;
|
|
}
|
|
ret.push_back(tmp_field);
|
|
tmp_field.clear();
|
|
i++;
|
|
|
|
#ifdef FRED_CSV_FORMAT
|
|
/* Extract mac address */
|
|
while (buffer_in[i] != ';')
|
|
{
|
|
tmp_field.push_back(buffer_in[i]);
|
|
i++;
|
|
}
|
|
ret.push_back(tmp_field);
|
|
tmp_field.clear();
|
|
i++;
|
|
|
|
/* Extract scan list */
|
|
while (i < buffer_in.size())
|
|
{
|
|
tmp_field.push_back(buffer_in[i]);
|
|
i++;
|
|
}
|
|
ret.push_back(tmp_field);
|
|
tmp_field.clear();
|
|
#else // FRED_CSV_FORMAT
|
|
while (i <= buffer_in.size())
|
|
{
|
|
if ((buffer_in[i] == ';' || i == buffer_in.size()) && !tmp_field.empty()) // Si on est sur un séparateur et que la valeur lue n'est pas vide,
|
|
{
|
|
#ifdef DEBUG_2
|
|
cout << "Ajout de la valeur lue : " << tmp_field << endl ;
|
|
#endif // DEBUG_2
|
|
ret.push_back(tmp_field) ; // on met la valeur lue dans les valeurs de retour.
|
|
tmp_field.clear() ;
|
|
}
|
|
else // Si on n'est pas sur un séparateur,
|
|
tmp_field.push_back(buffer_in[i]) ; // on ajoute le caractère courant à la suite de la valeur lue.
|
|
|
|
i++ ;
|
|
}
|
|
#endif // FRED_CSV_FORMAT
|
|
|
|
/* Return the vector with each data */
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
/* ***************************************************************** */
|
|
|
|
|
|
|
|
//Server::Server(string ip_addr, int listen_port, int send_port) // FIXME : paramètre send_port inutilisé
|
|
Server::Server(const string &ip_addr, const int &listen_port)
|
|
{
|
|
/* Open socket */
|
|
sockListen = socket(PF_INET, SOCK_DGRAM, 0);
|
|
sockSend = socket(PF_INET, SOCK_DGRAM, 0);
|
|
|
|
/* Set addr */
|
|
server_addr.sin_family = AF_INET;
|
|
server_addr.sin_port = htons(listen_port);
|
|
server_addr.sin_addr.s_addr = inet_addr(ip_addr.c_str());
|
|
memset(server_addr.sin_zero, '\0', sizeof(server_addr.sin_zero));
|
|
|
|
/* Bind */
|
|
bind(sockListen, (struct sockaddr *)&server_addr, sizeof(server_addr));
|
|
|
|
makeReferencePointListFromFile(DEFAULT_REF_POINT_FILE);
|
|
makeApListFromFile(DEFAULT_AP_FILE);
|
|
}
|
|
|
|
|
|
|
|
Server::~Server()
|
|
{
|
|
client_list.clear();
|
|
reference_point_list.clear();
|
|
access_point_list.clear();
|
|
close(sockListen);
|
|
close(sockSend);
|
|
}
|
|
|
|
|
|
|
|
void Server::send_to_client(const int &cl)
|
|
{
|
|
/* Do not forget to implement later: usefull for a demo */
|
|
}
|
|
|
|
|
|
|
|
int Server::receive_data()
|
|
{
|
|
/* Do not forget to implement later: usefull for a demo */
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* FONCTION POUR RÉTRO-COMPATIBILITÉ.
|
|
* Recherche un point de coordonnées (x;y;z) dans la liste reference_point_list, retourne true s'il existe, false sinon. */
|
|
bool Server::pointExists(const float &x, const float &y, const float &z)const
|
|
{
|
|
return pointExists(reference_point_list, Point(x, y, z)) ;
|
|
}
|
|
|
|
|
|
|
|
/* FONCTION POUR RÉTRO-COMPATIBILITÉ.
|
|
* Recherche un Point dans la liste reference_point_list, retourne true s'il existe, false sinon. */
|
|
bool Server::pointExists(const Point &p)const
|
|
{
|
|
return pointExists(reference_point_list, p) ;
|
|
}
|
|
|
|
|
|
|
|
/* Recherche un point de coordonnées (x;y;z) dans la liste "point_list", retourne true s'il existe, false sinon. */
|
|
bool Server::pointExists(const vector<ReferencePoint> &point_list, const float &x, const float &y, const float &z) const
|
|
{
|
|
return pointExists(point_list, Point(x, y, z)) ;
|
|
}
|
|
|
|
|
|
|
|
/* Recherche un Point dans la liste "point_list", retourne true s'il existe, false sinon. */
|
|
bool Server::pointExists(const vector<ReferencePoint> &point_list, const Point &p) const
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0 ; i < point_list.size() ; i++)
|
|
if (p == point_list[i].getCoordinates())
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
/* Do not forget to call pointExists() before this one */
|
|
unsigned int Server::pointIndex(const float &x, const float &y, const float &z)const
|
|
{
|
|
return pointIndex(reference_point_list, Point(x, y, z)) ;
|
|
}
|
|
|
|
|
|
|
|
/* Do not forget to call pointExists() before this one */
|
|
unsigned int Server::pointIndex(const Point &p)const
|
|
{
|
|
return pointIndex(reference_point_list, p) ;
|
|
}
|
|
|
|
|
|
|
|
unsigned int Server::pointIndex(const vector<ReferencePoint> &point_list, const float &x, const float &y, const float &z) const
|
|
{
|
|
return pointIndex(point_list, Point(x, y, z)) ;
|
|
}
|
|
|
|
|
|
|
|
unsigned int Server::pointIndex(const vector<ReferencePoint> &point_list, const Point &p) const
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0 ; i < reference_point_list.size() ; i++)
|
|
if (p == reference_point_list[i].getCoordinates())
|
|
return i;
|
|
|
|
return 0; // Should never happen
|
|
}
|
|
|
|
|
|
|
|
bool Server::apExists(const string &ap_addr)const
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0 ; i < access_point_list.size() ; i++)
|
|
if (access_point_list[i].getApAddr() == ap_addr)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
unsigned int Server::apIndex(const string &ap_addr)const
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0 ; i < access_point_list.size() ; i++)
|
|
if (access_point_list[i].getApAddr() == ap_addr)
|
|
return i;
|
|
|
|
return 0; // Should never happen
|
|
}
|
|
|
|
|
|
|
|
/* Selects the "k" closest points from the measurement "m", in the SS space.
|
|
* Returns an empty vector if no points are found, which should never happen.
|
|
*/
|
|
vector<Point> Server::getkClosestInSs(const vector<Measurement> &m, const unsigned int &k)const
|
|
{
|
|
return getkClosestInSs(m, k, NULL) ;
|
|
}
|
|
|
|
|
|
|
|
/* Selects the "k" closest points from the measurement "m", in the SS space.
|
|
* If "point_ignored" is not NULL, the Point "*point_ignored" is ignored.
|
|
* Returns an empty vector if no points are found, which should never happen.
|
|
*/
|
|
vector<Point> Server::getkClosestInSs(const vector<Measurement> &m, const unsigned int &k, const Point *point_ignored)const
|
|
{
|
|
unsigned int i, j, min_idx;
|
|
vector<float> distances_vector;
|
|
vector<Point> points_vector;
|
|
Point tmp_pt;
|
|
float tmp_distance = 0, dist_max = 10000000, tmp_min;
|
|
|
|
for (i = 0 ; i < reference_point_list.size() ; i++)
|
|
if (point_ignored == NULL || (reference_point_list[i].getCoordinates() != *point_ignored))
|
|
{
|
|
tmp_distance = reference_point_list[i].getSsSquareDistance(m);
|
|
#ifdef DEBUG_2
|
|
cout << tmp_distance << " " ;
|
|
#endif // DEBUG_2
|
|
|
|
/* if not k points, add it */
|
|
if(distances_vector.size() < k)
|
|
{
|
|
distances_vector.push_back(tmp_distance);
|
|
points_vector.push_back(reference_point_list[i].getCoordinates());
|
|
dist_max = (dist_max < tmp_distance) ? tmp_distance : dist_max;
|
|
}
|
|
else
|
|
{
|
|
/* if tmp_dst < dist_max, should add it and remove previous greatest dist. */
|
|
if(dist_max > tmp_distance)
|
|
{
|
|
/* remove old max */
|
|
for (j = 0 ; j < distances_vector.size() ; j++)
|
|
if (distances_vector[j] == dist_max)
|
|
{
|
|
distances_vector[j] = tmp_distance;
|
|
points_vector[j] = reference_point_list[i].getCoordinates();
|
|
break;
|
|
}
|
|
/* Now seek the new max. distance */
|
|
dist_max = distances_vector[0];
|
|
for(j = 1 ; j < distances_vector.size() ; j++)
|
|
if(distances_vector[j] > dist_max)
|
|
dist_max = distances_vector[j];
|
|
}
|
|
/* Else nothing needs to be done */
|
|
}
|
|
}
|
|
#ifdef DEBUG_2
|
|
cout << endl ;
|
|
#endif // DEBUG_2
|
|
|
|
/* Sorts the vector */
|
|
for (i = 0 ; i < distances_vector.size() - 1 ; i++)
|
|
{
|
|
tmp_min = distances_vector[i];
|
|
min_idx = i;
|
|
for (j = i+1 ; j < distances_vector.size() ; j++)
|
|
if (tmp_min > distances_vector[j])
|
|
{
|
|
tmp_min = distances_vector[j];
|
|
min_idx = j;
|
|
}
|
|
|
|
if (min_idx != i)
|
|
{
|
|
/* Swap points */
|
|
tmp_pt = points_vector[i];
|
|
points_vector[i] = points_vector[min_idx];
|
|
points_vector[min_idx] = tmp_pt;
|
|
|
|
/* Swap distances */
|
|
distances_vector[min_idx] = distances_vector[i];
|
|
distances_vector[i] = tmp_min;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
cout << "getkClosestInSs() : Points sélectionnés :" << endl ;
|
|
if (distances_vector.size() != points_vector.size())
|
|
cout << "Erreur ! distances_vector.size()=" << distances_vector.size() << " != points_vector.size()=" << points_vector.size() << endl ;
|
|
else
|
|
for (i = 0 ; i < distances_vector.size() - 1 ; i++)
|
|
cout << distances_vector[i] << " : " << points_vector[i] << endl ;
|
|
#endif // DEBUG
|
|
|
|
return points_vector;
|
|
}
|
|
|
|
|
|
|
|
Point Server::getkWeightedInSs(const vector<Measurement> &m, const unsigned int &k)const
|
|
{
|
|
return getkWeightedInSs(m, k, NULL) ;
|
|
}
|
|
|
|
|
|
|
|
/* If "point_ignored" is not NULL, the Point "*point_ignored" is ignored.
|
|
*/
|
|
Point Server::getkWeightedInSs(const vector<Measurement> &m, const unsigned int &k, const Point *point_ignored)const
|
|
{
|
|
unsigned int i, j;
|
|
vector<float> distances_vector;
|
|
vector<Point> points_vector;
|
|
float tmp_distance = 0, dist_max = 10000000;
|
|
Point ret;
|
|
float total = 0, x = 0, y = 0, z = 0;
|
|
|
|
for (i = 0 ; i < reference_point_list.size() ; i++)
|
|
if (point_ignored == NULL || (reference_point_list[i].getCoordinates() != *point_ignored))
|
|
{
|
|
tmp_distance = reference_point_list[i].getSsSquareDistance(m);
|
|
/* if not k points, add it */
|
|
if (distances_vector.size() < k)
|
|
{
|
|
distances_vector.push_back(tmp_distance);
|
|
points_vector.push_back(reference_point_list[i].getCoordinates());
|
|
dist_max = (dist_max > tmp_distance) ? tmp_distance : dist_max;
|
|
}
|
|
else
|
|
{
|
|
/* if tmp_dst < dist_max, should add it and remove previous greatest dist. */
|
|
if (dist_max > tmp_distance)
|
|
{
|
|
/* remove old max */
|
|
for (j = 0 ; j < distances_vector.size() ; j++)
|
|
if(distances_vector[j] == dist_max)
|
|
{
|
|
dist_max = tmp_distance;
|
|
distances_vector.erase(distances_vector.begin() + j);
|
|
points_vector.erase(points_vector.begin() + j);
|
|
distances_vector.push_back(tmp_distance);
|
|
points_vector.push_back(reference_point_list[i].getCoordinates());
|
|
break;
|
|
}
|
|
}
|
|
/* Else nothing needs to be done */
|
|
}
|
|
}
|
|
for (i = 0 ; i < distances_vector.size() ; i++)
|
|
total += distances_vector[i];
|
|
|
|
for (i = 0 ; i < distances_vector.size() ; i++)
|
|
{
|
|
x += points_vector[i].getX() * distances_vector[i] / total;
|
|
y += points_vector[i].getY() * distances_vector[i] / total;
|
|
z += points_vector[i].getZ() * distances_vector[i] / total;
|
|
}
|
|
|
|
ret.setX(x);
|
|
ret.setY(y);
|
|
ret.setZ(z);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
Point Server::kPointsAverage(const vector<Point> &vp)const
|
|
{
|
|
unsigned int i;
|
|
float x=0, y=0, z=0;
|
|
Point p;
|
|
|
|
for (i = 0 ; i < vp.size() ; i++)
|
|
{
|
|
x += vp[i].getX();
|
|
y += vp[i].getY();
|
|
z += vp[i].getZ();
|
|
}
|
|
p.setX(x / (float) vp.size());
|
|
p.setY(y / (float) vp.size());
|
|
p.setZ(z / (float) vp.size());
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
|
|
Point Server::fbcm(const vector<Measurement> &m, const int &client_idx)const
|
|
{
|
|
Point ret(0, 0, 0);
|
|
vector<string> addr;
|
|
vector<float> dist_vect;
|
|
vector<Point> centres;
|
|
unsigned int i, ap_idx;
|
|
float constant_term, minmax_res, minmax_max;
|
|
float x = MINMAX_X_START, y = MINMAX_Y_START;
|
|
|
|
i = 0;
|
|
//cout << "FBCM: ";
|
|
for (i = 0 ; i < m.size() ; i++)
|
|
if (apExists(m[i].getMacAddr()))
|
|
{
|
|
ap_idx = apIndex(m[i].getMacAddr());
|
|
//cout << "AP idx: " << ap_idx << " ";
|
|
centres.push_back(access_point_list[ap_idx].getCoordinates());
|
|
addr.push_back(m[i].getMacAddr());
|
|
constant_term = access_point_list[ap_idx].getOutputPower() + access_point_list[ap_idx].getAntennaGain() + 2;
|
|
constant_term += 20 * log10((300000000.0 / (float) access_point_list[ap_idx].getFrequency()) / (4*M_PI));
|
|
//end of expr. should be: client_list[client_idx].getAntennaGain() instead of 2.
|
|
//cout << "20log(" << (300000000.0 / (float) access_point_list[ap_idx].getFrequency()) / (4*M_PI) << ") = ";
|
|
//cout << constant_term << " ";
|
|
dist_vect.push_back(pow(10, (constant_term - m[i].getAverage()) / (10 * access_point_list[ap_idx].getFriisIndex())));
|
|
//cout << endl;
|
|
}
|
|
|
|
/* Then: min-max */
|
|
minmax_res = 1000000;
|
|
for (x = MINMAX_X_START ; x < MINMAX_X_STOP ; x += MINMAX_STEP)
|
|
for (y = MINMAX_Y_START ; y < MINMAX_Y_STOP ; y += MINMAX_STEP)
|
|
{
|
|
minmax_max = 0;
|
|
for (i = 0 ; i < centres.size() ; i++)
|
|
if ((centres[i].squareDistance(x, y, 3) - (dist_vect[i]*dist_vect[i])) > minmax_max)
|
|
minmax_max = centres[i].squareDistance(x, y, 3) - (dist_vect[i] * dist_vect[i]);
|
|
if (minmax_max < minmax_res)
|
|
{
|
|
ret.setX(x);
|
|
ret.setY(y);
|
|
minmax_res = minmax_max;
|
|
}
|
|
}
|
|
|
|
/* Clear all vectors */
|
|
addr.clear();
|
|
dist_vect.clear();
|
|
centres.clear();
|
|
|
|
/* Return position */
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
Point Server::interlink(const vector<Measurement> &m, const int &client_idx)const
|
|
{
|
|
Point ret(0, 0, 0);
|
|
vector<string> addr;
|
|
vector<float> dist_vect;
|
|
vector<Point> centres;
|
|
unsigned int i, ap_idx;
|
|
float constant_term, minmax_res, minmax_max;
|
|
float x = MINMAX_X_START, y = MINMAX_Y_START;
|
|
|
|
i = 0;
|
|
for (i = 0 ; i < m.size() ; i++)
|
|
if (apExists(m[i].getMacAddr()))
|
|
{
|
|
ap_idx = apIndex(m[i].getMacAddr());
|
|
centres.push_back(access_point_list[ap_idx].getCoordinates());
|
|
addr.push_back(m[i].getMacAddr());
|
|
constant_term = access_point_list[ap_idx].getOutputPower() + access_point_list[ap_idx].getAntennaGain();
|
|
constant_term += 20 * log10((300000000.0 / (float) access_point_list[ap_idx].getFrequency()) / (4*M_PI)) + 2;
|
|
//end of expr. should be: client_list[client_idx].getAntennaGain() instead of 2.
|
|
dist_vect.push_back(pow(10, (constant_term - m[i].getAverage()) / 35));
|
|
}
|
|
|
|
/* Then: min-max */
|
|
minmax_res = 1000000;
|
|
for (x = MINMAX_X_START ; x < MINMAX_X_STOP ; x += MINMAX_STEP)
|
|
for (y = MINMAX_Y_START ; y < MINMAX_Y_STOP ; y += MINMAX_STEP)
|
|
{
|
|
minmax_max = 0;
|
|
for (i = 0 ; i < centres.size() ; i++)
|
|
if ((centres[i].squareDistance(x, y, 3) - (dist_vect[i] * dist_vect[i])) > minmax_max)
|
|
minmax_max = centres[i].squareDistance(x, y, 3) - (dist_vect[i] * dist_vect[i]) ;
|
|
if (minmax_max < minmax_res)
|
|
{
|
|
ret.setX(x);
|
|
ret.setY(y);
|
|
minmax_res = minmax_max;
|
|
}
|
|
}
|
|
|
|
/* Clear all vectors */
|
|
addr.clear();
|
|
dist_vect.clear();
|
|
centres.clear();
|
|
|
|
/* Return position */
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
/* FONCTION POUR RÉTRO-COMPATIBILITÉ.
|
|
* Crée la liste des points de référence dans la liste reference_point_list. */
|
|
void Server::makeReferencePointListFromFile(const string &filename)
|
|
{
|
|
makePointListFromFile(reference_point_list, filename, true) ;
|
|
}
|
|
|
|
|
|
|
|
void Server::makePointListFromFile(vector<ReferencePoint> &dest_point_list, const string &filename)
|
|
{
|
|
makePointListFromFile(dest_point_list, filename, true) ;
|
|
}
|
|
|
|
|
|
|
|
/* Lit le fichier de mesures (CSV) nommé "filename", et place les informations dans la liste "dest_point_list".
|
|
* Si "uniq_point" est vrai, on vérifiera l'existence d'un point avant tout ajout d'information, de manière à ne pas créer de doublon : si le point existe déjà, les informations lui seront ajoutées, sinon un nouveau point sera créé dans la liste.
|
|
* Si "uniq_point" est faux, un nouveau point sera créé pour chaque ligne du fichier.
|
|
*/
|
|
void Server::makePointListFromFile(vector<ReferencePoint> &dest_point_list, const string &filename, const bool uniq_point)
|
|
{
|
|
ifstream input_file ; // Flux d'entrée du fichier.
|
|
char buffer[BUFFER_LENGTH]; // Buffer lu dans le fichier.
|
|
string cpp_buffer ; // Buffer au format string.
|
|
ReferencePoint rp;
|
|
Point tmp_point;
|
|
float x, y, z ; // Coordonnées des points.
|
|
unsigned int pt_idx = 0 ; // Position du point lu dans la liste.
|
|
vector<string> infos ; // Liste des informations lues dans une ligne du fichier.
|
|
|
|
input_file.open(filename.c_str()) ;
|
|
|
|
if (input_file.fail())
|
|
{
|
|
cerr << "Error opening input file « " << filename << " » !" << endl ;
|
|
return ;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
cout << "Lecture du fichier « " << filename << " »..." ;
|
|
int nlines = 0 ;
|
|
int npoints = 0 ;
|
|
#endif // DEBUG
|
|
|
|
while (!input_file.eof())
|
|
{
|
|
#ifdef DEBUG
|
|
if (nlines % 100 == 0)
|
|
printf("\n%5d", nlines) ;
|
|
cout << '.' ;
|
|
nlines++ ;
|
|
#endif // DEBUG
|
|
|
|
input_file.getline(buffer, BUFFER_LENGTH);
|
|
|
|
if ((input_file.rdstate() & ifstream::eofbit) == 0)
|
|
{
|
|
/* Extract fields */
|
|
cpp_buffer = buffer;
|
|
if (cpp_buffer.size() == 0) // Ignorer une ligne vide
|
|
continue ;
|
|
|
|
infos = extractReferencePointInfoFromBuffer(cpp_buffer);
|
|
x = string2float(infos[0]);
|
|
y = string2float(infos[1]);
|
|
#ifdef FRED_CSV_FORMAT
|
|
z = DEFAULT_Z ;
|
|
#else // FRED_CSV_FORMAT
|
|
z = string2float(infos[2]) ;
|
|
#endif // FRED_CSV_FORMAT
|
|
|
|
/* Set point coordinates */
|
|
tmp_point.setX(x);
|
|
tmp_point.setY(y);
|
|
tmp_point.setZ(z);
|
|
|
|
/* Use C++ string format */
|
|
if (!uniq_point || !pointExists(dest_point_list, tmp_point)) // Si on ne veut pas de points unique, ou que le point n'existe pas encore,
|
|
{
|
|
rp.setCoordinates(tmp_point);
|
|
dest_point_list.push_back(rp) ; // on le crée.
|
|
pt_idx = dest_point_list.size() - 1 ; // Le point que l'on vient d'ajouter est le dernier du vector.
|
|
#ifdef DEBUG
|
|
npoints++ ;
|
|
#endif // DEBUG
|
|
#ifdef DEBUG_2
|
|
cout << tmp_point << " : ajouté." << endl ;
|
|
#endif // DEBUG_2
|
|
}
|
|
else // Le point existe déjà :
|
|
{
|
|
#ifdef DEBUG_2
|
|
cout << tmp_point << " : existe déjà." << endl ;
|
|
#endif // DEBUG_2
|
|
pt_idx = pointIndex(dest_point_list, tmp_point) ; // On recherche le point auquel on veut ajouter les informations.
|
|
}
|
|
|
|
#ifdef FRED_CSV_FORMAT
|
|
vector<int> measures_vector = extractValues(infos[4]) ;
|
|
for (unsigned int i = 0 ; i < measures_vector.size() ; i++)
|
|
dest_point_list[pt_idx].addMeasurement(infos[3], measures_vector[i]);
|
|
measures_vector.clear();
|
|
#else // FRED_CSV_FORMAT
|
|
for (unsigned int i = 4 ; i < infos.size() ; i++)
|
|
{
|
|
#ifdef DEBUG_2
|
|
cout << "Lecture de la valeur : " << infos[i] << "... " ;
|
|
#endif // DEBUG_2
|
|
if (i + 1 < infos.size())
|
|
{
|
|
dest_point_list[pt_idx].addMeasurement(infos[i], string2int(infos[i+1])) ;
|
|
#ifdef DEBUG_2
|
|
cout << "Mesure ajoutée : AP = " << infos[i] << " | SS = " << string2int(infos[i+1]) << endl ;
|
|
#endif // DEBUG_2
|
|
i++ ;
|
|
}
|
|
}
|
|
#endif // FRED_CSV_FORMAT
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
cout << '\n' << nlines << " lignes lues, " << npoints << " points différents ajoutés.\n" << endl ;
|
|
#endif // DEBUG
|
|
|
|
input_file.close();
|
|
infos.clear() ;
|
|
}
|
|
|
|
|
|
|
|
void Server::makeApListFromFile(const string &filename)
|
|
{
|
|
ifstream input_file;
|
|
char buffer[BUFFER_LENGTH];
|
|
vector<string> ap_infos;
|
|
AccessPoint tmp_ap;
|
|
|
|
input_file.open(filename.c_str());
|
|
if (input_file.fail())
|
|
{
|
|
cerr << "Error opening input file « " << filename << " » !" << endl ;
|
|
return ;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
cout << "Lecture du fichier « " << filename << " »..." << endl ;
|
|
#endif // DEBUG
|
|
|
|
while (!input_file.eof())
|
|
{
|
|
input_file.getline(buffer, BUFFER_LENGTH);
|
|
|
|
if ((input_file.rdstate() & ifstream::eofbit) == 0)
|
|
{
|
|
/* Traitement basique des commentaires */
|
|
if (buffer[0] == '\0' // Ligne vide
|
|
|| buffer[0] == '#') // ou ligne commençant par #
|
|
continue ; // ignorer cette ligne.
|
|
|
|
ap_infos = explode(buffer, ';');
|
|
#ifdef DEBUG
|
|
cout << "AP : " << buffer ;
|
|
#endif // DEBUG
|
|
tmp_ap.setApAddr(ap_infos[0]);
|
|
tmp_ap.setCoordinates(string2float(ap_infos[1]), string2float(ap_infos[2]), string2float(ap_infos[3]));
|
|
tmp_ap.setFrequency(string2uint(ap_infos[4]));
|
|
tmp_ap.setAntennaGain(string2float(ap_infos[5]));
|
|
tmp_ap.setOutputPower(string2float(ap_infos[6]));
|
|
access_point_list.push_back(tmp_ap);
|
|
ap_infos.clear();
|
|
#ifdef DEBUG
|
|
cout << " ajouté." << endl ;
|
|
#endif // DEBUG
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
cout << endl ;
|
|
#endif // DEBUG
|
|
|
|
|
|
input_file.close();
|
|
}
|
|
|
|
|
|
|
|
/* FONCTION POUR RÉTRO-COMPATIBILITÉ
|
|
* Affiche la liste des points de référence (reference_point_list). */
|
|
void Server::printReferencePointList()
|
|
{
|
|
printPointList(reference_point_list) ;
|
|
}
|
|
|
|
|
|
|
|
/* Affiche une liste de points (point_list). */
|
|
void Server::printPointList(vector<ReferencePoint> &point_list)
|
|
{
|
|
for (unsigned int i = 0 ; i < point_list.size() ; i++)
|
|
cout << point_list[i] << endl ;
|
|
}
|
|
|
|
|
|
|
|
void Server::printAccessPointList()
|
|
{
|
|
for (unsigned int i = 0 ; i < access_point_list.size() ; i++)
|
|
cout << access_point_list[i] << endl;
|
|
}
|
|
|
|
|
|
|
|
void Server::computeFriisFromRefList()
|
|
{
|
|
vector<float> friis_idx_list;
|
|
Point pt_coords, ap_coords;
|
|
float ap_power, ap_gain, calib_gain = 2, const_term, mes_power, friis_sum;
|
|
unsigned int ap_freq;
|
|
string ap_mac;
|
|
|
|
for (unsigned int i = 0 ; i < access_point_list.size() ; i++)
|
|
{
|
|
ap_power = access_point_list[i].getOutputPower();
|
|
ap_coords = access_point_list[i].getCoordinates();
|
|
ap_freq = access_point_list[i].getFrequency();
|
|
ap_gain = access_point_list[i].getAntennaGain();
|
|
ap_mac = access_point_list[i].getApAddr();
|
|
|
|
/* Compute main general term, independant from scans */
|
|
const_term = calib_gain + ap_gain;
|
|
const_term -= 20 * log10(4 * M_PI);
|
|
const_term += 20 * log10 (300000000.0 / ap_freq) + ap_power;
|
|
|
|
/* Compute an index for each ref point. List stored in friis_idx_list */
|
|
for (unsigned int j = 0 ; j < reference_point_list.size() ; j++)
|
|
{
|
|
pt_coords = reference_point_list[j].getCoordinates();
|
|
if (reference_point_list[i].getPowerForAp(ap_mac, &mes_power))
|
|
friis_idx_list.push_back((const_term - mes_power) / (10 * log10(ap_coords.distance(pt_coords))));
|
|
}
|
|
|
|
/* Now, compute avg value */
|
|
friis_sum = 0;
|
|
for (unsigned int j = 0 ; j < friis_idx_list.size() ; j++)
|
|
friis_sum += friis_idx_list[j];
|
|
access_point_list[i].setFriisIndex(friis_sum / friis_idx_list.size());
|
|
|
|
cout << access_point_list[i].getApAddr() << " -> " << (friis_sum / friis_idx_list.size()) << endl;
|
|
|
|
friis_idx_list.clear();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Computes new cumulative distances for each running viterbi instance,
|
|
* Returns the solution (type: Point) of the last ended viterbi.
|
|
* Distances are grouped by line corresponding to an instance.
|
|
* "K" MUST be the same as last.size() and current.size() !
|
|
*/
|
|
void Server::fastViterbiLike(const unsigned short &N, const unsigned short &K, const unsigned int &id_client)
|
|
{
|
|
#ifdef TEST
|
|
ClientInfo cl ;
|
|
float **V = cl.get_viterbi_V() ;
|
|
vector<Point>
|
|
&E_current = cl.getRef_viterbi_Ecurrent(),
|
|
&E_previous = cl.getRef_viterbi_Eprevious() ;
|
|
vector<ReferencePoint> peregrination_point_list ;
|
|
makePointListFromFile(peregrination_point_list, DEFAULT_TRACKING_FILE, false) ;
|
|
#else // TEST
|
|
float **V = client_list[id_client].get_viterbi_V() ;
|
|
vector<Point>
|
|
&E_current = client_list[id_client].getRef_viterbi_Ecurrent(),
|
|
&E_previous = client_list[id_client].getRef_viterbi_Eprevious() ;
|
|
#endif // TEST
|
|
|
|
int i = 1 ; // Nombre d'ensembles d'historique qu'on a déjà passés
|
|
|
|
if (N < 2)
|
|
{
|
|
cerr << "fastViterbiLike() : N ne peut être inférieur à 2 !" << endl ;
|
|
return ;
|
|
}
|
|
|
|
#ifdef TEST
|
|
unsigned int pt = 0 ;
|
|
#ifdef DEBUG
|
|
cout << reference_point_list.size() << " points de référence, " << peregrination_point_list.size() << " points de pérégrination." << endl ;
|
|
|
|
cout << "***** Liste pts référence : *****" << endl ;
|
|
printReferencePointList() ;
|
|
cout << "***** Liste pérégrination : *****" << endl ;
|
|
printPointList(peregrination_point_list) ;
|
|
cout << "*********************************" << endl ;
|
|
#endif // DEBUG
|
|
|
|
while (pt < peregrination_point_list.size())
|
|
#else // TEST
|
|
while (true)
|
|
#endif // TEST
|
|
{
|
|
vector<Measurement> vm ;
|
|
|
|
#ifdef TEST
|
|
/* Get point measurements */
|
|
//vm.clear();
|
|
vm = peregrination_point_list[pt].getMeasurementList();
|
|
#endif // TEST
|
|
|
|
E_previous = E_current ;
|
|
E_current = getkClosestInSs(vm, K) ; // Création de l'ensemble des K points les plus proches dans l'espace des puissances.
|
|
|
|
#ifdef DEBUG
|
|
cout << "Point courant : " << peregrination_point_list[pt] ;
|
|
#endif // DEBUG
|
|
|
|
if (i > 1) // Si on n'est plus à la première itération
|
|
{
|
|
/* Recalcul des plus courtes distances */
|
|
for (int n = N-1-i ; n < N-2 ; n++) // Pour chaque historique existant (sauf le dernier),
|
|
for (int k = 0 ; k < K ; k++) // pour chaque point de l'historique,
|
|
{ // on met à jour le chemin minimum entre l'historique précédent et le point :
|
|
V[n][k] = V[n+1][0] + E_previous[0].distance(E_current[k]) ;
|
|
for (int l = 1 ; l < K ; l++)
|
|
{
|
|
float f = V[n+1][l] + E_previous[l].distance(E_current[k]) ;
|
|
if (f < V[n][k])
|
|
V[n][k] = f ;
|
|
}
|
|
}
|
|
|
|
/* Traitement du dernier historique */
|
|
for (int k = 0 ; k < K ; k++) // Pour chaque point,
|
|
{ // on récupère le chemin minimum entre l'historique précédent et le point :
|
|
V[N-2][k] = E_previous[0].distance(E_current[k]) ;
|
|
for (int l = 1 ; l < K ; l++)
|
|
{
|
|
float f = E_previous[l].distance(E_current[k]) ;
|
|
if (f < V[N-2][k])
|
|
V[N-2][k] = f ;
|
|
}
|
|
}
|
|
|
|
/* Choix du min à renvoyer */
|
|
if (N-1-i == 0)
|
|
{
|
|
float V0_min = V[0][0] ;
|
|
for (int k=1 ; k < K ; k++)
|
|
{
|
|
if (V[0][k] < V0_min)
|
|
V0_min = V[0][k] ;
|
|
cout << "V[0][" << k << "]=" << V[0][k] << " ; V0_min=" << V0_min << " -- " ;
|
|
}
|
|
cout << "V0_min = " << V0_min << endl ;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
// cout << "(N=" << N << ") - 1 - (i=" << i << ") = " << N-1-i << endl ;
|
|
cout << "V :" << endl ;
|
|
for (int n=0 ; n < N-1 ; n++)
|
|
{
|
|
for (int k=0 ; k < K ; k++)
|
|
cout << "[" << V[n][k] << "]" ;
|
|
cout << endl ;
|
|
}
|
|
cout << "\n--------------------------" << endl ;
|
|
#endif // DEBUG
|
|
|
|
if (i < N-1)
|
|
i++ ;
|
|
|
|
#ifdef TEST
|
|
pt++ ;
|
|
#endif // TEST
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* For experimentation purpose only */
|
|
void Server::radar_exp()
|
|
{
|
|
ofstream logfile;
|
|
vector<Point> solutions;
|
|
Point solution, solution_kw, ref_coords;
|
|
unsigned int i;
|
|
vector<Measurement> vm;
|
|
|
|
// computeFriisFromRefList();
|
|
|
|
/* Open a log file */
|
|
logfile.open(DEFAULT_LOGFILE);
|
|
if (logfile.fail())
|
|
{
|
|
cerr << "Error opening output file « " << logfile << " » !" << endl ;
|
|
return ;
|
|
}
|
|
|
|
/* Column names */
|
|
logfile << "Coordinates\t2-kss\t(Error)\t3-kss\t(Error)\t4-kss\t(Error)\t5-kss\t(Error)\tnss\t(Error)\tInterlink\t(Error)\tFBCM\t(Error)" << endl;
|
|
|
|
cout << reference_point_list.size() << " reference points." << endl ;
|
|
for (i = 0 ; i < reference_point_list.size() ; i++)
|
|
{
|
|
/* Get point measurements */
|
|
vm.clear();
|
|
vm = reference_point_list[i].getMeasurementList();
|
|
ref_coords = reference_point_list[i].getCoordinates();
|
|
|
|
/* Print point coordinates */
|
|
logfile << ref_coords << "\t";
|
|
|
|
/* From 2 to 5 K-weighted-SS */
|
|
solution = getkWeightedInSs(vm, 2, &ref_coords);
|
|
logfile << solution << "\t" << solution.distance(ref_coords) << "\t";
|
|
solution = getkWeightedInSs(vm, 3, &ref_coords);
|
|
logfile << solution << "\t" << solution.distance(ref_coords) << "\t";
|
|
solution = getkWeightedInSs(vm, 4, &ref_coords);
|
|
logfile << solution << "\t" << solution.distance(ref_coords) << "\t";
|
|
solution = getkWeightedInSs(vm, 5, &ref_coords);
|
|
logfile << solution << "\t" << solution.distance(ref_coords) << "\t";
|
|
|
|
/* Nearest in SS */
|
|
solutions = getkClosestInSs(vm, 1, &ref_coords);
|
|
logfile << solutions[0] << "\t" << solutions[0].distance(ref_coords) << "\t";
|
|
|
|
/* Interlink Networks */
|
|
solution = interlink(vm, 0);
|
|
logfile << solution << "\t" << solution.distance(ref_coords) << "\t";
|
|
|
|
/* FBCM */
|
|
solution = fbcm(vm, 0);
|
|
logfile << solution << "\t" << solution.distance(ref_coords) << endl;
|
|
|
|
solutions.clear();
|
|
}
|
|
logfile.close();
|
|
}
|