diff --git a/TODO b/TODO new file mode 100644 index 0000000..1cf254e --- /dev/null +++ b/TODO @@ -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 diff --git a/libowlps/libowlps.c b/libowlps/libowlps.c index 30b41ab..026203d 100644 --- a/libowlps/libowlps.c +++ b/libowlps/libowlps.c @@ -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) { diff --git a/owlps-positioning/Makefile b/owlps-positioning/Makefile index 69a9c2f..b5f3cf7 100644 --- a/owlps-positioning/Makefile +++ b/owlps-positioning/Makefile @@ -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 diff --git a/owlps-positioning/TODO b/owlps-positioning/TODO index fb105d8..1deae6e 100644 --- a/owlps-positioning/TODO +++ b/owlps-positioning/TODO @@ -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 ? diff --git a/owlps-positioning/calibrationmeasurement.hh b/owlps-positioning/calibrationmeasurement.hh index 1ceac35..ced0ea1 100644 --- a/owlps-positioning/calibrationmeasurement.hh +++ b/owlps-positioning/calibrationmeasurement.hh @@ -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 &_ss_list = std::vector(), 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): diff --git a/owlps-positioning/csv/.gitignore b/owlps-positioning/csv/.gitignore new file mode 100644 index 0000000..afed073 --- /dev/null +++ b/owlps-positioning/csv/.gitignore @@ -0,0 +1 @@ +*.csv diff --git a/owlps-positioning/inputcsv.cc b/owlps-positioning/inputcsv.cc index 8849eeb..02815cc 100644 --- a/owlps-positioning/inputcsv.cc +++ b/owlps-positioning/inputcsv.cc @@ -1,10 +1,17 @@ #include "inputcsv.hh" +#include "posutil.hh" + +#include + +#include +#include + +using namespace std ; +using std::tr1::unordered_map ; #include #include -#include -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 > tok( line, escaped_list_separator('\\', ';', '\"')) ; - vector ss_list ; + tokenizer >::iterator ti(tok.begin()) ; - for (tokenizer >::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(*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(*i)) ; + pos[i] = lexical_cast(*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 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(*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 ; } diff --git a/owlps-positioning/inputcsv.hh b/owlps-positioning/inputcsv.hh index 8601cae..b75bba0 100644 --- a/owlps-positioning/inputcsv.hh +++ b/owlps-positioning/inputcsv.hh @@ -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 ; } ; diff --git a/owlps-positioning/inputmedium.hh b/owlps-positioning/inputmedium.hh index a01fa71..aa52f3b 100644 --- a/owlps-positioning/inputmedium.hh +++ b/owlps-positioning/inputmedium.hh @@ -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 ; } diff --git a/owlps-positioning/measurement.cc b/owlps-positioning/measurement.cc index faf747a..80021dd 100644 --- a/owlps-positioning/measurement.cc +++ b/owlps-positioning/measurement.cc @@ -8,19 +8,18 @@ using namespace std ; /*** Constructeurs ***/ -Measurement::Measurement(const Mobile *_mobile, const AccessPoint *_ap, +Measurement::Measurement(const AccessPoint *_ap, const vector &_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::iterator i = ss_list.begin() ; i < ss_list.end() ; i++) + for (vector::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::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) diff --git a/owlps-positioning/measurement.hh b/owlps-positioning/measurement.hh index b46abb0..af24b0a 100644 --- a/owlps-positioning/measurement.hh +++ b/owlps-positioning/measurement.hh @@ -1,7 +1,6 @@ #ifndef _OWLPS_POSITIONING_MEASUREMENT_HH_ #define _OWLPS_POSITIONING_MEASUREMENT_HH_ -#include "mobile.hh" #include "accesspoint.hh" #include @@ -11,7 +10,6 @@ class Measurement { protected: - Mobile *mobile ; AccessPoint *ap ; float average_ss ; std::vector 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 &_ss_list = std::vector()) ; Measurement(const Measurement &m) ; ~Measurement() ; - Mobile* get_mobile() const ; AccessPoint* get_ap() const ; std::vector 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 &_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 ; } diff --git a/owlps-positioning/posutil.cc b/owlps-positioning/posutil.cc index d7869f8..01888db 100644 --- a/owlps-positioning/posutil.cc +++ b/owlps-positioning/posutil.cc @@ -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 ; +} diff --git a/owlps-positioning/posutil.hh b/owlps-positioning/posutil.hh index 6b3c063..5afebb4 100644 --- a/owlps-positioning/posutil.hh +++ b/owlps-positioning/posutil.hh @@ -1,6 +1,9 @@ #ifndef _OWLPS_POSITIONING_POSUTIL_HH_ #define _OWLPS_POSITIONING_POSUTIL_HH_ +#include +#include // 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_ diff --git a/owlps-positioning/referencepoint.cc b/owlps-positioning/referencepoint.cc index 7a02ad3..6bfe81d 100644 --- a/owlps-positioning/referencepoint.cc +++ b/owlps-positioning/referencepoint.cc @@ -160,7 +160,7 @@ ostream &operator<<(ostream &os, const ReferencePoint &rp) else for (vector::const_iterator i = rp.measurements.begin() ; - i < rp.measurements.end() ; i++) + i != rp.measurements.end() ; i++) os << endl << *i ; return os ; diff --git a/owlps-positioning/request.cc b/owlps-positioning/request.cc new file mode 100644 index 0000000..cc3d4bf --- /dev/null +++ b/owlps-positioning/request.cc @@ -0,0 +1,79 @@ +#include "request.hh" +#include "mobile.hh" + +using namespace std ; +using std::tr1::unordered_map ; + + + +/*** Constructeurs ***/ + + +Request::Request(const unordered_map &_measurements) +{ + mobile = NULL ; + timestamp.tv_sec = 0 ; + timestamp.tv_nsec = 0 ; + measurements = _measurements ; +} + + +Request::Request(const struct timespec &_timestamp, + const unordered_map &_measurements) +{ + mobile = NULL ; + timestamp = _timestamp ; + measurements = _measurements ; +} + + +Request::Request(const Mobile *_mobile, const struct timespec &_timestamp, + const unordered_map &_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::const_iterator i + = r.measurements.begin() ; i != r.measurements.end() ; i++) + { + os << '\n' << i->first << ": " << i->second ; + } + + return os ; +} diff --git a/owlps-positioning/request.hh b/owlps-positioning/request.hh new file mode 100644 index 0000000..11b6b67 --- /dev/null +++ b/owlps-positioning/request.hh @@ -0,0 +1,94 @@ +#ifndef _OWLPS_POSITIONING_REQUEST_HH_ +#define _OWLPS_POSITIONING_REQUEST_HH_ + +class Mobile ; + +#include "measurement.hh" + +#include +#include +#include + +class Request +{ +protected: + Mobile *mobile ; + struct timespec timestamp ; + std::tr1::unordered_map measurements ; + +public: + Request(const std::tr1::unordered_map &_measurements + = std::tr1::unordered_map()) ; + Request(const struct timespec &_timestamp, + const std::tr1::unordered_map &_measurements + = std::tr1::unordered_map()) ; + Request(const Mobile *_mobile, const struct timespec &_timestamp, + const std::tr1::unordered_map &_measurements + = std::tr1::unordered_map()) ; + + 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 + &_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 + &_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_ diff --git a/owlps-positioning/waypoint.cc b/owlps-positioning/waypoint.cc index 1074dad..bab373d 100644 --- a/owlps-positioning/waypoint.cc +++ b/owlps-positioning/waypoint.cc @@ -66,7 +66,7 @@ ostream &operator<<(ostream &os, const Waypoint &wp) os << endl << "Belongs to no building!" ; else for (vector::const_iterator i = wp.buildings.begin() ; - i < wp.buildings.end() ; i++) + i != wp.buildings.end() ; i++) os << endl << *i ; return os ;