[Positioning] Add Request, complete InputCSV

== code/owlps-positioning ==

- Add new class Request (split of Measurement).
- Update Measurement and CalibrationMeasurement (suppress the 'mobile'
  attribute).
- Update InputCSV (and InputMedium) to use Request instead of
  Measurement. Complete the file reading (mobile & ap pointers remain to
  be implemented).
- PosUtil: Add timespec_to_ms(), timespec_to_ns(), ms_to_timespec(), and
  ns_to_timespec().
- Makefile: Update to use stlport, fix all deps and add new classes.
- Minor fixes.
- TODO: Add UML-related things, updates Measurement & Request.

== code ==

- libowlps: Add ms_to_timeval() (commented), may be useful later.
- Add TODO.
This commit is contained in:
Matteo Cypriani 2010-01-11 19:40:45 +01:00
parent 8f071d13b0
commit 5f8f955a3d
17 changed files with 400 additions and 86 deletions

4
TODO Normal file
View File

@ -0,0 +1,4 @@
Abandonner gettimeofday() et struct timeval au profit de clock_gettime()
et struct timespec. gettimeofday() est obsolète depuis POSIX:2008.
Abandonner int, long & Cie pour les échanges de données, passer à stdint.h

View File

@ -92,6 +92,20 @@ unsigned long long timeval_to_ms(struct timeval d)
/*
* Convertit une date sous forme de valeur entière en millisecondes,
* en une struct timeval, et retourne cette structure.
struct timeval ms_to_timeval(unsigned long long tms)
{
struct timeval d ;
d.tv_sec = tms / 1000 ;
d.tv_usec = (tms - d.tv_sec * 1000) * 1000 ;
return d ;
}
*/
/* Retourne le temps (en millisecondes) écoulé entre deux dates */
unsigned long sub_date(struct timeval sup, struct timeval inf)
{

View File

@ -11,16 +11,19 @@ CP = cp -v
# Autres outils
STYLE = astyle --style=gnu
GXX = g++
GXX = g++-4.4
DEBUG = -g
GXXFLAGS = $(DEBUG) -Wall -pedantic
LD = g++
LDFLAGS = -lm
STLPORTGXXFLAGS = -I/usr/include/stlport -pthread -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
GXXFLAGS = $(DEBUG) -Wall -Wextra $(STLPORTGXXFLAGS)
LD = $(GXX)
LDFLAGS = -lm -lstlport
LIBS = -lpq -lboost_program_options-mt
TARGET = owlps-positioning
HEADER = owlps-positioning.hh
OBJ = posutil.o point3d.o referencepoint.o waypoint.o building.o area.o wifidevice.o accesspoint.o mobile.o measurement.o calibrationmeasurement.o inputcsv.o
OBJ = posutil.o point3d.o referencepoint.o waypoint.o building.o \
area.o wifidevice.o accesspoint.o mobile.o measurement.o \
calibrationmeasurement.o request.o inputcsv.o
all: $(TARGET)
@ -31,16 +34,17 @@ all: $(TARGET)
posutil.o: posutil.hh
point3d.o: point3d.hh
referencepoint.o : referencepoint.hh point3d.hh calibrationmeasurement.hh
waypoint.o: waypoint.hh point3d.hh building.hh
referencepoint.o : referencepoint.hh point3d.o
waypoint.o: waypoint.hh point3d.o building.o
building.o: building.hh
area.o: area.hh building.hh point3d.hh
wifidevice.o: wifidevice.hh posutil.hh
accesspoint.o: accesspoint.hh wifidevice.hh point3d.hh
mobile.o: mobile.hh wifidevice.hh
measurement.o: measurement.hh mobile.hh accesspoint.hh
calibrationmeasurement.o: calibrationmeasurement.hh measurement.hh referencepoint.hh
inputcsv.o: inputcsv.hh inputmedium.hh
area.o: area.hh building.o point3d.o
wifidevice.o: wifidevice.hh posutil.o
accesspoint.o: accesspoint.hh wifidevice.o point3d.o
mobile.o: mobile.hh wifidevice.o
measurement.o: measurement.hh accesspoint.o
calibrationmeasurement.o: calibrationmeasurement.hh measurement.o referencepoint.o
request.o: request.hh measurement.o
inputcsv.o: inputcsv.hh inputmedium.hh request.o
#libowlps-positioning.o: libowlps-positioning.hh
#positioning.o: point.hh referencepoint.hh accesspoint.hh area.hh measurement.hh libowlps-positioning.hh
#server.o: server.hh positioning.hh point.hh measurement.hh treatment.hh libowlps-positioning.hh

View File

@ -1,11 +1,16 @@
- Measurement
Un Measurement est un groupe de mesures de signaux envoyés par un
mobile à un AP. Pour une demande de localisation, on aura donc
plusieurs Measurement. Cela pose-t-il problème ? Faut-il grouper
les Measurement dans une classe Demande ?
Anciennement, on avait une liste de points de référence, et à
chaque point étaient associés des mesures {MAC AP, SS}.
- Measurement & Request
Actuellement, l'AP associé à chaque Measurement (pointeur) n'est
pas initialisé lors de la lecture depuis un InputCSV. Les
Measurement sont créés par accès direct dans la table de hachage :
measurements[mac_ap].add_ss(ss)
C'est donc le constructeur par défaut Measurement() qui est utilisé
lors du premier accès.
- InputCSV
° Différencier une requête normale d'une requête de calibration, en
utilisant les champs de direction.
° Lire la direction en tant qu'entier plutôt que float ?
- '\n' vs. endl.
Utiliser '\n' plutôt que endl lorsque le vidage du tampon n'est pas
@ -13,6 +18,12 @@
- Measurement : corriger le calcul de moyenne.
- Revoir le diagramme UML
° Associations : devraient êtres représentées par des attributs
pointeurs.
° Compositions : devraient être représentées par des attributs
normaux.
- AccessPoint : attribut float friis_index ?
- Mobile : attributs Viterbi ?

View File

@ -11,11 +11,10 @@ protected:
ReferencePoint *reference_point ;
public:
CalibrationMeasurement(const Mobile *_mobile = NULL,
const AccessPoint *_ap = NULL,
CalibrationMeasurement(const AccessPoint *_ap = NULL,
const std::vector<int> &_ss_list = std::vector<int>(),
ReferencePoint *_reference_point = NULL):
Measurement(_mobile, _ap, _ss_list), reference_point(_reference_point) {}
Measurement(_ap, _ss_list), reference_point(_reference_point) {}
CalibrationMeasurement(const CalibrationMeasurement &cm):
Measurement(cm), reference_point(cm.reference_point) {}
CalibrationMeasurement(const Measurement &m):

1
owlps-positioning/csv/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.csv

View File

@ -1,10 +1,17 @@
#include "inputcsv.hh"
#include "posutil.hh"
#include <stdint.h>
#include <iostream>
#include <unordered_map>
using namespace std ;
using std::tr1::unordered_map ;
#include <boost/tokenizer.hpp>
#include <boost/lexical_cast.hpp>
#include <iostream>
using namespace std ;
using namespace boost ;
@ -19,8 +26,8 @@ InputCSV::InputCSV(const string &filename)
input_file.open(input_file_name.c_str()) ;
if (! input_file)
cerr
<< "InputCSV(): Error opening input file « " << input_file_name
<< " »!" << endl ;
<< "InputCSV::InputCSV(): Error opening input file « "
<< input_file_name << " »!" << endl ;
}
@ -28,10 +35,10 @@ InputCSV::InputCSV(const string &filename)
/*** Opérations ***/
const Measurement& InputCSV::get_next_measurement()
const Request& InputCSV::get_next_request()
{
if (! input_file)
return current_measurement ;
return current_request ;
string line ;
@ -46,37 +53,115 @@ const Measurement& InputCSV::get_next_measurement()
if (input_file.eof())
{
// End of file reached: blank current measurement
current_measurement.clear() ;
return current_measurement ;
// End of file reached: blank current request
current_request.clear() ;
return current_request ;
}
// Split read string into fields (semicolon-separated)
tokenizer<escaped_list_separator<char> > tok(
line, escaped_list_separator<char>('\\', ';', '\"')) ;
vector<int> ss_list ;
tokenizer<escaped_list_separator<char> >::iterator ti(tok.begin()) ;
for (tokenizer<escaped_list_separator<char> >::iterator i(tok.begin()) ;
i != tok.end() ; ++i)
// Read Mobile MAC field
if (ti == tok.end())
{
// Wrong number of fields: blank current request
current_request.clear() ;
return current_request ;
}
// FIXME! We need to search for the mobile corresponding to the read
// MAC address and set the mobile pointer in the Request.
//current_request.set_mobile(NULL) ;
// Read Timestamp field
if (++ti == tok.end())
{
// Wrong number of fields: blank current request
current_request.clear() ;
return current_request ;
}
try
{
current_request.set_timestamp(PosUtil::ns_to_timespec
(lexical_cast<uint64_t>(*ti))) ;
}
catch (bad_lexical_cast &e)
{
cerr
<< "InputCSV::get_next_request(): Bad value « "
<< *ti << " » at line "
<< current_line << ", field « Timestamp », of input file « "
<< input_file_name << " »!" << endl ;
current_request.clear() ; // Blank current request
return current_request ;
}
// Read position fields
float pos[4] ;
for (int i = 0 ; i < 4 ; ++i)
{
if (++ti == tok.end())
{
// Wrong number of fields: blank current request
current_request.clear() ;
return current_request ;
}
try
{
ss_list.push_back(lexical_cast<int>(*i)) ;
pos[i] = lexical_cast<float>(*ti) ;
}
catch (bad_lexical_cast &e)
{
cerr
<< "InputCSV::getNextMeasurement(): Bad value at line "
<< current_line
<< " of input file « " << input_file_name << " »!"
<< "InputCSV::get_next_request(): Bad value « "
<< *ti << " » at line "
<< current_line << ", position field #" << i
<< ", of input file « " << input_file_name << " »!"
<< endl ;
current_measurement.clear() ; // Blank current measurement
return current_measurement ;
current_request.clear() ; // Blank current request
return current_request ;
}
}
current_measurement.set_ss_list(ss_list) ;
unordered_map<string, Measurement> measurements ;
return current_measurement ;
// Reading {MAC_AP;SS} couples
for (++ti ; ti != tok.end() ; ++ti)
{
string mac_ap(*ti) ;
if (++ti == tok.end())
{
// Wrong number of fields: blank current request
current_request.clear() ;
return current_request ;
}
int ss ;
try
{
ss = lexical_cast<int>(*ti) ;
}
catch (bad_lexical_cast &e)
{
cerr
<< "InputCSV::get_next_request(): Bad value « "
<< *ti << " » at line "
<< current_line
<< " of input file « " << input_file_name << " »!"
<< endl ;
current_request.clear() ; // Blank current request
return current_request ;
}
// Adding value
measurements[mac_ap].add_ss(ss) ;
}
current_request.set_measurements(measurements) ;
return current_request ;
}

View File

@ -17,7 +17,7 @@ public:
bool eof(void) const ;
const Measurement& get_next_measurement(void) ;
const Request& get_next_request(void) ;
operator bool(void) const ;
} ;

View File

@ -1,29 +1,29 @@
#ifndef _OWLPS_POSITIONING_INPUTMEDIUM_HH_
#define _OWLPS_POSITIONING_INPUTMEDIUM_HH_
#include "measurement.hh"
#include "request.hh"
class InputMedium
{
protected:
Measurement current_measurement ;
Request current_request ;
unsigned long current_line ;
public:
InputMedium() ;
const Measurement& get_current_measurement(void) const ;
const Request& get_current_request(void) const ;
unsigned int get_current_line(void) const ;
/*
* Reads the next measurement and returns it, increments current_line
* Returns an empty Measurement in case of error or EOF (note that
* when casted in bool, an empty Measurement is false).
* Reads the next request and returns it, increments current_line
* Returns an empty Request in case of error or EOF (note that
* when casted in bool, an empty Request is false).
*/
virtual const Measurement& get_next_measurement(void) = 0 ;
virtual const Request& get_next_request(void) = 0 ;
/*
* Returns true if the last measurement has been reached
* Returns true if the last request has been reached
*/
virtual bool eof(void) const = 0 ;
} ;
@ -43,9 +43,9 @@ inline InputMedium::InputMedium()
/*** Accesseurs lecture ***/
inline const Measurement& InputMedium::get_current_measurement() const
inline const Request& InputMedium::get_current_request() const
{
return current_measurement ;
return current_request ;
}

View File

@ -8,19 +8,18 @@ using namespace std ;
/*** Constructeurs ***/
Measurement::Measurement(const Mobile *_mobile, const AccessPoint *_ap,
Measurement::Measurement(const AccessPoint *_ap,
const vector<int> &_ss_list)
{
mobile = (Mobile *) _mobile ;
ap = (AccessPoint *) _ap ;
ss_list = _ss_list ;
ss_list.reserve(10) ;
update_average_ss() ;
}
Measurement::Measurement(const Measurement &m)
{
mobile = m.mobile ;
ap = m.ap ;
ss_list = m.ss_list ;
average_ss = m.average_ss ;
@ -45,7 +44,8 @@ void Measurement::update_average_ss()
{
average_ss = 0 ;
for (vector<int>::iterator i = ss_list.begin() ; i < ss_list.end() ; i++)
for (vector<int>::iterator i = ss_list.begin() ;
i != ss_list.end() ; i++)
{
float ss_mwatts =
pow(10, (float) *i / 10.0) +
@ -81,7 +81,6 @@ void Measurement::clear()
ss_list.clear() ;
average_ss = 0 ;
ap = NULL ;
mobile = NULL ;
}
@ -94,7 +93,6 @@ Measurement Measurement::operator=(const Measurement &m)
if (this == &m)
return *this ;
mobile = m.mobile ;
ap = m.ap ;
ss_list = m.ss_list ;
average_ss = m.average_ss ;
@ -109,7 +107,6 @@ bool Measurement::operator==(const Measurement &m) const
return true ;
return
mobile == m.mobile &&
ap == m.ap &&
ss_list == m.ss_list &&
average_ss == m.average_ss ;
@ -119,10 +116,9 @@ bool Measurement::operator==(const Measurement &m) const
ostream &operator<<(ostream &os, const Measurement &m)
{
// MAC addresses
// MAC address
os
<< (m.mobile != NULL ? m.mobile->get_mac_addr() : "Unknown_mobile")
<< "->" << (m.ap != NULL ? m.ap->get_mac_addr() : "Unknown_AP")
<< "AP: " << (m.ap != NULL ? m.ap->get_mac_addr() : "Unknown_AP")
<< ": " ;
// List of SS
@ -130,7 +126,7 @@ ostream &operator<<(ostream &os, const Measurement &m)
os << "No values" ;
else
for (vector<int>::const_iterator i = m.ss_list.begin() ;
i < m.ss_list.end() ; i++)
i != m.ss_list.end() ; i++)
{
os << *i ;
if (i != m.ss_list.end() - 1)

View File

@ -1,7 +1,6 @@
#ifndef _OWLPS_POSITIONING_MEASUREMENT_HH_
#define _OWLPS_POSITIONING_MEASUREMENT_HH_
#include "mobile.hh"
#include "accesspoint.hh"
#include <vector>
@ -11,7 +10,6 @@
class Measurement
{
protected:
Mobile *mobile ;
AccessPoint *ap ;
float average_ss ;
std::vector<int> ss_list ;
@ -19,19 +17,17 @@ protected:
void update_average_ss(void) ;
public:
Measurement(const Mobile *_mobile = NULL, const AccessPoint *_ap = NULL,
Measurement(const AccessPoint *_ap = NULL,
const std::vector<int> &_ss_list = std::vector<int>()) ;
Measurement(const Measurement &m) ;
~Measurement() ;
Mobile* get_mobile() const ;
AccessPoint* get_ap() const ;
std::vector<int> get_ss_list() const ;
float get_average_ss() const ;
//float get_ss_square_distance(const float &ss) const ;
void set_mobile(const Mobile *_mobile) ;
void set_ap(const AccessPoint *_ap) ;
void add_ss(const int &ss) ;
void set_ss_list(const std::vector<int> &_ss_list) ;
@ -50,12 +46,6 @@ public:
/*** Accesseurs lecture ***/
inline Mobile* Measurement::get_mobile() const
{
return mobile ;
}
inline AccessPoint* Measurement::get_ap() const
{
return ap ;
@ -84,12 +74,6 @@ inline float Measurement::get_average_ss() const
/*** Accesseurs écriture ***/
inline void Measurement::set_mobile(const Mobile *_mobile)
{
mobile = (Mobile *) _mobile ;
}
inline void Measurement::set_ap(const AccessPoint *_ap)
{
ap = (AccessPoint *) _ap ;
@ -114,7 +98,6 @@ inline Measurement::operator bool() const
{
return
ap != NULL ||
mobile != NULL ||
ss_list.size() > 0 ;
}

View File

@ -56,3 +56,37 @@ unsigned int PosUtil::channel_to_frequency(const int &channel)
return 0 ; // Error: wrong channel value
}
uint64_t PosUtil::timespec_to_ms(const struct timespec &d)
{
return d.tv_sec * 1000 + d.tv_nsec / 1000000 ;
}
struct timespec PosUtil::ms_to_timespec(const uint64_t &tms)
{
struct timespec d ;
d.tv_sec = tms / 1000 ;
d.tv_nsec = (tms - d.tv_sec * 1000) * 1000000 ;
return d ;
}
uint64_t PosUtil::timespec_to_ns(const struct timespec &d)
{
return d.tv_sec * 1000000000 + d.tv_nsec ;
}
struct timespec PosUtil::ns_to_timespec(const uint64_t &tns)
{
struct timespec d ;
d.tv_sec = tns / 1000000000 ;
d.tv_nsec = tns - d.tv_sec * 1000000000 ;
return d ;
}

View File

@ -1,6 +1,9 @@
#ifndef _OWLPS_POSITIONING_POSUTIL_HH_
#define _OWLPS_POSITIONING_POSUTIL_HH_
#include <ctime>
#include <stdint.h> // <cstdint> is not C++ 98 compliant
/* Wi-Fi channel frequencies in Hz */
#define CHANNEL_1 2412
#define CHANNEL_2 2417
@ -20,7 +23,14 @@
class PosUtil
{
public:
/* Wi-Fi */
static unsigned int channel_to_frequency(const int &channel) ;
/* Time & Dates */
static uint64_t timespec_to_ms(const struct timespec &d) ;
static struct timespec ms_to_timespec(const uint64_t &tms) ;
static uint64_t timespec_to_ns(const struct timespec &d) ;
static struct timespec ns_to_timespec(const uint64_t &tns) ;
} ;
#endif // _OWLPS_POSITIONING_POSUTIL_HH_

View File

@ -160,7 +160,7 @@ ostream &operator<<(ostream &os, const ReferencePoint &rp)
else
for (vector<CalibrationMeasurement*>::const_iterator
i = rp.measurements.begin() ;
i < rp.measurements.end() ; i++)
i != rp.measurements.end() ; i++)
os << endl << *i ;
return os ;

View File

@ -0,0 +1,79 @@
#include "request.hh"
#include "mobile.hh"
using namespace std ;
using std::tr1::unordered_map ;
/*** Constructeurs ***/
Request::Request(const unordered_map<string, Measurement> &_measurements)
{
mobile = NULL ;
timestamp.tv_sec = 0 ;
timestamp.tv_nsec = 0 ;
measurements = _measurements ;
}
Request::Request(const struct timespec &_timestamp,
const unordered_map<string, Measurement> &_measurements)
{
mobile = NULL ;
timestamp = _timestamp ;
measurements = _measurements ;
}
Request::Request(const Mobile *_mobile, const struct timespec &_timestamp,
const unordered_map<string, Measurement> &_measurements)
{
mobile = (Mobile*) _mobile ;
timestamp = _timestamp ;
measurements = _measurements ;
}
/*** Accesseurs écriture ***/
void Request::clear()
{
mobile = NULL ;
timestamp.tv_sec = 0 ;
timestamp.tv_nsec = 0 ;
measurements.clear() ;
}
/*** Opérateurs ***/
ostream &operator<<(ostream &os, const Request &r)
{
// Timestamp
os
<< "At " << PosUtil::timespec_to_ns(r.timestamp) << "; " ;
// MAC address
os
<< "Mobile: "
<< (r.mobile != NULL ? r.mobile->get_mac_addr() : "Unknown_Mobile")
<< ":" ;
// List of Measurements
if (r.measurements.size() == 0)
os << " No values" ;
else
for (unordered_map<string, Measurement>::const_iterator i
= r.measurements.begin() ; i != r.measurements.end() ; i++)
{
os << '\n' << i->first << ": " << i->second ;
}
return os ;
}

View File

@ -0,0 +1,94 @@
#ifndef _OWLPS_POSITIONING_REQUEST_HH_
#define _OWLPS_POSITIONING_REQUEST_HH_
class Mobile ;
#include "measurement.hh"
#include <ctime>
#include <unordered_map>
#include <ostream>
class Request
{
protected:
Mobile *mobile ;
struct timespec timestamp ;
std::tr1::unordered_map<std::string, Measurement> measurements ;
public:
Request(const std::tr1::unordered_map<std::string, Measurement> &_measurements
= std::tr1::unordered_map<std::string, Measurement>()) ;
Request(const struct timespec &_timestamp,
const std::tr1::unordered_map<std::string, Measurement> &_measurements
= std::tr1::unordered_map<std::string, Measurement>()) ;
Request(const Mobile *_mobile, const struct timespec &_timestamp,
const std::tr1::unordered_map<std::string, Measurement> &_measurements
= std::tr1::unordered_map<std::string, Measurement>()) ;
Mobile* get_mobile() const ;
void set_mobile(const Mobile *_mobile) ;
void set_timestamp(const struct timespec &_timestamp) ;
void set_measurements(const std::tr1::unordered_map
<std::string, Measurement> &_measurements) ;
void clear(void) ;
operator bool(void) const ;
friend std::ostream &operator<<(std::ostream &os, const Request &r) ;
} ;
/*** Accesseurs lecture ***/
inline Mobile* Request::get_mobile() const
{
return mobile ;
}
/*** Accesseurs écriture ***/
inline void Request::set_mobile(const Mobile *_mobile)
{
mobile = (Mobile *) _mobile ;
}
inline void Request::set_timestamp(const struct timespec &_timestamp)
{
timestamp = _timestamp ;
}
inline void Request::set_measurements(const std::tr1::unordered_map
<std::string, Measurement> &_measurements)
{
measurements = _measurements ;
}
/*** Opérateurs ***/
/*
* Returns false if the Request is empty, or true if at least one
* attribute is initialised.
*/
inline Request::operator bool() const
{
return
mobile != NULL ||
timestamp.tv_sec != 0 ||
measurements.size() > 0 ;
}
#endif // _OWLPS_POSITIONING_REQUEST_HH_

View File

@ -66,7 +66,7 @@ ostream &operator<<(ostream &os, const Waypoint &wp)
os << endl << "Belongs to no building!" ;
else
for (vector<Building*>::const_iterator i = wp.buildings.begin() ;
i < wp.buildings.end() ; i++)
i != wp.buildings.end() ; i++)
os << endl << *i ;
return os ;