diff --git a/TODO b/TODO index f46cbb2..5279ed0 100644 --- a/TODO +++ b/TODO @@ -68,4 +68,67 @@ * Positioning -- Has its own fat TODO file, which I could merge in here. +- Known bugs + ° Cannot compute the error (Real) with autocalibration requests. + +- Algorithms + ° MinMax: use a different step for X, Y and Z? + +- Autocalibration + ° Generate reference points in 3D. + ° Handle 2 APs, not only >2 APs. + ° Find why some CalibrationRequest were not deleted when + calling Stock::delete_calibration_request() (via + ReferencePoint::delete_requests()). + +- Refactoring + ° Split Stock::generate_reference_point() into several functions. + ° Write a class for Request::type? + CalibrationRequest::direction uses a dedicated class Direction, why + not Request::type? That would simplify writing of the type to + streams (no need to cast each time anymore). + ° Wi-Fi devices' list + . Merge Stock::mobiles & Stock::aps? + . Factorise AccessPointsReaderCSV & MobilesReaderCSV? + ° Members renaming + . InputMedium: + . - current_line_nb & get_current_line_nb() + . - get_next_request() −> read_next_request() + . Input: get_next_request() −> read_next_request() + . Area: p_min et p_max −> coord_min et coord_max + +- User interface + ° When reading the APs, add them to the mobiles' list (or another + way to be able to have a single entry for an AP). + ° Review the option names & descriptions. + ° Add option positioning.self-calibrate (or autocalibrate), to + activate automatically the options needed by the autocalibration. + ° Improve --verbose (and/or debug level): print the options, etc. + ° Case-insensitive string comparison (for algorithm names, etc.). + ° Use a prefix for configuration files (search for config files set + with relative path in owlps-positioning.cfg in the same directory). + +- Optimisation & code improvement + ° Multithread algorithm calls. + ° ReferencePoint: the request list should be an unordered_set + instead of a vector, to guarantee the unicity of the elements. + ° Pre-allocate vectors' memory with reserve(). + "C++ en action", p. 217. + ° Copy of containers to streams (in some operator<<() for + instance). + "C++ en action", p. 275. + ° Review all the classes to respect principles exposed in "Coder + proprement", chapter 6, p. 103: do implement accessors for each + class attribute, etc. + +- Unit tests + ° Update tests (currently unmaintained). + ° Unfinished tests: + . InputDataReader + . Input + . Output + . Positioning + ° Test InterlinkNetworks::compute() ? + ° Timestamp: there is a probability of 10^-6 that the value in + nanoseconds and the rounded value in milliseconds are identical, in + which case some tests can fail. diff --git a/libowlps-client/Makefile_atheros_openwrt-10.03 b/libowlps-client/Makefile_atheros_openwrt-10.03 index e171c83..5cb21ed 100644 --- a/libowlps-client/Makefile_atheros_openwrt-10.03 +++ b/libowlps-client/Makefile_atheros_openwrt-10.03 @@ -66,3 +66,8 @@ purge : clean help : @make help + + +# Local Variables: * +# mode: makefile-gmake * +# End: * diff --git a/libowlps-client/Makefile_atheros_openwrt-8.09 b/libowlps-client/Makefile_atheros_openwrt-8.09 index 0398f6d..95b4248 100644 --- a/libowlps-client/Makefile_atheros_openwrt-8.09 +++ b/libowlps-client/Makefile_atheros_openwrt-8.09 @@ -67,3 +67,8 @@ purge : clean help : @make help + + +# Local Variables: * +# mode: makefile-gmake * +# End: * diff --git a/libowlps/Makefile_atheros_openwrt-10.03 b/libowlps/Makefile_atheros_openwrt-10.03 index 69b9690..e9f76cd 100644 --- a/libowlps/Makefile_atheros_openwrt-10.03 +++ b/libowlps/Makefile_atheros_openwrt-10.03 @@ -121,3 +121,8 @@ purge : clean help : @make help + + +# Local Variables: * +# mode: makefile-gmake * +# End: * diff --git a/libowlps/Makefile_atheros_openwrt-8.09 b/libowlps/Makefile_atheros_openwrt-8.09 index 03d1eaa..2543c40 100644 --- a/libowlps/Makefile_atheros_openwrt-8.09 +++ b/libowlps/Makefile_atheros_openwrt-8.09 @@ -123,3 +123,8 @@ purge : clean help : @make help + + +# Local Variables: * +# mode: makefile-gmake * +# End: * diff --git a/libowlps/owlps.h b/libowlps/owlps.h index 5a5cfd5..40bd0ba 100644 --- a/libowlps/owlps.h +++ b/libowlps/owlps.h @@ -157,83 +157,6 @@ typedef struct _owl_autocalibration_order #define OWL_80211_HZ_CHANNEL_14 2477000000ul - -/* Packet header sizes (in bytes) */ -#define IEEE80211_HEADER_SIZE_DATA 24 // Header size for a Data frame -#define LLC_HEADER_SIZE 8 - -/* IEEE 802.11 frame types */ -// Beacon (TODO: convert to mask) -#define RAW_PACKET_TYPE_BEACON 0x80 - -// Data frame -#define FRAME_TYPE_DATA_MASK 0x08 -#define IS_DATA_FRAME(FC1) \ - (((FC1) & FRAME_TYPE_DATA_MASK) == FRAME_TYPE_DATA_MASK) - -// QoS Data frame -#define FRAME_SUBTYPE_QOS_MASK 0x80 -#define DATA_FRAME_IS_QOS(FC1) \ - (((FC1) & FRAME_SUBTYPE_QOS_MASK) == FRAME_SUBTYPE_QOS_MASK) - -// To/From DS -#define FRAME_FROM_STA_MASK 0x02 -#define IS_FRAME_FROM_STA(FC2) \ - (((FC2) & FRAME_FROM_STA_MASK) != FRAME_FROM_STA_MASK) - - -/* Positions of the radiotap header fixed fields (in bytes) */ -#define RTAP_P_HREVISION 0 // Header revision -#define RTAP_P_HPAD 1 // Header pad -#define RTAP_P_HLENGTH 2 // Header length -#define RTAP_P_PRESENTFLAGS 4 // Present flags - - -/* Radiotap field lengths (in bytes) */ -#define RTAP_L_HREVISION 1 // Header revision -#define RTAP_L_HPAD 1 // Header pad -#define RTAP_L_HLENGTH 2 // Header length -#define RTAP_L_PRESENTFLAGS 4 // Present flags -#define RTAP_L_MACTS 8 // MAC timestamp (Time Synchronization Function Timer) -#define RTAP_L_FLAGS 1 // autre champ de flags -#define RTAP_L_RATE 1 // Data rate -#define RTAP_L_CHANNEL 2 // Channel frequency -#define RTAP_L_CHANNELTYPE 2 // Channel type -#define RTAP_L_ANTENNASIGNALDBM 1 // SSI signal (dBm) -#define RTAP_L_ANTENNANOISEDBM 1 // SSI noise (dBm) -#define RTAP_L_ANTENNA 1 // Antenna number -#define RTAP_L_FHSS 2 // Hop set and pattern for Frequency-Hopping Spread Spectrum -#define RTAP_L_LOCKQUALITY 2 // Signal quality -#define RTAP_L_TXATTENUATION 2 // Transmit power from max power -#define RTAP_L_TXATTENUATIONDB 2 // Idem (dB) -#define RTAP_L_TXATTENUATIONDBM 1 // Idem (dBm) -#define RTAP_L_ANTENNASIGNALDB 1 // SSI signal (dB) -#define RTAP_L_ANTENNANOISEDB 1 // SSI noise (dB) -#define RTAP_L_FCS 4 // Frame Check Sequence -//#define RTAP_L_CHANNELP // Extended channel info (not implemented) -//#define RTAP_L_EXT // Extension aux Present flags (not emplemented) - - -/* Positions in 'Present flags' (and present fields 'check' array) */ -#define RTAP_MACTS 0 -#define RTAP_FLAGS 1 -#define RTAP_RATE 2 -#define RTAP_CHANNEL 3 // and RTAP_CHANNELTYPE -#define RTAP_FHSS 4 -#define RTAP_ANTENNASIGNALDBM 5 -#define RTAP_ANTENNANOISEDBM 6 -#define RTAP_LOCKQUALITY 7 -#define RTAP_TXATTENUATION 8 -#define RTAP_TXATTENUATIONDB 9 -#define RTAP_TXATTENUATIONDBM 10 -#define RTAP_ANTENNA 11 -#define RTAP_ANTENNASIGNALDB 12 -#define RTAP_ANTENNANOISEDB 13 -#define RTAP_FCS 14 -//#define RTAP_CHANNELP 18 -//#define RTAP_EXT 31 - - /* Misc. */ // Length of a MAC address in string format (including '\0') #define OWL_ETHER_ADDR_STRLEN 18 @@ -245,10 +168,6 @@ extern owl_bool owl_run ; /* Function error codes */ -#define ERR_SETTING_MODE 101 -#define ERR_SETTING_CHANNEL 102 -#define ERR_READING_CHANNEL 103 -#define ERR_READING_MODE 104 #define ERR_BAD_SIGNAL 111 diff --git a/owlps-aggregator/owlps-aggregatord.c b/owlps-aggregator/owlps-aggregatord.c index 98a12b2..7047e3f 100644 --- a/owlps-aggregator/owlps-aggregatord.c +++ b/owlps-aggregator/owlps-aggregatord.c @@ -605,7 +605,7 @@ void* monitor_requests(void *NULL_value) request_info_ptr = request_ptr->info ; while (request_info_ptr != NULL) { - request.nb_info++; + ++request.nb_info ; request_info_ptr = request_info_ptr->next ; } // Endianess conversions: diff --git a/owlps-ardrone/owlps-drone.c b/owlps-ardrone/owlps-drone.c index 9b4575f..6dca8ea 100644 --- a/owlps-ardrone/owlps-drone.c +++ b/owlps-ardrone/owlps-drone.c @@ -798,28 +798,29 @@ void* receive_position(void* NULL_value) } +/* Split the string received from OwlPS Positioning and store the fields + * in a result structure. + * + * Handled CSV format: + * Mobile_MAC;Request_type;Request_timestamp;Algorithm;X;Y;Z;Error;Area + * The Request_timestamp format is: seconds.nanoseconds + */ void string2data(char* string_data) { - /*Découpage de la chaine de caractère reçu du serveur de positionnement - sous forme de addrMAC;TypeRequete;Timestamp1.Timestamp2;Algo;X;Y;Z - en variables séparées - */ - char *mac = NULL ; char *ptr = NULL ; - char *delims = ";" ; + const char delims[] = ";" ; int type_req = 0 ; int count_algo= 0 ; int count_print = 0 ; int onetime = 0 ; - int error = 0 ; + owl_bool error_present = FALSE ; while(onetime<1) { - - //Lecture Adresse Mac + // Mobile MAC address ptr = strtok(string_data, delims) ; if(ptr==NULL) { @@ -828,7 +829,7 @@ void string2data(char* string_data) } mac = ptr ; - //Lecture Type Request + // Request type ptr = strtok(NULL, delims) ; if (ptr==NULL) { @@ -837,7 +838,7 @@ void string2data(char* string_data) } type_req = atoi(ptr) ; - //Lecture TimeStamp1 + // Timestamp (seconds) ptr = strtok(NULL, ".") ; if (ptr==NULL) { @@ -846,7 +847,7 @@ void string2data(char* string_data) } sscanf(ptr, "%ld", ×tamp.tv_sec) ; - //Lecture TimeStamp2 + // Timestamp (nanoseconds) ptr = strtok(NULL, ";") ; if (ptr==NULL) { @@ -860,14 +861,15 @@ void string2data(char* string_data) while(run) { - //Lecture de l'algorythme utilisé + // Algorithm name ptr = strtok(NULL, delims) ; - if(ptr==NULL) break ; - sscanf(ptr, "%s", results[count_algo].algo) ; + if (ptr == NULL) + break ; + strncpy(results[count_algo].algo, ptr, ALGO_STRLEN) ; if(!strcmp(results[count_algo].algo,"Real")) - error=1; + error_present = TRUE ; - //Lecture du point X + // X coordinate ptr = strtok(NULL, delims) ; if(ptr==NULL) { @@ -885,7 +887,7 @@ void string2data(char* string_data) } results[count_algo].x = atof(ptr) ; - //Lecture du point Y + // Y coordinate ptr = strtok(NULL, delims) ; if(ptr==NULL) { @@ -903,7 +905,7 @@ void string2data(char* string_data) } results[count_algo].y = atof(ptr) ; - //Lecture du point Z + // Z coordinate ptr = strtok(NULL, delims) ; if(ptr==NULL) { @@ -914,15 +916,16 @@ void string2data(char* string_data) } else { - perror ("algo"); + print_error("algo") ; count_algo--; break ; } } results[count_algo].z = atof(ptr) ; - if(error==1) + + // Distance error + if (error_present) { - //Lecture du message Error ptr = strtok(NULL, delims) ; if(ptr==NULL) { @@ -938,52 +941,50 @@ void string2data(char* string_data) break ; } } - results[count_algo].check = ptr ; - - //Lecture valeur Error - ptr = strtok(NULL, delims) ; - if(ptr==NULL) - { - if(count_algo==0) - { - print_error ("trame"); - break ; - } - else - { - perror ("algo"); - count_algo--; - break ; - } - } - results[count_algo].err = atof(ptr) ; - - - ++count_algo ; + results[count_algo].error = atof(ptr) ; } + ++count_algo ; - else - ++count_algo ; + // Area name + ptr = strtok(NULL, delims) ; + if (ptr == NULL) + { + if (count_algo == 0) + { + print_error("trame") ; + break ; + } + else + { + print_error("algo") ; + count_algo-- ; + break ; + } + } + strncpy(results[count_algo].area, ptr, AREA_STRLEN) ; } for (count_print = 0 ; count_print < count_algo ; ++count_print) printf("\n----------------\n" - " Adresse Mac : %s\n" - " Type de requete : %d\n" - " Timestamp : %ld.%ld\n" - " Algo : %s\n" - " X : %f\n " - " Y : %f\n" - " Z : %f\n" + " Mobile's MAC address: %s\n" + " Request type: %d\n" + " Timestamp: %ld.%ld\n" + " Algorithm: %s\n" + " X: %f\n" + " Y: %f\n" + " Z: %f\n" + " Distance error: %f\n" + " Area: %s\n" "------------------\n", mac, type_req, - timestamp.tv_sec, - timestamp.tv_nsec, + timestamp.tv_sec, timestamp.tv_nsec, results[count_print].algo, results[count_print].x, results[count_print].y, - results[count_print].z) ; + results[count_print].z, + results[count_print].error, + results[count_print].area) ; } diff --git a/owlps-ardrone/owlps-drone.h b/owlps-ardrone/owlps-drone.h index 427f714..bae6da7 100644 --- a/owlps-ardrone/owlps-drone.h +++ b/owlps-ardrone/owlps-drone.h @@ -15,8 +15,9 @@ #define DEFAULT_DELAY_CALIB 50000 // Calibration request #define DEFAULT_DELAY_NORMAL 25000 // Localisation request -/* Maximum length of the algorithm name */ +/* Maximum length of the algorithm & area names */ #define ALGO_STRLEN 15 +#define AREA_STRLEN 50 /* GPS inputs */ #define SEPARATOR ',' @@ -38,15 +39,15 @@ #define ERR_BAD_USAGE 1 // Bad program call (bad number of arguments) -/* Received result */ +/* Result from OwlPS Positioning (parsed string structure) */ typedef struct _result { char algo[ALGO_STRLEN]; float x; float y; float z; - char *check; - float err; + float error ; + char area[AREA_STRLEN] ; } result ; typedef struct _gps diff --git a/owlps-client/Makefile_atheros_openwrt-10.03 b/owlps-client/Makefile_atheros_openwrt-10.03 index 32a460a..b7c93b1 100644 --- a/owlps-client/Makefile_atheros_openwrt-10.03 +++ b/owlps-client/Makefile_atheros_openwrt-10.03 @@ -99,3 +99,8 @@ purge : clean help : @make -f Makefile_atheros help + + +# Local Variables: * +# mode: makefile-gmake * +# End: * diff --git a/owlps-client/Makefile_atheros_openwrt-8.09 b/owlps-client/Makefile_atheros_openwrt-8.09 index 871a021..702da67 100644 --- a/owlps-client/Makefile_atheros_openwrt-8.09 +++ b/owlps-client/Makefile_atheros_openwrt-8.09 @@ -114,3 +114,8 @@ $(TARGET).semistatic (version sans lien dynamique vers libowlps)." @echo @echo "Note : l'installation se fait dans l'arborescence $(PREFIX). \ Modifiez la variable PREFIX du Makefile pour changer ce comportement." + + +# Local Variables: * +# mode: makefile-gmake * +# End: * diff --git a/owlps-client/owlps-client.c b/owlps-client/owlps-client.c index d059f6e..2a3f8c8 100644 --- a/owlps-client/owlps-client.c +++ b/owlps-client/owlps-client.c @@ -157,7 +157,7 @@ void parse_main_options(int argc, char **argv) // Take the optind value: options.flood_delay = strtoul(argv[optind], NULL, 0) ; - optind++ ; + ++optind ; } } break ; @@ -185,7 +185,7 @@ void parse_main_options(int argc, char **argv) // Take the optind value: options.listening_port = strtoul(argv[optind], NULL, 0) ; - optind++ ; + ++optind ; } } break ; diff --git a/owlps-listener/Makefile_atheros_openwrt-10.03 b/owlps-listener/Makefile_atheros_openwrt-10.03 index b9c8a52..343175e 100644 --- a/owlps-listener/Makefile_atheros_openwrt-10.03 +++ b/owlps-listener/Makefile_atheros_openwrt-10.03 @@ -101,3 +101,8 @@ purge : clean help : @make help + + +# Local Variables: * +# mode: makefile-gmake * +# End: * diff --git a/owlps-listener/Makefile_atheros_openwrt-8.09 b/owlps-listener/Makefile_atheros_openwrt-8.09 index efb6d81..a5bc864 100644 --- a/owlps-listener/Makefile_atheros_openwrt-8.09 +++ b/owlps-listener/Makefile_atheros_openwrt-8.09 @@ -97,3 +97,8 @@ purge : clean help : @make help + + +# Local Variables: * +# mode: makefile-gmake * +# End: * diff --git a/owlps-listener/owlps-listener.h b/owlps-listener/owlps-listener.h index 16118fe..fd657e8 100644 --- a/owlps-listener/owlps-listener.h +++ b/owlps-listener/owlps-listener.h @@ -71,11 +71,89 @@ enum {MODE_ACTIVE = 'a', MODE_PASSIVE = 'p', MODE_MIXED = 'm'} ; #define VERBOSE_CHATTERBOX GET_VERBOSE() >= 3 +/* Packet header sizes (in bytes) */ +#define IEEE80211_HEADER_SIZE_DATA 24 // Header size for a Data frame +#define LLC_HEADER_SIZE 8 + +/* IEEE 802.11 frame types */ +// Beacon (TODO: convert to mask) +#define RAW_PACKET_TYPE_BEACON 0x80 + +// Data frame +#define FRAME_TYPE_DATA_MASK 0x08 +#define IS_DATA_FRAME(FC1) \ + (((FC1) & FRAME_TYPE_DATA_MASK) == FRAME_TYPE_DATA_MASK) + +// QoS Data frame +#define FRAME_SUBTYPE_QOS_MASK 0x80 +#define DATA_FRAME_IS_QOS(FC1) \ + (((FC1) & FRAME_SUBTYPE_QOS_MASK) == FRAME_SUBTYPE_QOS_MASK) + +// To/From DS +#define FRAME_FROM_STA_MASK 0x02 +#define IS_FRAME_FROM_STA(FC2) \ + (((FC2) & FRAME_FROM_STA_MASK) != FRAME_FROM_STA_MASK) + + +/* Positions of the radiotap header fixed fields (in bytes) */ +#define RTAP_P_HREVISION 0 // Header revision +#define RTAP_P_HPAD 1 // Header pad +#define RTAP_P_HLENGTH 2 // Header length +#define RTAP_P_PRESENTFLAGS 4 // Present flags + + +/* Radiotap field lengths (in bytes) */ +#define RTAP_L_HREVISION 1 // Header revision +#define RTAP_L_HPAD 1 // Header pad +#define RTAP_L_HLENGTH 2 // Header length +#define RTAP_L_PRESENTFLAGS 4 // Present flags +#define RTAP_L_MACTS 8 // MAC timestamp (Time Synchronization Function Timer) +#define RTAP_L_FLAGS 1 // autre champ de flags +#define RTAP_L_RATE 1 // Data rate +#define RTAP_L_CHANNEL 2 // Channel frequency +#define RTAP_L_CHANNELTYPE 2 // Channel type +#define RTAP_L_ANTENNASIGNALDBM 1 // SSI signal (dBm) +#define RTAP_L_ANTENNANOISEDBM 1 // SSI noise (dBm) +#define RTAP_L_ANTENNA 1 // Antenna number +#define RTAP_L_FHSS 2 // Hop set and pattern for Frequency-Hopping Spread Spectrum +#define RTAP_L_LOCKQUALITY 2 // Signal quality +#define RTAP_L_TXATTENUATION 2 // Transmit power from max power +#define RTAP_L_TXATTENUATIONDB 2 // Idem (dB) +#define RTAP_L_TXATTENUATIONDBM 1 // Idem (dBm) +#define RTAP_L_ANTENNASIGNALDB 1 // SSI signal (dB) +#define RTAP_L_ANTENNANOISEDB 1 // SSI noise (dB) +#define RTAP_L_FCS 4 // Frame Check Sequence +//#define RTAP_L_CHANNELP // Extended channel info (not implemented) +//#define RTAP_L_EXT // Present flags' extension (not emplemented) + + +/* Positions in 'Present flags' (and present fields 'check' array) */ +#define RTAP_MACTS 0 +#define RTAP_FLAGS 1 +#define RTAP_RATE 2 +#define RTAP_CHANNEL 3 // and RTAP_CHANNELTYPE +#define RTAP_FHSS 4 +#define RTAP_ANTENNASIGNALDBM 5 +#define RTAP_ANTENNANOISEDBM 6 +#define RTAP_LOCKQUALITY 7 +#define RTAP_TXATTENUATION 8 +#define RTAP_TXATTENUATIONDB 9 +#define RTAP_TXATTENUATIONDBM 10 +#define RTAP_ANTENNA 11 +#define RTAP_ANTENNASIGNALDB 12 +#define RTAP_ANTENNANOISEDB 13 +#define RTAP_FCS 14 +//#define RTAP_CHANNELP 18 +//#define RTAP_EXT 31 + + /* Error codes */ #define ERR_OPENING_IFACE 2 // Error when opening capture interface #define ERR_BAD_USAGE 3 // Bad program call #define ERR_PARSING_CONFIG_FILE 4 // Error reading the configuration file #define ERR_CREATING_THREAD 6 // Error creating a thread +#define ERR_SETTING_MODE 101 +#define ERR_READING_MODE 104 /* Function headers */ @@ -98,6 +176,11 @@ int iface_mode_monitor(const char *const iface) ; int capture(void) ; void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) ; +void extract_calibration_data(const u_char *packet, + owl_captured_request *request) ; +void extract_radiotap_data(const u_char *packet, + owl_captured_request *request, + owl_bool rtap_fields[15]) ; void get_mac_addr(char *eth, uint8_t mac_bytes[ETHER_ADDR_LEN]) ; void get_ip_addr(char *eth, char *ip_bytes) ; diff --git a/owlps-listener/owlps-listenerd.c b/owlps-listener/owlps-listenerd.c index 7a6ef97..56e0033 100644 --- a/owlps-listener/owlps-listenerd.c +++ b/owlps-listener/owlps-listenerd.c @@ -770,12 +770,9 @@ int capture() void read_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { - uint16_t rtap_bytes ; // Received data size - uint32_t rtap_presentflags ; - uint_fast16_t rtap_position ; owl_captured_request request ; // Message to send to the aggregator - ssize_t nsent ; // sendto return value - owl_bool check[15] ; // Present flags + uint16_t rtap_bytes ; // Radiotap header size + owl_bool rtap_fields[15] ; // Present flags uint8_t raw_packet_fc1 ; // First byte of the received frame's FC uint8_t raw_packet_fc2 ; // Second byte of the received frame's FC uint8_t raw_packet_flags ; // IEEE 802.11 header flags @@ -790,7 +787,7 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, owl_bool is_explicit_packet = TRUE ; // Is the packet an explicit request? // Is the packet an autocalibration positioning request? owl_bool uses_autocalibration_request_port = FALSE ; - int i ; // Iterator + ssize_t nsent ; // sendto return value // Blank the request: memset(&request, 0, sizeof(request)) ; @@ -909,21 +906,12 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, case OWL_REQUEST_CALIBRATION : if (VERBOSE_INFO) printf("\nExplicit calibration packet received.\n") ; - request.direction = - packet[rtap_bytes + ieee80211_header_size + LLC_HEADER_SIZE - + sizeof(struct iphdr) + sizeof(struct udphdr) + 9]; - memcpy(&request.x_position, - &packet[rtap_bytes + ieee80211_header_size - + LLC_HEADER_SIZE + sizeof(struct iphdr) - + sizeof(struct udphdr) + 10], sizeof(float)) ; - memcpy(&request.y_position, - &packet[rtap_bytes + ieee80211_header_size - + LLC_HEADER_SIZE + sizeof(struct iphdr) - + sizeof(struct udphdr) + 14], sizeof(float)) ; - memcpy(&request.z_position, - &packet[rtap_bytes + ieee80211_header_size - + LLC_HEADER_SIZE + sizeof(struct iphdr) - + sizeof(struct udphdr) + 18], sizeof(float)) ; + extract_calibration_data(&packet[rtap_bytes + + ieee80211_header_size + + LLC_HEADER_SIZE + + sizeof(struct iphdr) + + sizeof(struct udphdr) + 9], + &request) ; break ; case OWL_REQUEST_AUTOCALIBRATION : @@ -934,21 +922,12 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, printf(".. on the wrong port!") ; putchar('\n') ; } - request.direction = - packet[rtap_bytes + ieee80211_header_size + LLC_HEADER_SIZE - + sizeof(struct iphdr) + sizeof(struct udphdr) + 9]; - memcpy(&request.x_position, - &packet[rtap_bytes + ieee80211_header_size - + LLC_HEADER_SIZE + sizeof(struct iphdr) - + sizeof(struct udphdr) + 10], sizeof(float)) ; - memcpy(&request.y_position, - &packet[rtap_bytes + ieee80211_header_size - + LLC_HEADER_SIZE + sizeof(struct iphdr) - + sizeof(struct udphdr) + 14], sizeof(float)) ; - memcpy(&request.z_position, - &packet[rtap_bytes + ieee80211_header_size - + LLC_HEADER_SIZE + sizeof(struct iphdr) - + sizeof(struct udphdr) + 18], sizeof(float)) ; + extract_calibration_data(&packet[rtap_bytes + + ieee80211_header_size + + LLC_HEADER_SIZE + + sizeof(struct iphdr) + + sizeof(struct udphdr) + 9], + &request) ; break ; default : @@ -991,96 +970,8 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, else // Active mode, packet was not an explicit request return ; - /* Radiotap header handling */ - - // Get rtap flags: - memcpy(&rtap_presentflags, - &packet[RTAP_P_PRESENTFLAGS], RTAP_L_PRESENTFLAGS) ; - // Radiotap header is little-endian - rtap_presentflags = le32toh(rtap_presentflags) ; - - for (i = 0 ; i < 15 ; i++) // Initialise present flags structure - check[i] = FALSE ; - rtap_position = 8 ; // Begining of the present flags determined fields - - // Test the first 15 bits of the flag field in order to check their - // presence and to copy them: - for (i = 0 ; i < 15 ; i++) - { - if ((rtap_presentflags % 2) == 1) - { - switch(i) - { - case RTAP_MACTS: - check[RTAP_MACTS] = TRUE ; - rtap_position += RTAP_L_MACTS ; - break ; - case RTAP_FLAGS: - check[RTAP_FLAGS] = TRUE; - rtap_position += RTAP_L_FLAGS ; - break ; - case RTAP_RATE: - check[RTAP_RATE] = TRUE; - rtap_position += RTAP_L_RATE ; - break ; - case RTAP_CHANNEL: - rtap_position += RTAP_L_CHANNEL ; - rtap_position += RTAP_L_CHANNELTYPE ; - break ; - case RTAP_FHSS: - check[RTAP_FHSS] = TRUE; - rtap_position += RTAP_L_FHSS ; - break ; - case RTAP_ANTENNASIGNALDBM: - memcpy(&(request.antenna_signal_dbm), - &packet[rtap_position], RTAP_L_ANTENNASIGNALDBM) ; - check[RTAP_ANTENNASIGNALDBM] = TRUE; - if (VERBOSE_INFO) - printf("Antenna signal: %d dBm\n", - request.antenna_signal_dbm - 0x100); - rtap_position += RTAP_L_ANTENNASIGNALDBM ; - break ; - case RTAP_ANTENNANOISEDBM: - check[RTAP_ANTENNANOISEDBM] = TRUE; - rtap_position += RTAP_L_ANTENNANOISEDBM ; - break ; - case RTAP_LOCKQUALITY: - check[RTAP_LOCKQUALITY] = TRUE; - rtap_position += RTAP_L_LOCKQUALITY ; - break ; - case RTAP_TXATTENUATION: - check[RTAP_TXATTENUATION] = TRUE; - rtap_position += RTAP_L_TXATTENUATION ; - break ; - case RTAP_TXATTENUATIONDB: - check[RTAP_TXATTENUATIONDB] = TRUE; - rtap_position += RTAP_L_TXATTENUATIONDB ; - break ; - case RTAP_TXATTENUATIONDBM: - check[RTAP_TXATTENUATIONDBM] = TRUE; - rtap_position += RTAP_L_TXATTENUATIONDBM ; - break ; - case RTAP_ANTENNA: - check[RTAP_ANTENNA] = TRUE; - rtap_position += RTAP_L_ANTENNA ; - break ; - case RTAP_ANTENNASIGNALDB: - check[RTAP_ANTENNASIGNALDB] = TRUE; - rtap_position += RTAP_L_ANTENNASIGNALDB ; - break ; - case RTAP_ANTENNANOISEDB: - check[RTAP_ANTENNANOISEDB] = TRUE; - rtap_position += RTAP_L_ANTENNANOISEDB ; - break ; - case RTAP_FCS: - check[RTAP_FCS] = TRUE; - rtap_position += RTAP_L_FCS ; - break ; - } - } - rtap_presentflags /= 2 ; - } + extract_radiotap_data(packet, &request, rtap_fields) ; /* Display the packet details */ if (GET_DISPLAY_CAPTURED()) @@ -1109,7 +1000,7 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, owl_mac_bytes_to_string(request.mobile_mac_addr_bytes), request_time_str, start_time_str, - check[RTAP_ANTENNASIGNALDBM] ? + rtap_fields[RTAP_ANTENNASIGNALDBM] ? request.antenna_signal_dbm - 0x100 : 0, owl_ntohf(request.x_position), owl_ntohf(request.y_position), @@ -1132,6 +1023,126 @@ void read_packet(u_char *args, const struct pcap_pkthdr *header, +/* + * Fills 'request' with the calibration data extracted from 'packet'. + * Note: 'packet' is read from its first byte, therefore you must not + * pass the whole received packet to this function. + */ +void extract_calibration_data(const u_char *packet, + owl_captured_request *request) +{ + request->direction = packet[0] ; + memcpy(&request->x_position, &packet[1], sizeof(float)) ; + memcpy(&request->y_position, &packet[4], sizeof(float)) ; + memcpy(&request->z_position, &packet[8], sizeof(float)) ; +} + + + +/* + * Fills 'request' with the required data extracted from the Radiotap + * header of 'packet'. The elements of 'rtap_fields' are set to TRUE + * when the corresponding Radiotap flag is found in the packet. + */ +void extract_radiotap_data(const u_char *packet, + owl_captured_request *request, + owl_bool rtap_fields[15]) +{ + uint32_t rtap_presentflags ; + uint_fast16_t rtap_position ; + int i ; // Iterator + + // Get rtap flags: + memcpy(&rtap_presentflags, + &packet[RTAP_P_PRESENTFLAGS], RTAP_L_PRESENTFLAGS) ; + // The Radiotap header is little-endian + rtap_presentflags = le32toh(rtap_presentflags) ; + + for (i = 0 ; i < 15 ; ++i) // Initialise present flags structure + rtap_fields[i] = FALSE ; + rtap_position = 8 ; // Begining of the present flags determined fields + + // Test the first 15 bits of the flag field in order to check their + // presence and to copy them: + for (i = 0 ; i < 15 ; ++i) + { + if ((rtap_presentflags % 2) == 1) + { + switch(i) + { + case RTAP_MACTS: + rtap_fields[RTAP_MACTS] = TRUE ; + rtap_position += RTAP_L_MACTS ; + break ; + case RTAP_FLAGS: + rtap_fields[RTAP_FLAGS] = TRUE; + rtap_position += RTAP_L_FLAGS ; + break ; + case RTAP_RATE: + rtap_fields[RTAP_RATE] = TRUE; + rtap_position += RTAP_L_RATE ; + break ; + case RTAP_CHANNEL: + rtap_position += RTAP_L_CHANNEL ; + rtap_position += RTAP_L_CHANNELTYPE ; + break ; + case RTAP_FHSS: + rtap_fields[RTAP_FHSS] = TRUE; + rtap_position += RTAP_L_FHSS ; + break ; + case RTAP_ANTENNASIGNALDBM: + memcpy(&request->antenna_signal_dbm, + &packet[rtap_position], RTAP_L_ANTENNASIGNALDBM) ; + rtap_fields[RTAP_ANTENNASIGNALDBM] = TRUE; + if (VERBOSE_INFO) + printf("Antenna signal: %d dBm\n", + request->antenna_signal_dbm - 0x100); + rtap_position += RTAP_L_ANTENNASIGNALDBM ; + break ; + case RTAP_ANTENNANOISEDBM: + rtap_fields[RTAP_ANTENNANOISEDBM] = TRUE; + rtap_position += RTAP_L_ANTENNANOISEDBM ; + break ; + case RTAP_LOCKQUALITY: + rtap_fields[RTAP_LOCKQUALITY] = TRUE; + rtap_position += RTAP_L_LOCKQUALITY ; + break ; + case RTAP_TXATTENUATION: + rtap_fields[RTAP_TXATTENUATION] = TRUE; + rtap_position += RTAP_L_TXATTENUATION ; + break ; + case RTAP_TXATTENUATIONDB: + rtap_fields[RTAP_TXATTENUATIONDB] = TRUE; + rtap_position += RTAP_L_TXATTENUATIONDB ; + break ; + case RTAP_TXATTENUATIONDBM: + rtap_fields[RTAP_TXATTENUATIONDBM] = TRUE; + rtap_position += RTAP_L_TXATTENUATIONDBM ; + break ; + case RTAP_ANTENNA: + rtap_fields[RTAP_ANTENNA] = TRUE; + rtap_position += RTAP_L_ANTENNA ; + break ; + case RTAP_ANTENNASIGNALDB: + rtap_fields[RTAP_ANTENNASIGNALDB] = TRUE; + rtap_position += RTAP_L_ANTENNASIGNALDB ; + break ; + case RTAP_ANTENNANOISEDB: + rtap_fields[RTAP_ANTENNANOISEDB] = TRUE; + rtap_position += RTAP_L_ANTENNANOISEDB ; + break ; + case RTAP_FCS: + rtap_fields[RTAP_FCS] = TRUE; + rtap_position += RTAP_L_FCS ; + break ; + } + } + rtap_presentflags /= 2 ; + } +} + + + /* * Get our own MAC address and copy it to 'mac_bytes'. */ diff --git a/owlps-positioning/Makefile b/owlps-positioning/Makefile index fe62d29..ab42305 100644 --- a/owlps-positioning/Makefile +++ b/owlps-positioning/Makefile @@ -101,6 +101,7 @@ OBJ_NOTEST_LIST = \ posexcept.o \ multilaterationalgorithm.o \ cartographyalgorithm.o \ + outputnetworksocket.o \ inputmedium.o INTERFACES_LIST = \ inputlogmedium.hh \ @@ -214,17 +215,24 @@ $(OBJ_DIR)/csvfilereader.o: \ $(OBJ_DIR)/textfilereader.o $(OBJ_DIR)/textfilewriter.o: \ $(OBJ_DIR)/posexcept.o +$(OBJ_DIR)/inputmedium.o: \ + $(OBJ_DIR)/calibrationrequest.o \ + $(OBJ_DIR)/posexcept.o \ + $(OBJ_DIR)/configuration.o \ + $(OBJ_DIR)/stock.o $(OBJ_DIR)/inputcsv.o: \ $(OBJ_DIR)/inputmedium.o \ $(OBJ_DIR)/csvfilereader.o \ $(OBJ_DIR)/request.o \ $(OBJ_DIR)/calibrationrequest.o \ + $(OBJ_DIR)/configuration.o \ $(OBJ_DIR)/stock.o $(OBJ_DIR)/inputudpsocket.o: \ $(OBJ_DIR)/inputmedium.o \ $(OBJ_DIR)/posexcept.o \ $(OBJ_DIR)/request.o \ $(OBJ_DIR)/calibrationrequest.o \ + $(OBJ_DIR)/configuration.o \ $(OBJ_DIR)/stock.o $(OBJ_DIR)/inputlogcsv.o: \ $(SRC_DIR)/inputlogmedium.hh \ @@ -246,12 +254,24 @@ $(OBJ_DIR)/outputcsv.o: \ $(OBJ_DIR)/textfilewriter.o \ $(OBJ_DIR)/resultlist.o \ $(OBJ_DIR)/result.o +$(OBJ_DIR)/outputnetworksocket.o: \ + $(SRC_DIR)/outputmedium.hh \ + $(OBJ_DIR)/resultlist.o \ + $(OBJ_DIR)/result.o $(OBJ_DIR)/outputudpsocket.o: \ - $(SRC_DIR)/outputmedium.hh \ - $(OBJ_DIR)/result.o + $(OBJ_DIR)/outputnetworksocket.o \ + $(OBJ_DIR)/request.o \ + $(OBJ_DIR)/resultlist.o \ + $(OBJ_DIR)/result.o \ + $(OBJ_DIR)/posexcept.o $(OBJ_DIR)/outputtcpsocketevaal.o: \ - $(SRC_DIR)/outputmedium.hh \ - $(OBJ_DIR)/result.o + $(OBJ_DIR)/outputnetworksocket.o \ + $(OBJ_DIR)/request.o \ + $(OBJ_DIR)/resultlist.o \ + $(OBJ_DIR)/result.o \ + $(OBJ_DIR)/area.o \ + $(OBJ_DIR)/posexcept.o \ + $(OBJ_DIR)/stock.o $(OBJ_DIR)/outputcsv.o: \ $(SRC_DIR)/outputmedium.hh \ $(OBJ_DIR)/result.o @@ -278,7 +298,9 @@ $(OBJ_DIR)/minmax.o: \ $(OBJ_DIR)/interlinknetworks.o: \ $(OBJ_DIR)/multilaterationalgorithm.o $(OBJ_DIR)/fbcm.o: \ - $(OBJ_DIR)/multilaterationalgorithm.o + $(OBJ_DIR)/multilaterationalgorithm.o \ + $(OBJ_DIR)/configuration.o \ + $(OBJ_DIR)/stock.o $(OBJ_DIR)/frbhmbasic.o: \ $(OBJ_DIR)/radar.o \ $(OBJ_DIR)/fbcm.o diff --git a/owlps-positioning/TODO b/owlps-positioning/TODO deleted file mode 100644 index 3bf131e..0000000 --- a/owlps-positioning/TODO +++ /dev/null @@ -1,88 +0,0 @@ - -- Known bugs - ° FBCM always gives the same result. - ° Cannot compute the error (Real) with autocalibration requests. - -- Algorithms - ° Check MultilaterationAlgorithm::make_constant_term(). - Hint: mobile.trx_power() vs. ap.trx_power(). - ° MinMax: use a different step for X, Y and Z? - -- Autocalibration - ° Generate reference points in 3D. - ° Handle 2 APs, not only >2 APs. - ° Find why some CalibrationRequest were not deleted when - calling Stock::delete_calibration_request() (via - ReferencePoint::delete_requests()). - -- Refactoring - ° Split Stock::regenerate_reference_points() into several - functions. - ° Create virtual class OutputSocket to factorise code of - OutputUDPSocket & OutputTCPSocketEvAAL. - ° Synchronise InputCSV & InputUDPSocket (calibration requests), - factorise code into InputMedium. - ° Write a class for Request::type? - CalibrationRequest::direction uses a dedicated class Direction, why - not Request::type? That would simplify writing of the type to - streams (no need to cast each time anymore). - ° Wi-Fi devices' list - . Merge Stock::mobiles & Stock::aps? - . Factorise AccessPointsReaderCSV & MobilesReaderCSV? - ° Members renaming - . InputMedium: - . - current_line_nb & get_current_line_nb() - . - get_next_request() −> read_next_request() - . Input: get_next_request() −> read_next_request() - . Area: p_min et p_max −> coord_min et coord_max - -- User interface - ° Add the area to the result in OutputCSV. - ° When reading the APs, add them to the mobiles' list (or another - way to be able to have a single entry for an AP). - ° Rename minmax-start & stop, since it is used elsewhere (grep - minmax-start). - ° Review the option names & descriptions. - ° Add option positioning.self-calibrate (or autocalibrate), to - activate automatically the options needed by the autocalibration. - ° Improve --verbose (and/or debug level): print the options, etc. - ° Case-insensitive string comparison (for algorithm names, etc.). - ° Use a prefix for configuration files (search for config files set - with relative path in owlps-positioning.cfg in the same directory). - -- Optimisation & code improvement - ° Multithread algorithm calls. - ° ReferencePoint: the request list should be an unordered_set - instead of a vector, to guarantee the unicity of the elements. - -- Unit tests - ° Update tests (currently unmaintained). - ° Unfinished tests: - . InputDataReader - . Input - . Output - . Positioning - ° Test InterlinkNetworks::compute() ? - ° Timestamp: there is a probability of 10^-6 that the value in - nanoseconds and the rounded value in milliseconds are identical, in - which case some tests can fail. - -- Revoir le diagramme UML - ° Associations : devraient êtres représentées par des attributs - pointeurs. - ° Compositions : devraient être représentées par des attributs - normaux. - -- « C++ en action » - ° Espaces de noms ? 109 - ° Réserver l'espace mémoire des vector avec reserve(). 217 - ° Copie de conteneur vers un flux (cas de certains operator<<). 275 - -- « Coder proprement » - ° Revoir toutes les classes pour respecter si possible les - principes exposés dans le chapitre 6 (p. 103) : implanter - systématiquement des accesseurs pour tous les attributs d'une - classe expose l'implantation de la classe et rend ses attributs - publics. La classe Direction (et maintenant Timestamp) tend à - respecter ce principe en utilisant mieux les opérateurs et en ne - proposant pas d'accesseur direct. diff --git a/owlps-positioning/cfg/owlps-positioning.cfg b/owlps-positioning/cfg/owlps-positioning.conf similarity index 87% rename from owlps-positioning/cfg/owlps-positioning.cfg rename to owlps-positioning/cfg/owlps-positioning.conf index 21c3a71..bdeb4a4 100644 --- a/owlps-positioning/cfg/owlps-positioning.cfg +++ b/owlps-positioning/cfg/owlps-positioning.conf @@ -49,13 +49,16 @@ csv-file = /tmp/owlps-positioning.log #algorithm = RADAR #algorithm = FRBHMBasic -# Start and stop coordinates for the MinMax multilateration method. +# Coordinates of the deployment area. +# This is used to delimit the area in which reference points are +# generated (when generate-reference-points is activated), and also +# by the MinMax multilateration method. # Since MinMax is currently the only multilateration method implemented # in OwlPS, you should define these parameters if you use any of the # multilateration-based algorithms (InterlinkNetworks, FBCM, FRBHM). # They are declared as strings (X;Y;Z). Do not quote! -#minmax-start = -2;-2;0 -#minmax-stop = 20;30;6 +#area-start = -2;-2;0 +#area-stop = 20;30;6 # With the RADAR algorithm, for a given positioning request, average # all the calibration requests associated with a reference point before @@ -123,3 +126,16 @@ csv-file = /tmp/owlps-positioning.log #medium = CSV csv-file = /tmp/owlps-positioning.out + +#medium = UDP +# Currently, the host must be an IP address (not a DNS name). +#udp-host = +#udp-port = 9910 + +# Note: you can use only one algorithm when using the TCPEvAAL output. +#medium = TCPEvAAL +# Currently, the host must be an IP address (not a DNS name). +#tcpevaal-host = 127.0.0.1 +#tcpevaal-port = 4444 + +# vim: syntax=cfg diff --git a/owlps-positioning/cfg/topology.csv b/owlps-positioning/cfg/topology.csv index 9eac23f..8abee10 100644 --- a/owlps-positioning/cfg/topology.csv +++ b/owlps-positioning/cfg/topology.csv @@ -5,12 +5,17 @@ # handle it. Since none of them are currently implemented, you # probably can save a lot of time by skipping the topology (and # waypoints) description. +# However, you can describe areas if you want to know when the mobile +# is in a particular location. In that case be sure that the algorithm +# you use will be able to generate positions that match each described +# area (in particular, with RADAR, at least one reference point should +# be present in each area). # # ALSO IMPORTANT (EVEN IF YOU DON'T DESCRIBE THE TOPOLOGY): -# If you use the MinMax multilateration method, you should provide -# minmax-start and minmax-stop parameters that match the deployment -# area. That is, the cuboid formed by these two points should include -# the whole deployment area. +# If you use the MinMax multilateration method, or the autocalibration, +# you must provide area-start and area-stop options that match the +# deployment area. That is, the cuboid formed by these two points +# should include the whole deployment area. # # This file lists the buildings and their "homogeneous areas" (rooms). # diff --git a/owlps-positioning/src/accesspoint.cc b/owlps-positioning/src/accesspoint.cc index 364bcab..e6fb4d0 100644 --- a/owlps-positioning/src/accesspoint.cc +++ b/owlps-positioning/src/accesspoint.cc @@ -5,10 +5,22 @@ using namespace std ; +/* *** Operations *** */ + + +double AccessPoint::friis_constant_term() const +{ + double wavelength = + static_cast(PosUtil::LIGHT_SPEED) / frequency ; + return antenna_gain + 20 * log10(wavelength) - 20 * log10(4 * M_PI) ; +} + + + /* *** Operators *** */ -const AccessPoint& AccessPoint::operator=(const AccessPoint &source) +AccessPoint& AccessPoint::operator=(const AccessPoint &source) { if (this == &source) return *this ; diff --git a/owlps-positioning/src/accesspoint.hh b/owlps-positioning/src/accesspoint.hh index 5919766..d42ea99 100644 --- a/owlps-positioning/src/accesspoint.hh +++ b/owlps-positioning/src/accesspoint.hh @@ -67,9 +67,15 @@ public: void set_friis_index(const float _friis_index) ; //@} + /** @name Operations */ + //@{ + /// Returns the Friis formula's constant term + double friis_constant_term(void) const ; + //@} + /** @name Operators */ //@{ - const AccessPoint& operator=(const AccessPoint &source) ; + AccessPoint& operator=(const AccessPoint &source) ; bool operator==(const AccessPoint &source) const ; bool operator!=(const AccessPoint &source) const ; //@} diff --git a/owlps-positioning/src/area.cc b/owlps-positioning/src/area.cc index ce02aa7..05eb191 100644 --- a/owlps-positioning/src/area.cc +++ b/owlps-positioning/src/area.cc @@ -119,7 +119,7 @@ void Area::reorder_coordinates() /* *** Operators *** */ -const Area& Area::operator=(const Area &source) +Area& Area::operator=(const Area &source) { if (this == &source) return *this ; diff --git a/owlps-positioning/src/area.hh b/owlps-positioning/src/area.hh index 2f15513..8e96d64 100644 --- a/owlps-positioning/src/area.hh +++ b/owlps-positioning/src/area.hh @@ -55,7 +55,7 @@ public: /** @name Operators */ //@{ - const Area& operator=(const Area &source) ; + Area& operator=(const Area &source) ; bool operator==(const Area &source) const ; bool operator!=(const Area &source) const ; //@} diff --git a/owlps-positioning/src/building.cc b/owlps-positioning/src/building.cc index d2b8ec9..5ddcca9 100644 --- a/owlps-positioning/src/building.cc +++ b/owlps-positioning/src/building.cc @@ -73,7 +73,7 @@ void Building::add_area(Area *&area) /* *** Operators *** */ -const Building& Building::operator=(const Building &source) +Building& Building::operator=(const Building &source) { if (this == &source) return *this ; diff --git a/owlps-positioning/src/building.hh b/owlps-positioning/src/building.hh index 63acd16..3c8dbee 100644 --- a/owlps-positioning/src/building.hh +++ b/owlps-positioning/src/building.hh @@ -48,7 +48,7 @@ public : /** @name Operators */ //@{ - const Building& operator=(const Building &source) ; + Building& operator=(const Building &source) ; bool operator==(const Building &source) const ; bool operator!=(const Building &source) const ; //@} diff --git a/owlps-positioning/src/calibrationrequest.cc b/owlps-positioning/src/calibrationrequest.cc index 0a37080..ba7841e 100644 --- a/owlps-positioning/src/calibrationrequest.cc +++ b/owlps-positioning/src/calibrationrequest.cc @@ -54,8 +54,8 @@ void CalibrationRequest::clear() /* *** Operators *** */ -const CalibrationRequest& -CalibrationRequest::operator=(const CalibrationRequest &source) +CalibrationRequest& CalibrationRequest:: +operator=(const CalibrationRequest &source) { if (this == &source) return *this ; @@ -68,7 +68,8 @@ CalibrationRequest::operator=(const CalibrationRequest &source) } -bool CalibrationRequest::operator==(const CalibrationRequest &source) const +bool CalibrationRequest:: +operator==(const CalibrationRequest &source) const { if (this == &source) return true ; diff --git a/owlps-positioning/src/calibrationrequest.hh b/owlps-positioning/src/calibrationrequest.hh index 0f0147f..a8bfd34 100644 --- a/owlps-positioning/src/calibrationrequest.hh +++ b/owlps-positioning/src/calibrationrequest.hh @@ -48,7 +48,7 @@ public: /** @name Operators */ //@{ - const CalibrationRequest& operator=(const CalibrationRequest &source) ; + CalibrationRequest& operator=(const CalibrationRequest &source) ; bool operator==(const CalibrationRequest &source) const ; bool operator!=(const CalibrationRequest &source) const ; //@} diff --git a/owlps-positioning/src/direction.cc b/owlps-positioning/src/direction.cc index 8d4da53..7c1915f 100644 --- a/owlps-positioning/src/direction.cc +++ b/owlps-positioning/src/direction.cc @@ -36,14 +36,14 @@ inline bool Direction::is_valid() const /* *** Operators *** */ -const Direction& Direction::operator=(const Direction &source) +Direction& Direction::operator=(const Direction &source) { direction = source.direction ; return *this ; } -const Direction& Direction::operator=(const char source) +Direction& Direction::operator=(const char source) { direction = source ; assert_valid() ; diff --git a/owlps-positioning/src/direction.hh b/owlps-positioning/src/direction.hh index 0cecb17..e9e9e80 100644 --- a/owlps-positioning/src/direction.hh +++ b/owlps-positioning/src/direction.hh @@ -27,8 +27,8 @@ public: /** @name Operators */ //@{ - const Direction& operator=(const Direction &source) ; - const Direction& operator=(const char source) ; + Direction& operator=(const Direction &source) ; + Direction& operator=(const char source) ; bool operator==(const Direction &source) const ; bool operator!=(const Direction &source) const ; operator bool(void) const ; diff --git a/owlps-positioning/src/fbcm.cc b/owlps-positioning/src/fbcm.cc index 0eed6fb..10347ef 100644 --- a/owlps-positioning/src/fbcm.cc +++ b/owlps-positioning/src/fbcm.cc @@ -1,7 +1,19 @@ #include "fbcm.hh" +#include "stock.hh" +#include "configuration.hh" +Result FBCM::compute(const Request &_request) +{ + // If the autocalibration is activated, we have to regenerate the + // Friis indexes each time we calculate a position + if (Configuration::bool_value("positioning.generate-reference-points")) + Stock::update_all_friis_indexes() ; + return MultilaterationAlgorithm::compute(_request) ; +} + + float FBCM::estimate_distance(const Measurement &measurement) { double constant_term = make_constant_term(measurement) ; diff --git a/owlps-positioning/src/fbcm.hh b/owlps-positioning/src/fbcm.hh index a1f8421..b210be9 100644 --- a/owlps-positioning/src/fbcm.hh +++ b/owlps-positioning/src/fbcm.hh @@ -13,7 +13,11 @@ public: FBCM(void): PositioningAlgorithm("FBCM") {} ~FBCM(void) {} + /** @name Operations */ + //@{ + Result compute(const Request &_request) ; float estimate_distance(const Measurement &measurement) ; + //@} } ; #endif // _OWLPS_POSITIONING_FBCM_HH_ diff --git a/owlps-positioning/src/inputcsv.cc b/owlps-positioning/src/inputcsv.cc index c4e8d8a..b3f72b9 100644 --- a/owlps-positioning/src/inputcsv.cc +++ b/owlps-positioning/src/inputcsv.cc @@ -17,24 +17,18 @@ using std::tr1::unordered_map ; /** - * This function reads the next Request in the CSV input file. Blank - * lines and lines containing only spaces are skipped. + * This function fills the current Request from the CSV input file. + * Blank lines and lines containing only spaces are skipped until a line + * containing a request is found. * - * #file should be opened before proceeding requests; otherwise, - * #current_request is \link Request::clear() cleared\endlink and a - * blank Request is returned. The file must be valid, - * semicolon-separated (\em not comma-separated). - * - * @return The read Request, or a blank Request in case of error (file - * not opened, end of file, invalid field or wrong number of fields in - * the line). + * @returns \em true if #current_request was correctly filled. + * @returns \em false in case of error (file not opened, end of file, + * invalid field or wrong number of fields in the line). */ -const Request& InputCSV::get_next_request() +bool InputCSV::fill_current_request() { - clear_current_request() ; - if (! file.next_line()) // End of file or error - return *current_request ; + return false ; ++current_line_nb ; // Read Mobile MAC field @@ -43,13 +37,13 @@ const Request& InputCSV::get_next_request() { if (Configuration::is_configured("verbose")) cerr << "InputCSV: cannot read mac_mobile.\n" ; - return *current_request ; + return false ; } PosUtil::to_upper(mac_mobile) ; if (! Configuration::bool_value("positioning.accept-new-mobiles") && ! Stock::mobile_exists(mac_mobile)) - return *current_request ; + return false ; const Mobile &mobile = Stock::find_create_mobile(mac_mobile) ; current_request->set_mobile(&mobile) ; @@ -59,11 +53,10 @@ const Request& InputCSV::get_next_request() uint16_t type_r ; if (! file.read_field(type_r)) { - // Wrong number of fields: blank current request - current_request->clear() ; + // Wrong number of fields if (Configuration::is_configured("verbose")) cerr << "InputCSV: cannot read type.\n" ; - return *current_request ; + return false ; } type = type_r ; current_request->set_type(type) ; @@ -72,11 +65,10 @@ const Request& InputCSV::get_next_request() Timestamp timestamp ; if (! file.read_timestamp(timestamp)) { - // Wrong number of fields: blank current request - current_request->clear() ; + // Wrong number of fields if (Configuration::is_configured("verbose")) cerr << "InputCSV: cannot read timestamp.\n" ; - return *current_request ; + return false ; } current_request->set_time_sent(timestamp) ; @@ -84,11 +76,10 @@ const Request& InputCSV::get_next_request() Point3D position ; if (! file.read_point3d(position)) { - // Wrong number of fields: blank current request - current_request->clear() ; + // Wrong number of fields if (Configuration::is_configured("verbose")) cerr << "InputCSV: cannot read coordinates.\n" ; - return *current_request ; + return false ; } // Read direction field @@ -96,11 +87,10 @@ const Request& InputCSV::get_next_request() int direction_int ; if (! file.read_field(direction_int)) { - // Wrong number of fields: blank current request - current_request->clear() ; + // Wrong number of fields if (Configuration::is_configured("verbose")) cerr << "InputCSV: cannot read direction.\n" ; - return *current_request ; + return false ; } if (direction_int != 0) direction = direction_int ; @@ -114,11 +104,10 @@ const Request& InputCSV::get_next_request() int ss ; if (! file.read_field(ss)) { - // Wrong number of fields: blank current request - current_request->clear() ; + // Wrong number of fields if (Configuration::is_configured("verbose")) cerr << "InputCSV: cannot read mac_ap.\n" ; - return *current_request ; + return false ; } PosUtil::to_upper(mac_ap) ; @@ -131,26 +120,11 @@ const Request& InputCSV::get_next_request() measurements[mac_ap].add_ss(ss) ; } if (measurements.empty()) - { - current_request->clear() ; - return *current_request ; - } + return false ; current_request->set_measurements(measurements) ; // Calibration request? - if (type == OWL_REQUEST_CALIBRATION || - type == OWL_REQUEST_AUTOCALIBRATION) - { - const ReferencePoint &reference_point = - Stock::find_create_reference_point(position) ; - current_request_to_calibration_request(&reference_point, - direction, type) ; - } + fill_calibration_request_data(mac_mobile, position, direction, type) ; - // We set the real coordinates (if found) only for non-calibration - // requests - else if (position) - current_request->set_real_position(position) ; - - return *current_request ; + return true ; } diff --git a/owlps-positioning/src/inputcsv.hh b/owlps-positioning/src/inputcsv.hh index 9310f51..de75abe 100644 --- a/owlps-positioning/src/inputcsv.hh +++ b/owlps-positioning/src/inputcsv.hh @@ -16,6 +16,12 @@ class InputCSV: public InputMedium protected: CSVFileReader file ; + /** @name Operations */ + //@{ + /// Reads data & fills the current request + bool fill_current_request(void) ; + //@} + public: InputCSV(const std::string &filename): file(filename) {} @@ -28,12 +34,6 @@ public: bool eof(void) const ; //@} - /** @name Operations */ - //@{ - /// Reads the next request - const Request& get_next_request(void) ; - //@} - /** @name Operators */ //@{ operator bool(void) const ; diff --git a/owlps-positioning/src/inputmedium.cc b/owlps-positioning/src/inputmedium.cc index e424633..9e38286 100644 --- a/owlps-positioning/src/inputmedium.cc +++ b/owlps-positioning/src/inputmedium.cc @@ -1,5 +1,10 @@ #include "inputmedium.hh" #include "calibrationrequest.hh" +#include "stock.hh" +#include "configuration.hh" +#include "posexcept.hh" + +using namespace std ; @@ -23,6 +28,116 @@ InputMedium::~InputMedium() /* *** Operations *** */ +/** + * Reads a Request, increments current_line_nb, updates #current_request + * and returns it. + * + * The input medium should be ready to be read before precessing + * requests; otherwise, #current_request is \link Request::clear() + * cleared\endlink and a blank Request is returned. + * + * @return The Request read, or an empty Request in case of error or + * EOF (note that when casted in bool, an empty Request is \em false, + * see Request::operator bool()). + */ +const Request& InputMedium::get_next_request() +{ + clear_current_request() ; + + if (! fill_current_request()) + { + clear_current_request() ; + return *current_request ; + } + + return *current_request ; +} + + +void InputMedium::clear_current_request() +{ + if (dynamic_cast(current_request) == NULL) + current_request->clear() ; + else + { + delete current_request ; + current_request = NULL ; + current_request = new Request() ; + } +} + + +/** + * The \em position argument can be changed by this function. + */ +void InputMedium:: +fill_calibration_request_data(const string &mac_mobile, Point3D &position, + const Direction &direction, uint8_t type) +{ + // We set the real coordinates (if found) for non-calibration requests + if (type != OWL_REQUEST_CALIBRATION && + type != OWL_REQUEST_AUTOCALIBRATION) + { + if (position) + current_request->set_real_position(position) ; + return ; + } + + if (position) + { + // Update the AP's coordinates if allowed (and if the mobile is + // an AP, of course) + if (Configuration:: + bool_value("positioning.update-ap-coordinates-online")) + { + if (type == OWL_REQUEST_AUTOCALIBRATION && + Configuration::bool_value("positioning.accept-new-aps")) + { + AccessPoint &transmitter = + const_cast( + Stock::find_create_ap(mac_mobile)) ; + transmitter.set_coordinates(position) ; + } + else + { + try + { + AccessPoint &transmitter = + const_cast(Stock::get_ap(mac_mobile)) ; + transmitter.set_coordinates(position) ; + } + catch (element_not_found &e) + { + // The mobile is not an AP or the AP does not exist + } + } + } + } + + else if (type == OWL_REQUEST_AUTOCALIBRATION) + { + // If an autocalibration request does not contain the coordinates + // of the AP, we use the current coordinates of the AP as + // ReferencePoint. + try + { + AccessPoint &transmitter = + const_cast(Stock::get_ap(mac_mobile)) ; + position = transmitter.get_coordinates() ; + } + catch (element_not_found &e) + { + // The mobile is not an AP or the AP does not exist + } + } + + const ReferencePoint &reference_point = + Stock::find_create_reference_point(position) ; + current_request_to_calibration_request( + &reference_point, direction, type) ; +} + + void InputMedium:: current_request_to_calibration_request( const ReferencePoint *const reference_point, @@ -47,16 +162,3 @@ current_request_to_calibration_request( direction, request_type) ; delete tmp ; } - - -void InputMedium::clear_current_request() -{ - if (dynamic_cast(current_request) == NULL) - current_request->clear() ; - else - { - delete current_request ; - current_request = NULL ; - current_request = new Request() ; - } -} diff --git a/owlps-positioning/src/inputmedium.hh b/owlps-positioning/src/inputmedium.hh index 93f11b6..d2e5283 100644 --- a/owlps-positioning/src/inputmedium.hh +++ b/owlps-positioning/src/inputmedium.hh @@ -6,6 +6,8 @@ class Direction ; #include "request.hh" +#include + /// Super class of all input media /** * This class Provides an interface for input media, i.e. to read @@ -18,6 +20,18 @@ protected: /// Number of the current line proceeded unsigned long current_line_nb ; + /** @name Operations */ + //@{ + /// Reads data & fills the current request + virtual bool fill_current_request(void) = 0 ; + /// \brief Checks if the current request is a calibration request and + /// if so fills it with additionnal data + void fill_calibration_request_data(const std::string &mac_mobile, + Point3D &position, + const Direction &direction, + uint8_t type) ; + //@} + public: InputMedium(void) ; @@ -43,14 +57,7 @@ public: //@{ /// Reads the next request - /** - * Reads a Request, increments current_line_nb, updates #current_request - * and returns it. - * @return The Request read, or an empty Request in case of error or - * EOF (note that when casted in bool, an empty Request is \em false, - * see Request::operator bool()). - */ - virtual const Request& get_next_request(void) = 0 ; + const Request& get_next_request(void) ; /// Converts #current_request into a CalibrationRequest void current_request_to_calibration_request( diff --git a/owlps-positioning/src/inputudpsocket.cc b/owlps-positioning/src/inputudpsocket.cc index dafe816..12e288d 100644 --- a/owlps-positioning/src/inputudpsocket.cc +++ b/owlps-positioning/src/inputudpsocket.cc @@ -72,22 +72,16 @@ bool InputUDPSocket::close_socket() /** - * This function reads the next Request in the UDP input socket. - * It cannot read calibration requests. + * This function fills the current Request from the UDP input socket. * - * #sockfd should be opened before processing requests; otherwise, - * #current_request is \link Request::clear() cleared\endlink and a - * blank Request is returned. - * - * @return The read Request, or a blank Request in case of error (socket - * not opened, bad packet format). + * @returns \em true if #current_request was correctly filled. + * @returns \em false in case of error (socket not opened, bad packet + * format). */ -const Request& InputUDPSocket::get_next_request() +bool InputUDPSocket::fill_current_request() { - clear_current_request() ; - if (eof()) - return *current_request ; + return false ; struct sockaddr_in client; // UDP client structure socklen_t client_len = sizeof(client) ; // Size of clients @@ -98,8 +92,8 @@ const Request& InputUDPSocket::get_next_request() (struct sockaddr *) &client, &client_len) ; if (nread <= 0) { - cerr << "No request received!" << endl ; - return *current_request ; + cerr << "InputUDPSocket: No request received!" << endl ; + return false ; } // Endianess conversions @@ -113,7 +107,7 @@ const Request& InputUDPSocket::get_next_request() if (! Configuration::bool_value("positioning.accept-new-mobiles") && ! Stock::mobile_exists(mac_mobile)) - return *current_request ; + return false ; const Mobile &mobile = Stock::find_create_mobile(mac_mobile) ; current_request->set_mobile(&mobile) ; @@ -139,8 +133,7 @@ const Request& InputUDPSocket::get_next_request() if (nread <= 0) { cerr << "No request info received!" << endl ; - current_request->clear() ; - return *current_request ; + return false ; } string mac_ap( owl_mac_bytes_to_string(request_info.ap_mac_addr_bytes)) ; @@ -156,47 +149,12 @@ const Request& InputUDPSocket::get_next_request() (request_info.antenna_signal_dbm)) ; } if (measurements.empty()) - { - current_request->clear() ; - return *current_request ; - } + return false ; current_request->set_measurements(measurements) ; // Calibration request? - if ((request.type == OWL_REQUEST_CALIBRATION || - request.type == OWL_REQUEST_AUTOCALIBRATION) - && - (Configuration::bool_value("positioning.accept-new-aps") || - Stock::ap_exists(mac_mobile))) - { - AccessPoint &transmitter = - const_cast(Stock::find_create_ap(mac_mobile)) ; + fill_calibration_request_data( + mac_mobile, position, request.direction, request.type) ; - // If an autocalibration request does not contain the coordinates - // of the AP, we use the current coordinates of the AP as - // ReferencePoint. - if (request.type == OWL_REQUEST_AUTOCALIBRATION && ! position) - position = transmitter.get_coordinates() ; - - // Update the AP's coordinates if allowed. A 'false' position - // (i.e. 0;0;0) is only set for calibration requests, to avoid - // setting the coordinates to 0;0;0 if an autocalibration - // request that does not contain the coordinates is received. - else if (Configuration:: - bool_value("positioning.update-ap-coordinates-online")) - transmitter.set_coordinates(position) ; - - const ReferencePoint &reference_point = - Stock::find_create_reference_point(position) ; - current_request_to_calibration_request(&reference_point, - Direction(request.direction), - request.type) ; - } - - // We set the real coordinates (if found) only for non-calibration - // requests - else if (position) - current_request->set_real_position(position) ; - - return *current_request ; + return true ; } diff --git a/owlps-positioning/src/inputudpsocket.hh b/owlps-positioning/src/inputudpsocket.hh index eff21f0..a3a6450 100644 --- a/owlps-positioning/src/inputudpsocket.hh +++ b/owlps-positioning/src/inputudpsocket.hh @@ -14,6 +14,15 @@ protected: //@{ /// Initialises the socket bool init_socket(void) ; + /// Reads data & fills the current request + /** + * This function fills the current Request from the data read from + * the input medium. + * + * @returns \em true if #current_request was correctly filled. + * @returns \em false in case of error. + */ + bool fill_current_request(void) ; //@} public: @@ -29,8 +38,6 @@ public: /** @name Operations */ //@{ - /// Reads the next request - const Request& get_next_request(void) ; /// Closes the socket bool close_socket(void) ; //@} diff --git a/owlps-positioning/src/measurement.cc b/owlps-positioning/src/measurement.cc index 75e912e..73a4354 100644 --- a/owlps-positioning/src/measurement.cc +++ b/owlps-positioning/src/measurement.cc @@ -124,7 +124,7 @@ void Measurement::update_average_ss() /* *** Operators *** */ -const Measurement& Measurement::operator=(const Measurement &m) +Measurement& Measurement::operator=(const Measurement &m) { if (this == &m) return *this ; diff --git a/owlps-positioning/src/measurement.hh b/owlps-positioning/src/measurement.hh index 3b28d5b..9f2b82d 100644 --- a/owlps-positioning/src/measurement.hh +++ b/owlps-positioning/src/measurement.hh @@ -68,7 +68,7 @@ public: /** @name Operators */ //@{ - const Measurement& operator=(const Measurement &m) ; + Measurement& operator=(const Measurement &m) ; bool operator==(const Measurement &m) const ; bool operator!=(const Measurement &m) const ; operator bool(void) const ; diff --git a/owlps-positioning/src/mobile.cc b/owlps-positioning/src/mobile.cc index 075f11f..3f4e235 100644 --- a/owlps-positioning/src/mobile.cc +++ b/owlps-positioning/src/mobile.cc @@ -5,7 +5,7 @@ /* *** Operators *** */ -const Mobile& Mobile::operator=(const Mobile &m) +Mobile& Mobile::operator=(const Mobile &m) { if (this == &m) return *this ; diff --git a/owlps-positioning/src/mobile.hh b/owlps-positioning/src/mobile.hh index b235a4d..11f8f8a 100644 --- a/owlps-positioning/src/mobile.hh +++ b/owlps-positioning/src/mobile.hh @@ -28,7 +28,7 @@ public: /** @name Operators */ //@{ - const Mobile& operator=(const Mobile &m) ; + Mobile& operator=(const Mobile &m) ; bool operator==(const Mobile &m) const ; bool operator!=(const Mobile &m) const ; //@} diff --git a/owlps-positioning/src/multilaterationalgorithm.cc b/owlps-positioning/src/multilaterationalgorithm.cc index f3f8b57..ca3cd3b 100644 --- a/owlps-positioning/src/multilaterationalgorithm.cc +++ b/owlps-positioning/src/multilaterationalgorithm.cc @@ -18,16 +18,16 @@ MultilaterationAlgorithm::MultilaterationAlgorithm(): // Will be changed when other multilateration methods will be // implemented. - if (! Configuration::is_configured("positioning.minmax-start") || - ! Configuration::is_configured("positioning.minmax-stop")) + if (! Configuration::is_configured("positioning.area-start") || + ! Configuration::is_configured("positioning.area-stop")) throw missing_configuration( - "You want to use MinMax, but either positioning.minmax-start or" - " positioning.minmax-stop is not defined!") ; + "You want to use MinMax, but either positioning.area-start or" + " positioning.area-stop is not defined!") ; Point3D minmax_start( - Configuration::string_value("positioning.minmax-start")) ; + Configuration::string_value("positioning.area-start")) ; Point3D minmax_stop( - Configuration::string_value("positioning.minmax-stop")) ; + Configuration::string_value("positioning.area-stop")) ; multilateration_method = new MinMax(minmax_start, minmax_stop) ; } @@ -47,19 +47,15 @@ double MultilaterationAlgorithm:: make_constant_term(const Measurement &measurement) { assert(request) ; - assert(request->get_mobile()) ; + const Mobile *mobile = request->get_mobile() ; + assert(mobile) ; const AccessPoint *ap = measurement.get_ap() ; assert(ap) ; return - ap->get_trx_power() + - ap->get_antenna_gain() + - 20 * log10( - static_cast(PosUtil::LIGHT_SPEED) / - ap->get_frequency() / - (4 * M_PI) - ) + - request->get_mobile()->get_antenna_gain() ; + ap->friis_constant_term() + + mobile->get_antenna_gain() + + mobile->get_trx_power() ; } diff --git a/owlps-positioning/src/outputcsv.hh b/owlps-positioning/src/outputcsv.hh index 4588377..056aa12 100644 --- a/owlps-positioning/src/outputcsv.hh +++ b/owlps-positioning/src/outputcsv.hh @@ -6,8 +6,7 @@ /// Writes results to a CSV file /** - * CSV format is: - * Mobile_MAC;Timestamp;Algorithm1;X;Y;Z;…;AlgorithmN;X;Y;Z + * The CSV format is documented in ResultList::to_csv(). */ class OutputCSV: public OutputMedium { diff --git a/owlps-positioning/src/outputnetworksocket.cc b/owlps-positioning/src/outputnetworksocket.cc new file mode 100644 index 0000000..3243d71 --- /dev/null +++ b/owlps-positioning/src/outputnetworksocket.cc @@ -0,0 +1,60 @@ +#include "outputnetworksocket.hh" +#include "resultlist.hh" +#include "result.hh" +#include "posexcept.hh" + +#include // For perror() + +using namespace std ; + + + +/* *** Constructors *** */ + + +OutputNetworkSocket::~OutputNetworkSocket() +{ + close_socket() ; +} + + + +/* *** Operations *** */ + + +/** + * Normally, the socket is closed automatically by the destructor. Use + * this if you want to close the socket prematurely. + * #sockfd is set to -1, even in case of error. + * @return \em true if the socket were successfully closed or were not + * opened. + * @return \em false in case of error. + */ +bool OutputNetworkSocket::close_socket() +{ + if (sockfd >= 0) + { + if (close(sockfd)) + { + perror("Cannot close network socket") ; + return false ; + } + + sockfd = -1 ; + } + + return true ; +} + + +void OutputNetworkSocket::write(const Result &result) +{ + send_data(result.to_csv()) ; +} + + +void OutputNetworkSocket::write(const ResultList &results) +{ + if (! results.empty()) + send_data(results.to_csv()) ; +} diff --git a/owlps-positioning/src/outputnetworksocket.hh b/owlps-positioning/src/outputnetworksocket.hh new file mode 100644 index 0000000..8c363dc --- /dev/null +++ b/owlps-positioning/src/outputnetworksocket.hh @@ -0,0 +1,50 @@ +#ifndef _OWLPS_POSITIONING_OUTPUTNETWORKSOCKET_HH_ +#define _OWLPS_POSITIONING_OUTPUTNETWORKSOCKET_HH_ + +#include "outputmedium.hh" + +#include +#include // is not C++ 98 compliant +#include + +/// Parent class for all output media that use network sockets +class OutputNetworkSocket: public OutputMedium +{ +protected: + int sockfd ; + std::string remote_host ; + uint_fast16_t remote_port ; + + struct sockaddr_in server_info ; + struct sockaddr_in client_info ; + + /** @name Operations */ + //@{ + /// Initialises the socket + /** + * You are required to call this function from the constructor of any + * derived class. + */ + virtual bool init_socket(void) = 0 ; + /// Sends a string through the socket + virtual bool send_data(const std::string &data) const = 0 ; + //@} + +public: + OutputNetworkSocket(const std::string &_remote_host, + const uint_fast16_t _remote_port): + sockfd(-1), remote_host(_remote_host), remote_port(_remote_port) {} + ~OutputNetworkSocket(void) ; + + /** @name Operations */ + //@{ + /// Sends a list of results through the socket + void write(const ResultList &results) ; + /// Sends a single result through the socket + void write(const Result &result) ; + /// Closes the socket + bool close_socket(void) ; + //@} +} ; + +#endif // _OWLPS_POSITIONING_OUTPUTNETWORKSOCKET_HH_ diff --git a/owlps-positioning/src/outputtcpsocketevaal.cc b/owlps-positioning/src/outputtcpsocketevaal.cc index 11fa53e..68b0d24 100644 --- a/owlps-positioning/src/outputtcpsocketevaal.cc +++ b/owlps-positioning/src/outputtcpsocketevaal.cc @@ -17,19 +17,13 @@ using namespace std ; /* *** Constructors *** */ -OutputTCPSocketEvAAL::OutputTCPSocketEvAAL( - const string &_remote_host, - const uint_fast16_t _remote_port): - remote_host(_remote_host), remote_port(_remote_port) +OutputTCPSocketEvAAL:: +OutputTCPSocketEvAAL(const string &_remote_host, + const uint_fast16_t _remote_port): + OutputNetworkSocket(_remote_host, _remote_port) { if (! init_socket()) - throw error_opening_output_file("TCP socket") ; -} - - -OutputTCPSocketEvAAL::~OutputTCPSocketEvAAL() -{ - close_socket() ; + throw error_opening_output_file("TCP socket (EvAAL)") ; } @@ -70,31 +64,6 @@ bool OutputTCPSocketEvAAL::init_socket() } -/** - * Normally, the socket is closed automatically by the destructor. Use - * this if you want to close the socket prematurely. - * #sockfd is set to -1, even in case of error. - * @return \em true if the socket were successfully closed or were not - * opened. - * @return \em false in case of error. - */ -bool OutputTCPSocketEvAAL::close_socket() -{ - if (sockfd >= 0) - { - if (close(sockfd)) - { - perror("Cannot close TCP socket") ; - return false ; - } - - sockfd = -1 ; - } - - return true ; -} - - /** * @param results Must contain only one element, since the EvAAL format * accepts only one algorithm result. @@ -128,7 +97,7 @@ void OutputTCPSocketEvAAL::write(const Result &result) int OutputTCPSocketEvAAL:: area_of_interest_number(const Point3D &position) const { - const Area *area = Stock::in_which_area_is(position) ; + const Area *const area = Stock::in_which_area_is(position) ; if (area == NULL) return 0 ; @@ -157,7 +126,7 @@ bool OutputTCPSocketEvAAL::send_data(const string &data) const ssize_t nsent = send(sockfd, data.c_str(), data.size(), 0) ; if (nsent != static_cast(data.size())) { - perror("Error sending result data") ; + perror("Error sending result data through the TCPEvAAL socket") ; return false ; } return true ; diff --git a/owlps-positioning/src/outputtcpsocketevaal.hh b/owlps-positioning/src/outputtcpsocketevaal.hh index 281b71a..cf8c30e 100644 --- a/owlps-positioning/src/outputtcpsocketevaal.hh +++ b/owlps-positioning/src/outputtcpsocketevaal.hh @@ -3,27 +3,16 @@ class Point3D ; -#include "outputmedium.hh" - -#include -#include // is not C++ 98 compliant -#include +#include "outputnetworksocket.hh" /// Sends results to a remote host by TCP (EvAAL competition format) /** * The results are sent through an TCP socket as a string value, * conforming to the EvAAL competition format. */ -class OutputTCPSocketEvAAL: public OutputMedium +class OutputTCPSocketEvAAL: public OutputNetworkSocket { protected: - int sockfd ; - std::string remote_host ; - uint_fast16_t remote_port ; - - struct sockaddr_in server_info ; - struct sockaddr_in client_info ; - /** @name Operations */ //@{ /// Initialises the socket @@ -37,16 +26,15 @@ protected: public: OutputTCPSocketEvAAL(const std::string &_remote_host, const uint_fast16_t _remote_port) ; - ~OutputTCPSocketEvAAL(void) ; /** @name Operations */ //@{ + /// Sends a list of results through the socket void write(const ResultList &results) ; + /// Sends a single result through the socket void write(const Result &result) ; /// Get the area of interest number from the position int area_of_interest_number(const Point3D &position) const ; - /// Closes the socket - bool close_socket(void) ; //@} } ; diff --git a/owlps-positioning/src/outputudpsocket.cc b/owlps-positioning/src/outputudpsocket.cc index 4e4bc02..ebc8350 100644 --- a/owlps-positioning/src/outputudpsocket.cc +++ b/owlps-positioning/src/outputudpsocket.cc @@ -1,11 +1,11 @@ #include "outputudpsocket.hh" #include "request.hh" #include "resultlist.hh" +#include "result.hh" #include "posexcept.hh" #include -#include #include // For perror() using namespace std ; @@ -17,17 +17,10 @@ using namespace std ; OutputUDPSocket::OutputUDPSocket(const string &_remote_host, const uint_fast16_t _remote_port): - remote_host(_remote_host), remote_port(_remote_port) + OutputNetworkSocket(_remote_host, _remote_port) { if (! init_socket()) throw error_opening_output_file("UDP socket") ; - -} - - -OutputUDPSocket::~OutputUDPSocket() -{ - close_socket() ; } @@ -47,52 +40,18 @@ bool OutputUDPSocket::init_socket() } -/** - * Normally, the socket is closed automatically by the destructor. Use - * this if you want to close the socket prematurely. - * #sockfd is set to -1, even in case of error. - * @return \em true if the socket were successfully closed or were not - * opened. - * @return \em false in case of error. - */ -bool OutputUDPSocket::close_socket() -{ - if (sockfd >= 0) - { - if (close(sockfd)) - { - perror("Cannot close UDP socket") ; - return false ; - } - - sockfd = -1 ; - } - - return true ; -} - - -void OutputUDPSocket::write(const Result &result) -{ - send_data(result.to_csv()) ; -} - - -void OutputUDPSocket::write(const ResultList &results) -{ - if (! results.empty()) - send_data(results.to_csv()) ; -} - - /** * Sends the text buffer 'data'. */ -void OutputUDPSocket::send_data(const string &data) +bool OutputUDPSocket::send_data(const string &data) const { ssize_t nsent = sendto(sockfd, data.c_str(), data.size(), 0, (struct sockaddr *) &server_info, sizeof(server_info)) ; if (nsent != static_cast(data.size())) - perror("Error sending result data") ; + { + perror("Error sending result data through the UDP socket") ; + return false ; + } + return true ; } diff --git a/owlps-positioning/src/outputudpsocket.hh b/owlps-positioning/src/outputudpsocket.hh index 2e8b681..9ab40ad 100644 --- a/owlps-positioning/src/outputudpsocket.hh +++ b/owlps-positioning/src/outputudpsocket.hh @@ -1,46 +1,28 @@ #ifndef _OWLPS_POSITIONING_OUTPUTUDPSOCKET_HH_ #define _OWLPS_POSITIONING_OUTPUTUDPSOCKET_HH_ -#include "outputmedium.hh" - -#include -#include // is not C++ 98 compliant -#include +#include "outputnetworksocket.hh" /// Sends results to a remote host by UDP /** - * The results are sent through an UDP socket as a CSV string value. The - * format used is the same as in OutputCSV. + * The results are sent through an UDP socket as a CSV string value. + * The format used is the same as in OutputCSV, and is documented in + * ResultList::to_csv(). */ -class OutputUDPSocket: public OutputMedium +class OutputUDPSocket: public OutputNetworkSocket { protected: - int sockfd ; - std::string remote_host ; - uint_fast16_t remote_port ; - - struct sockaddr_in server_info ; - struct sockaddr_in client_info ; - /** @name Operations */ //@{ /// Initialises the socket bool init_socket(void) ; - void send_data(const std::string &data) ; + /// Sends a string through the socket + bool send_data(const std::string &data) const ; //@} public: - OutputUDPSocket(const std::string &_remote_ip, - const uint_fast16_t _port) ; - ~OutputUDPSocket(void) ; - - /** @name Operations */ - //@{ - void write(const Result &result) ; - void write(const ResultList &results) ; - /// Closes the socket - bool close_socket(void) ; - //@} + OutputUDPSocket(const std::string &_remote_host, + const uint_fast16_t _remote_port) ; } ; diff --git a/owlps-positioning/src/point3d.cc b/owlps-positioning/src/point3d.cc index 10c7652..045725d 100644 --- a/owlps-positioning/src/point3d.cc +++ b/owlps-positioning/src/point3d.cc @@ -93,7 +93,7 @@ double Point3D::angle(const Point3D &b, const Point3D &c) const /* *** Operators *** */ -const Point3D& Point3D::operator=(const Point3D &source) +Point3D& Point3D::operator=(const Point3D &source) { if (this == &source) return *this ; diff --git a/owlps-positioning/src/point3d.hh b/owlps-positioning/src/point3d.hh index 54c536d..45ba518 100644 --- a/owlps-positioning/src/point3d.hh +++ b/owlps-positioning/src/point3d.hh @@ -67,7 +67,7 @@ public: /** @name Operators */ //@{ - const Point3D& operator=(const Point3D &source) ; + Point3D& operator=(const Point3D &source) ; bool operator==(const Point3D &source) const ; bool operator!=(const Point3D &source) const ; bool operator<(const Point3D &source) const ; diff --git a/owlps-positioning/src/positioning.cc b/owlps-positioning/src/positioning.cc index e494fd0..f717a4c 100644 --- a/owlps-positioning/src/positioning.cc +++ b/owlps-positioning/src/positioning.cc @@ -61,7 +61,12 @@ void Positioning::initialise_algorithms() else if (*i == "FBCM") { - Stock::update_all_friis_indexes() ; + // Generate the Friis indexes only if the autocalibration is + // not activated (if it is, Friis indexes will be regenerated + // each time FBCM wants to computes a position) + if (! Configuration:: + bool_value("positioning.generate-reference-points")) + Stock::update_all_friis_indexes() ; algorithms.push_back(new FBCM) ; } diff --git a/owlps-positioning/src/referencepoint.cc b/owlps-positioning/src/referencepoint.cc index 37abd58..ffd1cd5 100644 --- a/owlps-positioning/src/referencepoint.cc +++ b/owlps-positioning/src/referencepoint.cc @@ -204,13 +204,7 @@ float ReferencePoint:: friis_index_for_ap(const string &ap_mac) const { const AccessPoint &ap = Stock::get_ap(ap_mac) ; - - double ap_freq = ap.get_frequency() ; - double const_term = - ap.get_antenna_gain() - - 20 * log10(4 * M_PI) - + 20 * log10(PosUtil::LIGHT_SPEED / ap_freq) - + ap.get_trx_power() ; + double const_term = ap.friis_constant_term() ; int nb_friis_idx = 0 ; double friis_idx_sum = @@ -258,8 +252,10 @@ float ReferencePoint::friis_indexes_for_ap( assert((*request)->get_mobile()) ; float mobile_gain = (*request)->get_mobile()->get_antenna_gain() ; + float mobile_pow = + (*request)->get_mobile()->get_trx_power() ; friis_idx_sum += - (const_term + mobile_gain - ss) + (const_term + mobile_gain + mobile_pow - ss) / (10 * log10(distance)) ; ++nb_indexes ; } @@ -272,8 +268,7 @@ float ReferencePoint::friis_indexes_for_ap( /* *** Operators *** */ -const ReferencePoint& ReferencePoint:: -operator=(const ReferencePoint &source) +ReferencePoint& ReferencePoint::operator=(const ReferencePoint &source) { if (this == &source) return *this ; diff --git a/owlps-positioning/src/referencepoint.hh b/owlps-positioning/src/referencepoint.hh index 71ee8dd..d0546be 100644 --- a/owlps-positioning/src/referencepoint.hh +++ b/owlps-positioning/src/referencepoint.hh @@ -75,7 +75,7 @@ public: /** @name Operators */ //@{ - const ReferencePoint& operator=(const ReferencePoint &source) ; + ReferencePoint& operator=(const ReferencePoint &source) ; bool operator==(const ReferencePoint &source) const ; bool operator!=(const ReferencePoint &source) const ; //@} diff --git a/owlps-positioning/src/request.cc b/owlps-positioning/src/request.cc index ccffeb0..6b2be2c 100644 --- a/owlps-positioning/src/request.cc +++ b/owlps-positioning/src/request.cc @@ -79,7 +79,7 @@ float Request::ss_square_distance(const Request &source) const /* *** Operators *** */ -const Request& Request::operator=(const Request &source) +Request& Request::operator=(const Request &source) { if (this == &source) return *this ; diff --git a/owlps-positioning/src/request.hh b/owlps-positioning/src/request.hh index ac04aef..f834081 100644 --- a/owlps-positioning/src/request.hh +++ b/owlps-positioning/src/request.hh @@ -94,7 +94,7 @@ public: /** @name Operators */ //@{ - const Request& operator=(const Request &source) ; + Request& operator=(const Request &source) ; bool operator==(const Request &comp) const ; bool operator!=(const Request &comp) const ; operator bool(void) const ; diff --git a/owlps-positioning/src/result.cc b/owlps-positioning/src/result.cc index 8a74ec4..003e517 100644 --- a/owlps-positioning/src/result.cc +++ b/owlps-positioning/src/result.cc @@ -50,7 +50,7 @@ void Result::compute_error(const Point3D &real_position) /* *** Operators *** */ -const Result& Result::operator=(const Result &source) +Result& Result::operator=(const Result &source) { if (this == &source) return *this ; @@ -76,7 +76,12 @@ bool Result::operator==(const Result &source) const /** - * @return The result as a CSV string, \em without trailing '\n'. + * This function creates a CSV string from the Result's data. + * + * The format used is the following: + * Algorithm_name;X;Y;Z;Error;Area_name + * + * @return The result as a CSV string, \em without a trailing '\\n'. */ const string Result::to_csv() const { @@ -87,8 +92,12 @@ const string Result::to_csv() const << ';' << position.get_x() << ';' << position.get_y() << ';' << position.get_z() - << ';' << "Error" - << ';' << error ; + << ';' << error + << ';' ; + + const Area *const area = Stock::in_which_area_is(position) ; + if (area != NULL) + csv_line << area->get_name() ; return csv_line.str() ; } diff --git a/owlps-positioning/src/result.hh b/owlps-positioning/src/result.hh index 108b660..fd724ea 100644 --- a/owlps-positioning/src/result.hh +++ b/owlps-positioning/src/result.hh @@ -49,7 +49,7 @@ public: /** @name Operators */ //@{ - const Result& operator=(const Result &source) ; + Result& operator=(const Result &source) ; bool operator==(const Result &source) const ; bool operator!=(const Result &source) const ; //@} diff --git a/owlps-positioning/src/resultlist.cc b/owlps-positioning/src/resultlist.cc index c530c66..e1888c7 100644 --- a/owlps-positioning/src/resultlist.cc +++ b/owlps-positioning/src/resultlist.cc @@ -21,7 +21,7 @@ ResultList::~ResultList() /* *** Operators *** */ -const ResultList& ResultList::operator=(const ResultList &source) +ResultList& ResultList::operator=(const ResultList &source) { if (this == &source) return *this ; @@ -46,7 +46,15 @@ bool ResultList::operator==(const ResultList &source) const /** - * @return The results as a CSV string, \em without trailing '\n'. + * This function creates a CSV string from the Result's data. + * + * The format used is the following: + * Mobile_MAC;Request_type;Timestamp;[Algorithm_1];…;[Algorithm_n] + * + * The CSV format for the [Algorithm_i] strings is documented in + * Result::to_csv(). + * + * @return The results as a CSV string, \em without a trailing '\\n'. */ const string ResultList::to_csv() const { diff --git a/owlps-positioning/src/resultlist.hh b/owlps-positioning/src/resultlist.hh index ee20901..6a03e80 100644 --- a/owlps-positioning/src/resultlist.hh +++ b/owlps-positioning/src/resultlist.hh @@ -38,7 +38,7 @@ public: /** @name Operators */ //@{ - const ResultList& operator=(const ResultList &source) ; + ResultList& operator=(const ResultList &source) ; bool operator==(const ResultList &source) const ; bool operator!=(const ResultList &source) const ; //@} diff --git a/owlps-positioning/src/stock.cc b/owlps-positioning/src/stock.cc index d020a63..e258180 100644 --- a/owlps-positioning/src/stock.cc +++ b/owlps-positioning/src/stock.cc @@ -87,7 +87,7 @@ const Building& Stock::get_building(const string &name) * @returns A pointer to the first Area in which \em point was found. * @returns NULL if \em point does not belong to any Area. */ -const Area* Stock::in_which_area_is(const Point3D point) +const Area* Stock::in_which_area_is(const Point3D &point) { for (unordered_map::const_iterator b = buildings.begin() ; b != buildings.end() ; ++b) @@ -281,12 +281,7 @@ void Stock::update_all_friis_indexes() int nb_friis_idx = 0 ; // Compute main general term, independant from scans - double ap_freq = ap->second.get_frequency() ; - double const_term = - ap->second.get_antenna_gain() - - 20 * log10(4 * M_PI) - + 20 * log10(PosUtil::LIGHT_SPEED / ap_freq) - + ap->second.get_trx_power() ; + double const_term = ap->second.friis_constant_term() ; /* * Compute indexes for each ReferencePoint. The Friis index for an @@ -424,48 +419,12 @@ closest_reference_point(const Request &request) } -/** - * Each reference point P we want to generate will end-up containing - * as many calibration requests as the total number of APs. - * For each of these requests, we consider a transmitter TRX (which is - * a virtual mobile) and a receiver RX (the current AP). - * To generate the signal strength (SS) received in P by RX from TRX, - * we first select two reference APs REF1 and REF2. Then, we average - * the real measurements REF1->RX and REF2->RX, weighting in function - * of the angles REF-RX-TRX and the distance from RX to TRX to compute - * the SS. - * Hope this is clear enough… - */ void Stock::regenerate_reference_points() { assert(! aps.empty()) ; assert(! reference_points.empty()) ; - /* Delete calibration requests that do not come from the APs */ - unordered_set::iterator rp = reference_points.begin() ; - while (rp != reference_points.end()) - { - ReferencePoint rp_copy(*rp) ; - if (rp_copy.delete_generated_requests()) // rp_copy was modified - { - rp = reference_points.erase(rp) ; - // Reinsert the modified copy if it still contains at least - // one CalibrationRequest: - if (! rp_copy.get_requests().empty()) - reference_points.insert(rp_copy) ; - /* __Note on the above insert__ - * From the boost::unordered documentation: - * "insert is only allowed to invalidate iterators when the - * insertion causes the load factor to be greater than or - * equal to the maximum load factor." - * In our case, we always remove an element prior to insert, - * so the load factor will never change; therefore insert() - * should be safe here. - */ - } - else // rp_copy was not modified - ++rp ; - } + delete_non_ap_calibration_requests() ; if (reference_points.size() < 3) { @@ -477,15 +436,15 @@ void Stock::regenerate_reference_points() } /* Generate RPs */ - if (! Configuration::is_configured("positioning.minmax-start") || - ! Configuration::is_configured("positioning.minmax-stop")) + if (! Configuration::is_configured("positioning.area-start") || + ! Configuration::is_configured("positioning.area-stop")) throw missing_configuration( "You must define the deployment area in order to generate" " reference points.") ; Point3D start( - Configuration::string_value("positioning.minmax-start")) ; + Configuration::string_value("positioning.area-start")) ; Point3D stop( - Configuration::string_value("positioning.minmax-stop")) ; + Configuration::string_value("positioning.area-stop")) ; float step_x = Configuration::float_value("positioning.generated-meshing-grain-x") ; float step_y = @@ -496,150 +455,161 @@ void Stock::regenerate_reference_points() //for (float z = start.get_z() ; z <= stop.get_z() ; z += step_z) { Point3D current_point(x,y,z) ; - - // If the point is the coordinates of an existing AP, we don't - // need to generate it - if (is_ap_coordinate(current_point)) - continue ; - - /* Get/create the reference point */ - const ReferencePoint ¤t_rp = - find_create_reference_point(current_point) ; - - /* Create the timestamp */ - Timestamp time_sent ; - time_sent.now() ; - - /* Create the measurement list */ - unordered_map measurements ; - - /* Prepare the virtual mobile */ - string vmob_mac(PosUtil::int_to_mac(nb_virtual_mobiles++)) ; - // The gain and trx power of the mobile will be the average of - // those of all the known APs (could be better, probably) - double vmob_gain = 0 ; - double vmob_pow = 0 ; - - for (unordered_map::const_iterator - rx = aps.begin() ; rx != aps.end() ; ++rx) - { - /* Update the mobile's attributes */ - vmob_gain += rx->second.get_antenna_gain() / aps.size() ; - vmob_pow += rx->second.get_trx_power() / aps.size() ; - - /* Choose the 2 nearest APs in angle */ - const Point3D &rx_coord = - rx->second.get_coordinates() ; - multimap::const_iterator> - sorted_angles ; - for (unordered_map::const_iterator - ref = aps.begin() ; ref != aps.end() ; ++ref) - { - if (ref == rx) - continue ; - const Point3D &ref_coord = - ref->second.get_coordinates() ; - // Skip the AP if the associated reference point does - // not exist yet: - if (! reference_point_exists(ref_coord)) - continue ; - double angle = - rx_coord.angle(current_point, ref_coord) ; - pair::const_iterator> - angle_ap(angle, ref) ; - sorted_angles.insert(angle_ap) ; - } - assert(sorted_angles.size() > 1) ; - - /* Compute the angle weight of the 2 reference APs */ - map::const_iterator> - ::const_iterator s = sorted_angles.begin() ; - // Angle REF1-RX-P - double ref1_angle = s->first ; - const AccessPoint &ref1 = s->second->second ; - ++s ; - const AccessPoint &ref2 = s->second->second ; - - // Angle REF1-RX-REF2 - const Point3D &ref1_coord = ref1.get_coordinates() ; - const Point3D &ref2_coord = ref2.get_coordinates() ; - double reference_angle = - rx_coord.angle(ref1_coord, ref2_coord) ; - double ref1_percent, ref2_percent ; - if (reference_angle == 0) - ref1_percent = ref2_percent = 50 ; - else - { - ref1_percent = ref1_angle * 100 / reference_angle ; - if (ref1_percent > 100) - ref1_percent = 100 ; - ref2_percent = 100 - ref1_percent ; - } - - /* Compute the SS that would be received from a mobile at - * distance of RX-P, in the direction of each reference AP */ - // Distance RX-P - float current_point_dst = - rx_coord.distance(current_point) ; - // Constants & common data - double wavelength = - static_cast(PosUtil::LIGHT_SPEED) / - rx->second.get_frequency() ; - double common_ss = - rx->second.get_antenna_gain() + - 20 * log10(wavelength) - - 20 * log10(4 * M_PI) ; - // SS for REF1 - const ReferencePoint &ref1_rp = - get_reference_point(ref1_coord) ; - double friis_index = - ref1_rp.friis_index_for_ap(rx->second.get_mac_addr()) ; - double ref1_ss = - common_ss + - ref1.get_trx_power() + - ref1.get_antenna_gain() - - 10 * friis_index * log10(current_point_dst) ; - // SS for REF2 - const ReferencePoint &ref2_rp = - get_reference_point(ref2_coord) ; - friis_index = - ref2_rp.friis_index_for_ap(rx->second.get_mac_addr()) ; - double ref2_ss = - common_ss + - ref2.get_trx_power() + - ref2.get_antenna_gain() - - 10 * friis_index * log10(current_point_dst) ; - - /* Compute the SS */ - ref1_ss = ref1_ss * ref1_percent / 100 ; - ref2_ss = ref2_ss * ref2_percent / 100 ; - double rx_ss = ref1_ss + ref2_ss ; - - /* Create the measurement, add it to the list */ - Measurement m(&rx->second) ; - m.add_ss(rx_ss) ; - measurements[rx->second.get_mac_addr()] = m ; - } - - /* Create the virtual mobile */ - Mobile vmob("", vmob_mac, vmob_gain, vmob_pow) ; - const Mobile &mobile = find_create_mobile(vmob) ; - - /* Create the calibration request */ - CalibrationRequest cr(OWL_REQUEST_GENERATED) ; - cr.set_time_sent(time_sent) ; - cr.set_mobile(&mobile) ; - cr.set_measurements(measurements) ; - cr.set_reference_point(¤t_rp) ; - - store_calibration_request(cr) ; + generate_reference_point(current_point) ; } } +/** + * The reference point P we want to generate will end-up containing + * as many calibration requests as the total number of APs. + * For each of these requests, we consider a transmitter TRX (which is + * a virtual mobile) and a receiver RX (the current AP). + * To generate the signal strength (SS) received in P by RX from TRX, + * we first select two reference APs REF1 and REF2. Then, we average + * the real measurements REF1->RX and REF2->RX, weighting in function + * of the angles REF-RX-TRX and the distance from RX to TRX to compute + * the SS. + * Hope this is clear enough… + */ +void Stock::generate_reference_point(const Point3D &point) +{ + // If the point is the coordinates of an existing AP, we don't + // need to generate it + if (is_ap_coordinate(point)) + return ; + + /* Get/create the reference point */ + const ReferencePoint ¤t_rp = + find_create_reference_point(point) ; + + /* Create the timestamp */ + Timestamp time_sent ; + time_sent.now() ; + + /* Create the measurement list */ + unordered_map measurements ; + + /* Prepare the virtual mobile */ + string vmob_mac(PosUtil::int_to_mac(nb_virtual_mobiles++)) ; + // The gain and trx power of the mobile will be the average of + // those of all the known APs (could be better, probably) + double vmob_gain = 0 ; + double vmob_pow = 0 ; + + for (unordered_map::const_iterator + rx = aps.begin() ; rx != aps.end() ; ++rx) + { + /* Update the mobile's attributes */ + vmob_gain += rx->second.get_antenna_gain() / aps.size() ; + vmob_pow += rx->second.get_trx_power() / aps.size() ; + + /* Choose the 2 nearest APs in angle */ + const Point3D &rx_coord = + rx->second.get_coordinates() ; + multimap::const_iterator> + sorted_angles ; + for (unordered_map::const_iterator + ref = aps.begin() ; ref != aps.end() ; ++ref) + { + if (ref == rx) + continue ; + const Point3D &ref_coord = + ref->second.get_coordinates() ; + // Skip the AP if the associated reference point does + // not exist yet: + if (! reference_point_exists(ref_coord)) + continue ; + double angle = + rx_coord.angle(point, ref_coord) ; + pair::const_iterator> + angle_ap(angle, ref) ; + sorted_angles.insert(angle_ap) ; + } + assert(sorted_angles.size() > 1) ; + + /* Compute the angle weight of the 2 reference APs */ + map::const_iterator> + ::const_iterator s = sorted_angles.begin() ; + // Angle REF1-RX-P + double ref1_angle = s->first ; + const AccessPoint &ref1 = s->second->second ; + ++s ; + const AccessPoint &ref2 = s->second->second ; + + // Angle REF1-RX-REF2 + const Point3D &ref1_coord = ref1.get_coordinates() ; + const Point3D &ref2_coord = ref2.get_coordinates() ; + double reference_angle = + rx_coord.angle(ref1_coord, ref2_coord) ; + double ref1_percent, ref2_percent ; + if (reference_angle == 0) + ref1_percent = ref2_percent = 50 ; + else + { + ref1_percent = ref1_angle * 100 / reference_angle ; + if (ref1_percent > 100) + ref1_percent = 100 ; + ref2_percent = 100 - ref1_percent ; + } + + /* Compute the SS that would be received from a mobile at + * distance of RX-P, in the direction of each reference AP */ + // Distance RX-P + float point_dst = + rx_coord.distance(point) ; + // Constant term + double common_ss = rx->second.friis_constant_term() ; + // SS for REF1 + const ReferencePoint &ref1_rp = + get_reference_point(ref1_coord) ; + double friis_index = + ref1_rp.friis_index_for_ap(rx->second.get_mac_addr()) ; + double ref1_ss = + common_ss + + ref1.get_trx_power() + + ref1.get_antenna_gain() - + 10 * friis_index * log10(point_dst) ; + // SS for REF2 + const ReferencePoint &ref2_rp = + get_reference_point(ref2_coord) ; + friis_index = + ref2_rp.friis_index_for_ap(rx->second.get_mac_addr()) ; + double ref2_ss = + common_ss + + ref2.get_trx_power() + + ref2.get_antenna_gain() - + 10 * friis_index * log10(point_dst) ; + + /* Compute the SS */ + ref1_ss = ref1_ss * ref1_percent / 100 ; + ref2_ss = ref2_ss * ref2_percent / 100 ; + double rx_ss = ref1_ss + ref2_ss ; + + /* Create the measurement, add it to the list */ + Measurement m(&rx->second) ; + m.add_ss(rx_ss) ; + measurements[rx->second.get_mac_addr()] = m ; + } + + /* Create the virtual mobile */ + Mobile vmob("", vmob_mac, vmob_gain, vmob_pow) ; + const Mobile &mobile = find_create_mobile(vmob) ; + + /* Create the calibration request */ + CalibrationRequest cr(OWL_REQUEST_GENERATED) ; + cr.set_time_sent(time_sent) ; + cr.set_mobile(&mobile) ; + cr.set_measurements(measurements) ; + cr.set_reference_point(¤t_rp) ; + + store_calibration_request(cr) ; +} + + /* *** CalibrationRequest operations *** */ @@ -729,3 +699,32 @@ closest_calibration_request(const Request &request) return *closest ; } + + +void Stock::delete_non_ap_calibration_requests() +{ + unordered_set::iterator rp = reference_points.begin() ; + while (rp != reference_points.end()) + { + ReferencePoint rp_copy(*rp) ; + if (rp_copy.delete_generated_requests()) // rp_copy was modified + { + rp = reference_points.erase(rp) ; + // Reinsert the modified copy if it still contains at least + // one CalibrationRequest: + if (! rp_copy.get_requests().empty()) + reference_points.insert(rp_copy) ; + /* __Note on the above insert__ + * From the boost::unordered documentation: + * "insert is only allowed to invalidate iterators when the + * insertion causes the load factor to be greater than or + * equal to the maximum load factor." + * In our case, we always remove an element prior to insert, + * so the load factor will never change; therefore insert() + * should be safe here. + */ + } + else // rp_copy was not modified + ++rp ; + } +} diff --git a/owlps-positioning/src/stock.hh b/owlps-positioning/src/stock.hh index 60bc7fe..4f75ef2 100644 --- a/owlps-positioning/src/stock.hh +++ b/owlps-positioning/src/stock.hh @@ -41,6 +41,18 @@ private: /// List of known CalibrationRequest static std::tr1::unordered_set calibration_requests ; + /** @name ReferencePoint operations */ + //@{ + /// Generates a single reference point + static void generate_reference_point(const Point3D &point) ; + //@} + + /** @name CalibrationRequest operations */ + //@{ + /// Delete calibration requests that do not come from the APs + static void delete_non_ap_calibration_requests(void) ; + //@} + public: /** @name Building operations */ //@{ @@ -51,7 +63,7 @@ public: /// Searches for a Building and creates it if it does not exist static const Building& find_create_building(const std::string &name) ; /// Searches the Area in which \em point is - static const Area* in_which_area_is(const Point3D point) ; + static const Area* in_which_area_is(const Point3D &point) ; //@} /** @name Waypoint operations */ diff --git a/owlps-positioning/src/timestamp.cc b/owlps-positioning/src/timestamp.cc index 498f91e..d826d38 100644 --- a/owlps-positioning/src/timestamp.cc +++ b/owlps-positioning/src/timestamp.cc @@ -144,7 +144,7 @@ bool Timestamp::greater_than(const struct timespec &source) const /* *** Operators *** */ -const Timestamp& Timestamp::operator=(const Timestamp &source) +Timestamp& Timestamp::operator=(const Timestamp &source) { if (this == &source) return *this ; diff --git a/owlps-positioning/src/timestamp.hh b/owlps-positioning/src/timestamp.hh index b64b031..dcbd23a 100644 --- a/owlps-positioning/src/timestamp.hh +++ b/owlps-positioning/src/timestamp.hh @@ -62,9 +62,9 @@ public: /** @name Operators */ //@{ - const Timestamp& operator=(const Timestamp &source) ; - const Timestamp& operator=(const struct timespec &source) ; - const Timestamp& operator=(const uint64_t source) ; //< deprecated + Timestamp& operator=(const Timestamp &source) ; + Timestamp& operator=(const struct timespec &source) ; + Timestamp& operator=(const uint64_t source) ; //< deprecated bool operator==(const Timestamp &source) const ; bool operator==(const struct timespec &source) const ; bool operator==(const uint64_t source) const ; //< deprecated @@ -109,15 +109,14 @@ inline void Timestamp::clear(void) /* *** Operators *** */ -inline const Timestamp& Timestamp:: -operator=(const struct timespec &source) +inline Timestamp& Timestamp::operator=(const struct timespec &source) { set(source) ; return *this ; } -inline const Timestamp& Timestamp::operator=(const uint64_t source) +inline Timestamp& Timestamp::operator=(const uint64_t source) { set(source) ; return *this ; diff --git a/owlps-positioning/src/userinterface.cc b/owlps-positioning/src/userinterface.cc index e229189..867dbcc 100644 --- a/owlps-positioning/src/userinterface.cc +++ b/owlps-positioning/src/userinterface.cc @@ -15,7 +15,7 @@ namespace po = boost::program_options ; /* *** Default value definitions *** */ #define DEFAULT_CONFIG_FILE_NAME \ - "/usr/local/etc/owlps/owlps-positioning.cfg" + "/usr/local/etc/owlps/owlps-positioning.conf" #define DEFAULT_TCPEVAAL_HOST "127.0.0.1" #define DEFAULT_TCPEVAAL_PORT 4444 @@ -183,12 +183,15 @@ void UserInterface::fill_positioning_options() "Algorithms used to compute positions. You can specify" "this option more than once (but at least once). Allowed: Real, FBCM," " FRBHMBasic, InterlinkNetworks, RADAR.") - ("positioning.minmax-start", po::value(), - "Coordinates of the start point of the MinMax multilateration" - " method (string format: \"X;Y;Z\").") - ("positioning.minmax-stop", po::value(), - "Coordinates of the stop point of the MinMax multilateration" - " method (string format: \"X;Y;Z\").") + ("positioning.area-start", po::value(), + "Coordinates of the first point of the deployment area; this is" + " used to delimit the area in which the MinMax multilateration" + " method tests points and in which the reference points are" + " generated, if the corresponding options are activated" + " (string format: \"X;Y;Z\").") + ("positioning.area-stop", po::value(), + "Coordinates of the last point of the deployment area" + " (string format: \"X;Y;Z\").") ("positioning.radar-average-reference-points", po::value()->default_value(false), "With the RADAR algorithm, for a given positioning request, average" diff --git a/owlps-positioning/src/waypoint.cc b/owlps-positioning/src/waypoint.cc index 506c86c..0b723d8 100644 --- a/owlps-positioning/src/waypoint.cc +++ b/owlps-positioning/src/waypoint.cc @@ -53,7 +53,7 @@ Waypoint::~Waypoint() /* *** Operators *** */ -const Waypoint& Waypoint::operator=(const Waypoint &wp) +Waypoint& Waypoint::operator=(const Waypoint &wp) { if (this == &wp) return *this ; diff --git a/owlps-positioning/src/waypoint.hh b/owlps-positioning/src/waypoint.hh index 7ea0a61..ac294ec 100644 --- a/owlps-positioning/src/waypoint.hh +++ b/owlps-positioning/src/waypoint.hh @@ -53,7 +53,7 @@ public: /** @name Operators */ //@{ - const Waypoint& operator=(const Waypoint &wp) ; + Waypoint& operator=(const Waypoint &wp) ; bool operator==(const Waypoint &wp) const ; bool operator!=(const Waypoint &wp) const ; operator std::string(void) const ; diff --git a/owlps-positioning/src/wifidevice.cc b/owlps-positioning/src/wifidevice.cc index 1b0ffd6..aff2b7c 100644 --- a/owlps-positioning/src/wifidevice.cc +++ b/owlps-positioning/src/wifidevice.cc @@ -7,7 +7,7 @@ using namespace std ; /* *** Operators *** */ -const WifiDevice& WifiDevice::operator=(const WifiDevice &wd) +WifiDevice& WifiDevice::operator=(const WifiDevice &wd) { if (this == &wd) return *this ; diff --git a/owlps-positioning/src/wifidevice.hh b/owlps-positioning/src/wifidevice.hh index 6777fb5..fc11b3a 100644 --- a/owlps-positioning/src/wifidevice.hh +++ b/owlps-positioning/src/wifidevice.hh @@ -52,7 +52,7 @@ public: /** @name Operators */ //@{ - const WifiDevice& operator=(const WifiDevice &wd) ; + WifiDevice& operator=(const WifiDevice &wd) ; bool operator==(const WifiDevice &wd) const ; bool operator!=(const WifiDevice &wl) const ; //@}