Merge branch dev (v1.1.7) into dev-drone
This commit is contained in:
commit
e823014708
36
TODO
36
TODO
|
@ -1,11 +1,14 @@
|
||||||
* Global
|
* Global
|
||||||
|
|
||||||
|
- Add option dump-configuration (displays the config & exits).
|
||||||
- Makefiles:
|
- Makefiles:
|
||||||
° Translate comments & help.
|
° Translate comments & help.
|
||||||
|
° Merge Makefile and Makefile_atheros*. Use template makefiles,
|
||||||
|
autohell, cmake…?
|
||||||
- Use string for network exchanges?
|
- Use string for network exchanges?
|
||||||
- Mark arguments as const in function headers if needed
|
- Mark arguments as const in function headers if needed
|
||||||
That is (mostly) done in the owlps-positioning C++ code, but not
|
Mostly done in the owlps-positioning C++ code (should check that),
|
||||||
constantly in C modules.
|
but not constantly in C modules.
|
||||||
[Done in libowlps & libowlps-client.]
|
[Done in libowlps & libowlps-client.]
|
||||||
- Allow to use hostnames instead of IP addresses in all modules
|
- Allow to use hostnames instead of IP addresses in all modules
|
||||||
getaddrinfo(3) (or gethostbyname(3)) should be used when opening
|
getaddrinfo(3) (or gethostbyname(3)) should be used when opening
|
||||||
|
@ -25,10 +28,14 @@
|
||||||
|
|
||||||
* Aggregator
|
* Aggregator
|
||||||
|
|
||||||
|
- -o should be optional.
|
||||||
|
- Add an option to (not) flush the output file.
|
||||||
|
- Refactor:
|
||||||
|
° monitor_requests()
|
||||||
|
° got_request()
|
||||||
- inet_ntoa() is not secure with threads
|
- inet_ntoa() is not secure with threads
|
||||||
(But it is currently used by only one thread.) Use inet_ntop()
|
(But it is currently used by only one thread.) Use inet_ntop()
|
||||||
instead?
|
instead?
|
||||||
- Refactor got_request().
|
|
||||||
- Use the type of a request to identify it?
|
- Use the type of a request to identify it?
|
||||||
(along with the mobile MAC address and the request time)
|
(along with the mobile MAC address and the request time)
|
||||||
- got_request(): option for the maximal difference time
|
- got_request(): option for the maximal difference time
|
||||||
|
@ -36,36 +43,29 @@
|
||||||
and received within an interval of 10ms are part of the same
|
and received within an interval of 10ms are part of the same
|
||||||
request. We should define an option to allow user to choose the
|
request. We should define an option to allow user to choose the
|
||||||
time he wants.
|
time he wants.
|
||||||
- Allow blank parameters for output options.
|
|
||||||
|
|
||||||
|
|
||||||
* Listener
|
* Listener
|
||||||
|
|
||||||
- Refactor and review read_packet().
|
- Refactor and review read_packet().
|
||||||
|
- Handle better the configuration file reading
|
||||||
|
Get rid of the "Cannot open configuration file" error, in quiet
|
||||||
|
mode and when the default configuration file has to be used (no
|
||||||
|
file specified by the user with -f).
|
||||||
- Listen for autocalibration requests without sending requests?
|
- Listen for autocalibration requests without sending requests?
|
||||||
- read_packet(): use ieee80211_header_size for all implicit packets
|
- read_packet(): use ieee80211_header_size for all implicit packets
|
||||||
Currently the size is corrected only for data packets.
|
Currently the size is corrected only for data packets.
|
||||||
- Move endianess #defines in libowlps?
|
|
||||||
- Merge Makefile and Makefile_atheros?
|
|
||||||
Use autohell, cmake, etc.?
|
|
||||||
- Use positive (USE_CONFUSE) and negative (NO_USE_PTHREAD) options?
|
|
||||||
The default options could be modified, but that's not so important,
|
|
||||||
is it?
|
|
||||||
|
|
||||||
|
|
||||||
* Client
|
* Client
|
||||||
|
|
||||||
|
- Handle signals.
|
||||||
|
- Add verbose & quiet options.
|
||||||
|
- Log sent requests?
|
||||||
- Allow to use a string for the direction?
|
- Allow to use a string for the direction?
|
||||||
Could be nice, but probably useless.
|
Could be nice, but probably useless.
|
||||||
|
|
||||||
|
|
||||||
* Positioning
|
* Positioning
|
||||||
|
|
||||||
- Has its own fat TODO file, which I should translate.
|
- Has its own fat TODO file, which I could merge in here.
|
||||||
|
|
||||||
|
|
||||||
* writeInDb
|
|
||||||
|
|
||||||
- Do something about that
|
|
||||||
° Merge in owlps-positioning?
|
|
||||||
° Delete?
|
|
||||||
|
|
|
@ -119,6 +119,7 @@ typedef struct _owl_autocalibration_order
|
||||||
#define OWL_REQUEST_NORMAL 0
|
#define OWL_REQUEST_NORMAL 0
|
||||||
#define OWL_REQUEST_CALIBRATION 1
|
#define OWL_REQUEST_CALIBRATION 1
|
||||||
#define OWL_REQUEST_AUTOCALIBRATION 2
|
#define OWL_REQUEST_AUTOCALIBRATION 2
|
||||||
|
#define OWL_REQUEST_GENERATED 3
|
||||||
#define OWL_REQUEST_IMPLICIT 10
|
#define OWL_REQUEST_IMPLICIT 10
|
||||||
#define OWL_REQUEST_UNDEFINED 255
|
#define OWL_REQUEST_UNDEFINED 255
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,7 @@ OBJ_LIST = \
|
||||||
userinterface.o \
|
userinterface.o \
|
||||||
inputdatareader.o \
|
inputdatareader.o \
|
||||||
accesspointsreadercsv.o \
|
accesspointsreadercsv.o \
|
||||||
|
mobilesreadercsv.o \
|
||||||
topologyreadercsv.o \
|
topologyreadercsv.o \
|
||||||
textfilereader.o \
|
textfilereader.o \
|
||||||
csvfilereader.o \
|
csvfilereader.o \
|
||||||
|
@ -90,6 +91,7 @@ OBJ_LIST = \
|
||||||
outputterminal.o \
|
outputterminal.o \
|
||||||
outputcsv.o \
|
outputcsv.o \
|
||||||
outputudpsocket.o \
|
outputudpsocket.o \
|
||||||
|
outputtcpsocketevaal.o \
|
||||||
positioning.o \
|
positioning.o \
|
||||||
input.o \
|
input.o \
|
||||||
inputcsv.o \
|
inputcsv.o \
|
||||||
|
@ -139,6 +141,7 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc $(SRC_DIR)/%.hh
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
$(OBJ_DIR)/point3d.o: \
|
$(OBJ_DIR)/point3d.o: \
|
||||||
|
$(OBJ_DIR)/posutil.o \
|
||||||
$(OBJ_DIR)/posexcept.o
|
$(OBJ_DIR)/posexcept.o
|
||||||
$(OBJ_DIR)/posutil.o: \
|
$(OBJ_DIR)/posutil.o: \
|
||||||
$(OBJ_DIR)/stock.o \
|
$(OBJ_DIR)/stock.o \
|
||||||
|
@ -154,6 +157,7 @@ $(OBJ_DIR)/userinterface.o: \
|
||||||
$(OBJ_DIR)/configuration.o
|
$(OBJ_DIR)/configuration.o
|
||||||
$(OBJ_DIR)/inputdatareader.o: \
|
$(OBJ_DIR)/inputdatareader.o: \
|
||||||
$(OBJ_DIR)/accesspointsreadercsv.o \
|
$(OBJ_DIR)/accesspointsreadercsv.o \
|
||||||
|
$(OBJ_DIR)/mobilesreadercsv.o \
|
||||||
$(OBJ_DIR)/topologyreadercsv.o \
|
$(OBJ_DIR)/topologyreadercsv.o \
|
||||||
$(OBJ_DIR)/configuration.o \
|
$(OBJ_DIR)/configuration.o \
|
||||||
$(OBJ_DIR)/posexcept.o
|
$(OBJ_DIR)/posexcept.o
|
||||||
|
@ -161,6 +165,10 @@ $(OBJ_DIR)/accesspointsreadercsv.o: \
|
||||||
$(OBJ_DIR)/csvfilereader.o \
|
$(OBJ_DIR)/csvfilereader.o \
|
||||||
$(OBJ_DIR)/accesspoint.o \
|
$(OBJ_DIR)/accesspoint.o \
|
||||||
$(OBJ_DIR)/stock.o
|
$(OBJ_DIR)/stock.o
|
||||||
|
$(OBJ_DIR)/mobilesreadercsv.o: \
|
||||||
|
$(OBJ_DIR)/csvfilereader.o \
|
||||||
|
$(OBJ_DIR)/mobile.o \
|
||||||
|
$(OBJ_DIR)/stock.o
|
||||||
$(OBJ_DIR)/topologyreadercsv.o: \
|
$(OBJ_DIR)/topologyreadercsv.o: \
|
||||||
$(OBJ_DIR)/csvfilereader.o \
|
$(OBJ_DIR)/csvfilereader.o \
|
||||||
$(OBJ_DIR)/area.o \
|
$(OBJ_DIR)/area.o \
|
||||||
|
@ -195,6 +203,8 @@ $(OBJ_DIR)/calibrationrequest.o: \
|
||||||
$(OBJ_DIR)/referencepoint.o \
|
$(OBJ_DIR)/referencepoint.o \
|
||||||
$(OBJ_DIR)/direction.o
|
$(OBJ_DIR)/direction.o
|
||||||
$(OBJ_DIR)/result.o: \
|
$(OBJ_DIR)/result.o: \
|
||||||
|
$(OBJ_DIR)/stock.o \
|
||||||
|
$(OBJ_DIR)/area.o \
|
||||||
$(OBJ_DIR)/request.o
|
$(OBJ_DIR)/request.o
|
||||||
$(OBJ_DIR)/resultlist.o: \
|
$(OBJ_DIR)/resultlist.o: \
|
||||||
$(OBJ_DIR)/result.o
|
$(OBJ_DIR)/result.o
|
||||||
|
@ -239,6 +249,9 @@ $(OBJ_DIR)/outputcsv.o: \
|
||||||
$(OBJ_DIR)/outputudpsocket.o: \
|
$(OBJ_DIR)/outputudpsocket.o: \
|
||||||
$(SRC_DIR)/outputmedium.hh \
|
$(SRC_DIR)/outputmedium.hh \
|
||||||
$(OBJ_DIR)/result.o
|
$(OBJ_DIR)/result.o
|
||||||
|
$(OBJ_DIR)/outputtcpsocketevaal.o: \
|
||||||
|
$(SRC_DIR)/outputmedium.hh \
|
||||||
|
$(OBJ_DIR)/result.o
|
||||||
$(OBJ_DIR)/outputcsv.o: \
|
$(OBJ_DIR)/outputcsv.o: \
|
||||||
$(SRC_DIR)/outputmedium.hh \
|
$(SRC_DIR)/outputmedium.hh \
|
||||||
$(OBJ_DIR)/result.o
|
$(OBJ_DIR)/result.o
|
||||||
|
@ -246,6 +259,7 @@ $(OBJ_DIR)/output.o: \
|
||||||
$(OBJ_DIR)/outputterminal.o \
|
$(OBJ_DIR)/outputterminal.o \
|
||||||
$(OBJ_DIR)/outputcsv.o \
|
$(OBJ_DIR)/outputcsv.o \
|
||||||
$(OBJ_DIR)/outputudpsocket.o \
|
$(OBJ_DIR)/outputudpsocket.o \
|
||||||
|
$(OBJ_DIR)/outputtcpsocketevaal.o \
|
||||||
$(OBJ_DIR)/configuration.o \
|
$(OBJ_DIR)/configuration.o \
|
||||||
$(OBJ_DIR)/posexcept.o
|
$(OBJ_DIR)/posexcept.o
|
||||||
$(OBJ_DIR)/multilaterationalgorithm.o: \
|
$(OBJ_DIR)/multilaterationalgorithm.o: \
|
||||||
|
|
|
@ -1,17 +1,60 @@
|
||||||
|
|
||||||
- Multithread algorithm calls.
|
- Known bugs
|
||||||
|
° FBCM always gives the same result.
|
||||||
|
° Cannot compute the error (Real) with autocalibration requests.
|
||||||
|
|
||||||
- Write a class for Request::type?
|
- 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
|
CalibrationRequest::direction uses a dedicated class Direction, why
|
||||||
not Request::type? That would simplify writing of the type to
|
not Request::type? That would simplify writing of the type to
|
||||||
streams (no need to cast each time anymore).
|
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
|
- 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.
|
° Improve --verbose (and/or debug level): print the options, etc.
|
||||||
° Case-insensitive string comparison (for algorithm names, etc.).
|
° Case-insensitive string comparison (for algorithm names, etc.).
|
||||||
° Use a prefix for configuration files (search for config files set
|
° Use a prefix for configuration files (search for config files set
|
||||||
with relative path in owlps-positioning.cfg in the same directory).
|
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
|
- Unit tests
|
||||||
° Update tests (currently unmaintained).
|
° Update tests (currently unmaintained).
|
||||||
° Unfinished tests:
|
° Unfinished tests:
|
||||||
|
@ -20,6 +63,9 @@
|
||||||
. Output
|
. Output
|
||||||
. Positioning
|
. Positioning
|
||||||
° Test InterlinkNetworks::compute() ?
|
° 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
|
- Revoir le diagramme UML
|
||||||
° Associations : devraient êtres représentées par des attributs
|
° Associations : devraient êtres représentées par des attributs
|
||||||
|
@ -27,25 +73,6 @@
|
||||||
° Compositions : devraient être représentées par des attributs
|
° Compositions : devraient être représentées par des attributs
|
||||||
normaux.
|
normaux.
|
||||||
|
|
||||||
- Building
|
|
||||||
Dans le destructeur, vérifier qu'il faut bien supprimer les Area et
|
|
||||||
les Waypoint. Si oui, faut-il aussi les enlever des listes dans
|
|
||||||
Stock ? (Pour l'instant ils ne sont pas dans Stock.)
|
|
||||||
|
|
||||||
- ReferencePoint
|
|
||||||
° La liste des requêtes devrait être un unordered_set (et pas un
|
|
||||||
vector), pour garantir l'unicité des entrées.
|
|
||||||
|
|
||||||
- MinMax
|
|
||||||
° Différencier le pas pour X, Y et Z ?
|
|
||||||
|
|
||||||
- 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
|
|
||||||
|
|
||||||
- « C++ en action »
|
- « C++ en action »
|
||||||
° Espaces de noms ? 109
|
° Espaces de noms ? 109
|
||||||
° Réserver l'espace mémoire des vector avec reserve(). 217
|
° Réserver l'espace mémoire des vector avec reserve(). 217
|
||||||
|
@ -59,11 +86,3 @@
|
||||||
publics. La classe Direction (et maintenant Timestamp) tend à
|
publics. La classe Direction (et maintenant Timestamp) tend à
|
||||||
respecter ce principe en utilisant mieux les opérateurs et en ne
|
respecter ce principe en utilisant mieux les opérateurs et en ne
|
||||||
proposant pas d'accesseur direct.
|
proposant pas d'accesseur direct.
|
||||||
|
|
||||||
- Miscellaneous
|
|
||||||
° Pointer function arguments: const * const <type>
|
|
||||||
|
|
||||||
- Timestamp
|
|
||||||
Dans les tests, il y a une probabilité de 1/1000000 que la valeur
|
|
||||||
en ns et la valeur arrondie en ms soient identiques. Dans ce cas,
|
|
||||||
certains tests peuvent échouer.
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Mobiles' physical description file.
|
||||||
|
#
|
||||||
|
# Each line follows this format:
|
||||||
|
# MAC address;Antenna gain (dBi);Trx power (dBm)
|
||||||
|
#
|
||||||
|
# Blank lines are ignored. Commented lines must have a sharp (#) as
|
||||||
|
# their FIRST character.
|
||||||
|
|
||||||
|
# Example mobile:
|
||||||
|
#aa:bb:cc:dd:ee:ff;1.8;18.0
|
|
|
@ -10,6 +10,10 @@
|
||||||
ap-medium = CSV
|
ap-medium = CSV
|
||||||
ap-csv-file = cfg/listeners.csv
|
ap-csv-file = cfg/listeners.csv
|
||||||
|
|
||||||
|
# Description of the clients
|
||||||
|
mobile-medium = CSV
|
||||||
|
mobile-csv-file = cfg/mobiles.csv
|
||||||
|
|
||||||
# Description of deployment area topology.
|
# Description of deployment area topology.
|
||||||
# You probably don't need a full description of the topology, see the
|
# You probably don't need a full description of the topology, see the
|
||||||
# topology example file for details.
|
# topology example file for details.
|
||||||
|
@ -59,6 +63,59 @@ csv-file = /tmp/owlps-positioning.log
|
||||||
# request is compared directly to each calibration request.
|
# request is compared directly to each calibration request.
|
||||||
#radar-average-reference-points = false
|
#radar-average-reference-points = false
|
||||||
|
|
||||||
|
# With the RADAR algorithm, do not select reference points on which an
|
||||||
|
# AP is sit, as far as possible (i.e. if there are reference points
|
||||||
|
# where no AP sits). This is useful if you are using autocalibration
|
||||||
|
# and want to select only the generated reference points.
|
||||||
|
# The default is false.
|
||||||
|
#radar-ignore-ap-reference-points = false
|
||||||
|
|
||||||
|
# Generate reference points from the (auto)calibration requests
|
||||||
|
# received.
|
||||||
|
#generate-reference-points = false
|
||||||
|
|
||||||
|
# When the above option is activated, the reference points are generated
|
||||||
|
# with the specified distance (in meters) between one another, in the X
|
||||||
|
# and Y axis.
|
||||||
|
#generated-meshing-grain-x = 0.5
|
||||||
|
#generated-meshing-grain-y = 0.5
|
||||||
|
|
||||||
|
# This option allows the calibration requests sent during the
|
||||||
|
# positioning phase to be added to the calibration request's list. They
|
||||||
|
# are added to the calibration requests read by InputDataReader during
|
||||||
|
# the start-up phase. If this option is not activated, the calibration
|
||||||
|
# requests are handled as positioning requests.
|
||||||
|
# This option must be activated for the self-calibration to work, but
|
||||||
|
# it is not activated by default for security purposes.
|
||||||
|
#accept-new-calibration-requests = false
|
||||||
|
|
||||||
|
# If you activate the above option and want the calibration requests
|
||||||
|
# to be treated as positioning requests (in addition to the normal
|
||||||
|
# treatment of calibration requests), activate this option.
|
||||||
|
# The default is false: the first calibration requests' purpose is to
|
||||||
|
# serve the positioning process, not to use it.
|
||||||
|
#position-calibration-requests = false
|
||||||
|
|
||||||
|
# This option allows to create a new AP when a request is captured by an
|
||||||
|
# AP which is not currently in the APs' list (i.e. not declared in the
|
||||||
|
# APs' configuration file), or when a self-calibration request is sent
|
||||||
|
# by an unknown AP.
|
||||||
|
# It is unactivated by default for the sake of security.
|
||||||
|
#accept-new-aps = false
|
||||||
|
|
||||||
|
# This option allows to create a new mobile when a request is sent by
|
||||||
|
# a mobile which is not currently in the mobiles' list (i.e. not
|
||||||
|
# declared in the mobiles' configuration file). If unset, the requests
|
||||||
|
# sent by unknown mobiles will be dropped.
|
||||||
|
# It is unactivated by default, mainly to avoid interferent devices.
|
||||||
|
#accept-new-mobiles = false
|
||||||
|
|
||||||
|
# When receiving a calibration or autocalibration request from an AP,
|
||||||
|
# containing the transmiter's coordinates, memorise the new AP's
|
||||||
|
# coordinates.
|
||||||
|
# This is unactivated by default for the sake of security.
|
||||||
|
#update-ap-coordinates-online = false
|
||||||
|
|
||||||
[output]
|
[output]
|
||||||
|
|
||||||
# This is the default output if none is specified.
|
# This is the default output if none is specified.
|
||||||
|
|
|
@ -13,7 +13,7 @@ using namespace std ;
|
||||||
AccessPointsReaderCSV::AccessPointsReaderCSV(const string &file_name):
|
AccessPointsReaderCSV::AccessPointsReaderCSV(const string &file_name):
|
||||||
file(file_name)
|
file(file_name)
|
||||||
{
|
{
|
||||||
read_access_points() ;
|
read_devices() ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,18 +21,19 @@ AccessPointsReaderCSV::AccessPointsReaderCSV(const string &file_name):
|
||||||
/* *** Operations *** */
|
/* *** Operations *** */
|
||||||
|
|
||||||
|
|
||||||
void AccessPointsReaderCSV::read_access_points()
|
void AccessPointsReaderCSV::read_devices()
|
||||||
{
|
{
|
||||||
while (file.next_line())
|
while (file.next_line())
|
||||||
process_access_point_line() ;
|
process_device_line() ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AccessPointsReaderCSV::process_access_point_line()
|
void AccessPointsReaderCSV::process_device_line()
|
||||||
{
|
{
|
||||||
string mac ;
|
string mac ;
|
||||||
if (! file.read_field(mac))
|
if (! file.read_field(mac))
|
||||||
throw malformed_input_data("Cannot read access point MAC address!") ;
|
throw malformed_input_data("Cannot read access point MAC address!") ;
|
||||||
|
PosUtil::to_upper(mac) ;
|
||||||
|
|
||||||
Point3D coord ;
|
Point3D coord ;
|
||||||
if (! file.read_point3d(coord))
|
if (! file.read_point3d(coord))
|
||||||
|
@ -52,6 +53,6 @@ void AccessPointsReaderCSV::process_access_point_line()
|
||||||
|
|
||||||
string ip("") ;
|
string ip("") ;
|
||||||
|
|
||||||
AccessPoint ap(coord, ip, mac, gain, power, frequency) ;
|
AccessPoint device(coord, ip, mac, gain, power, frequency) ;
|
||||||
Stock::find_create_ap(ap) ;
|
Stock::find_create_ap(device) ;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,8 @@ class AccessPointsReaderCSV
|
||||||
protected:
|
protected:
|
||||||
CSVFileReader file ;
|
CSVFileReader file ;
|
||||||
|
|
||||||
void read_access_points(void) ;
|
void read_devices(void) ;
|
||||||
void process_access_point_line(void) ;
|
void process_device_line(void) ;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AccessPointsReaderCSV(const std::string &file_name) ;
|
AccessPointsReaderCSV(const std::string &file_name) ;
|
||||||
|
|
|
@ -39,7 +39,7 @@ Building::~Building()
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param area A pointer to the Area to add. If \em a is NULL, nothing
|
* @param area A pointer to the Area to add. If it is NULL, nothing
|
||||||
* will be added. If the Area it points to already exist in #areas, it is
|
* will be added. If the Area it points to already exist in #areas, it is
|
||||||
* deleted and nullified, unless it is the same pointer (see the code to
|
* deleted and nullified, unless it is the same pointer (see the code to
|
||||||
* understand!); hmm, maybe we should handle that with exceptions…
|
* understand!); hmm, maybe we should handle that with exceptions…
|
||||||
|
|
|
@ -30,6 +30,12 @@ CalibrationRequest(const Request &source,
|
||||||
/* *** Write accessors *** */
|
/* *** Write accessors *** */
|
||||||
|
|
||||||
|
|
||||||
|
void CalibrationRequest::reference_point_delete_requests() const
|
||||||
|
{
|
||||||
|
reference_point->delete_requests() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CalibrationRequest::reference_point_backward_link() const
|
void CalibrationRequest::reference_point_backward_link() const
|
||||||
{
|
{
|
||||||
reference_point->add_request(this) ;
|
reference_point->add_request(this) ;
|
||||||
|
|
|
@ -41,6 +41,8 @@ public:
|
||||||
void set_reference_point(const ReferencePoint *_rp) ;
|
void set_reference_point(const ReferencePoint *_rp) ;
|
||||||
/// Adds the CalibrationRequest to the #reference_point list of requests
|
/// Adds the CalibrationRequest to the #reference_point list of requests
|
||||||
void reference_point_backward_link(void) const ;
|
void reference_point_backward_link(void) const ;
|
||||||
|
/// Deletes all the requests of #reference_point
|
||||||
|
void reference_point_delete_requests(void) const ;
|
||||||
void clear(void) ;
|
void clear(void) ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
|
@ -5,5 +5,5 @@
|
||||||
Result CartographyAlgorithm::compute(const Request &request)
|
Result CartographyAlgorithm::compute(const Request &request)
|
||||||
{
|
{
|
||||||
Point3D position(select_point(request)) ;
|
Point3D position(select_point(request)) ;
|
||||||
return Result(position, name) ;
|
return Result(&request, name, position) ;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,12 @@ int Configuration::int_value(const string &key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float Configuration::float_value(const string &key)
|
||||||
|
{
|
||||||
|
return configuration[key].as<float>() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Configuration::bool_value(const string &key)
|
bool Configuration::bool_value(const string &key)
|
||||||
{
|
{
|
||||||
return configuration[key].as<bool>() ;
|
return configuration[key].as<bool>() ;
|
||||||
|
|
|
@ -21,6 +21,8 @@ public:
|
||||||
static const std::string& string_value(const std::string &key) ;
|
static const std::string& string_value(const std::string &key) ;
|
||||||
/// Returns the int value corresponding to \em key
|
/// Returns the int value corresponding to \em key
|
||||||
static int int_value(const std::string &key) ;
|
static int int_value(const std::string &key) ;
|
||||||
|
/// Returns the float value corresponding to \em key
|
||||||
|
static float float_value(const std::string &key) ;
|
||||||
/// Returns the bool value corresponding to \em key
|
/// Returns the bool value corresponding to \em key
|
||||||
static bool bool_value(const std::string &key) ;
|
static bool bool_value(const std::string &key) ;
|
||||||
/// Checks if a given string value exists in \em key
|
/// Checks if a given string value exists in \em key
|
||||||
|
|
|
@ -101,9 +101,9 @@ bool CSVFileReader::read_point3d(Point3D &p)
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
coord[i] = boost::lexical_cast<float>(*token_iterator) ;
|
coord[i] = lexical_cast<float>(*token_iterator) ;
|
||||||
}
|
}
|
||||||
catch (boost::bad_lexical_cast &e)
|
catch (bad_lexical_cast &e)
|
||||||
{
|
{
|
||||||
print_error_cast() ;
|
print_error_cast() ;
|
||||||
return false ;
|
return false ;
|
||||||
|
|
|
@ -12,7 +12,7 @@ Result FRBHMBasic::compute(const Request &_request)
|
||||||
compute_ap_distance_circles() ;
|
compute_ap_distance_circles() ;
|
||||||
Point3D position(multilaterate_2d(closest_in_ss->get_z())) ;
|
Point3D position(multilaterate_2d(closest_in_ss->get_z())) ;
|
||||||
|
|
||||||
return Result(position, name) ;
|
return Result(request, name, position) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "posexcept.hh"
|
#include "posexcept.hh"
|
||||||
#include "stock.hh"
|
#include "stock.hh"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using namespace std ;
|
using namespace std ;
|
||||||
|
@ -113,8 +114,39 @@ const Request& Input::get_next_request() const
|
||||||
{
|
{
|
||||||
if (! eof())
|
if (! eof())
|
||||||
{
|
{
|
||||||
medium->get_next_request() ;
|
const Request& request = medium->get_next_request() ;
|
||||||
log_current_request() ;
|
log_current_request() ;
|
||||||
|
|
||||||
|
// If the request is a calibration request, add it to the Stock
|
||||||
|
// (if allowed, and if it is not empty)
|
||||||
|
if (Configuration::bool_value(
|
||||||
|
"positioning.accept-new-calibration-requests")
|
||||||
|
&& request)
|
||||||
|
{
|
||||||
|
CalibrationRequest *calibration_request =
|
||||||
|
dynamic_cast<CalibrationRequest*>(
|
||||||
|
const_cast<Request*>(&request)) ;
|
||||||
|
if (calibration_request != NULL)
|
||||||
|
{
|
||||||
|
calibration_request->reference_point_delete_requests() ;
|
||||||
|
Stock::store_calibration_request(*calibration_request) ;
|
||||||
|
|
||||||
|
if (Configuration::is_configured("verbose"))
|
||||||
|
cerr
|
||||||
|
<< "Got a new calibration request (total "
|
||||||
|
<< Stock::nb_calibration_requests() << " in "
|
||||||
|
<< Stock::nb_reference_points()
|
||||||
|
<< " reference points).\n" ;
|
||||||
|
|
||||||
|
if (Configuration::bool_value(
|
||||||
|
"positioning.generate-reference-points"))
|
||||||
|
Stock::regenerate_reference_points() ;
|
||||||
|
|
||||||
|
if (! Configuration::bool_value(
|
||||||
|
"positioning.position-calibration-requests"))
|
||||||
|
medium->clear_current_request() ;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return medium->get_current_request() ;
|
return medium->get_current_request() ;
|
||||||
|
|
|
@ -45,6 +45,12 @@ const Request& InputCSV::get_next_request()
|
||||||
cerr << "InputCSV: cannot read mac_mobile.\n" ;
|
cerr << "InputCSV: cannot read mac_mobile.\n" ;
|
||||||
return *current_request ;
|
return *current_request ;
|
||||||
}
|
}
|
||||||
|
PosUtil::to_upper(mac_mobile) ;
|
||||||
|
|
||||||
|
if (! Configuration::bool_value("positioning.accept-new-mobiles") &&
|
||||||
|
! Stock::mobile_exists(mac_mobile))
|
||||||
|
return *current_request ;
|
||||||
|
|
||||||
const Mobile &mobile = Stock::find_create_mobile(mac_mobile) ;
|
const Mobile &mobile = Stock::find_create_mobile(mac_mobile) ;
|
||||||
current_request->set_mobile(&mobile) ;
|
current_request->set_mobile(&mobile) ;
|
||||||
|
|
||||||
|
@ -114,11 +120,21 @@ const Request& InputCSV::get_next_request()
|
||||||
cerr << "InputCSV: cannot read mac_ap.\n" ;
|
cerr << "InputCSV: cannot read mac_ap.\n" ;
|
||||||
return *current_request ;
|
return *current_request ;
|
||||||
}
|
}
|
||||||
|
PosUtil::to_upper(mac_ap) ;
|
||||||
|
|
||||||
|
if (! Configuration::bool_value("positioning.accept-new-aps") &&
|
||||||
|
! Stock::ap_exists(mac_ap))
|
||||||
|
continue ;
|
||||||
|
|
||||||
const AccessPoint &ap = Stock::find_create_ap(mac_ap) ;
|
const AccessPoint &ap = Stock::find_create_ap(mac_ap) ;
|
||||||
measurements[mac_ap].set_ap(&ap) ;
|
measurements[mac_ap].set_ap(&ap) ;
|
||||||
measurements[mac_ap].add_ss(ss) ;
|
measurements[mac_ap].add_ss(ss) ;
|
||||||
}
|
}
|
||||||
|
if (measurements.empty())
|
||||||
|
{
|
||||||
|
current_request->clear() ;
|
||||||
|
return *current_request ;
|
||||||
|
}
|
||||||
current_request->set_measurements(measurements) ;
|
current_request->set_measurements(measurements) ;
|
||||||
|
|
||||||
// Calibration request?
|
// Calibration request?
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "inputdatareader.hh"
|
#include "inputdatareader.hh"
|
||||||
#include "accesspointsreadercsv.hh"
|
#include "accesspointsreadercsv.hh"
|
||||||
|
#include "mobilesreadercsv.hh"
|
||||||
#include "topologyreadercsv.hh"
|
#include "topologyreadercsv.hh"
|
||||||
#include "inputcsv.hh"
|
#include "inputcsv.hh"
|
||||||
#include "calibrationrequest.hh"
|
#include "calibrationrequest.hh"
|
||||||
|
@ -19,6 +20,7 @@ using namespace std ;
|
||||||
InputDataReader::InputDataReader()
|
InputDataReader::InputDataReader()
|
||||||
{
|
{
|
||||||
read_access_points() ;
|
read_access_points() ;
|
||||||
|
read_mobiles() ;
|
||||||
read_topology() ;
|
read_topology() ;
|
||||||
read_reference_points() ;
|
read_reference_points() ;
|
||||||
}
|
}
|
||||||
|
@ -80,6 +82,51 @@ void InputDataReader::initialise_access_points_csv()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Mobiles *** */
|
||||||
|
|
||||||
|
|
||||||
|
void InputDataReader::read_mobiles()
|
||||||
|
{
|
||||||
|
if (! Configuration::is_configured("data-input.mobile-medium"))
|
||||||
|
return ;
|
||||||
|
|
||||||
|
initialise_mobiles_media() ;
|
||||||
|
|
||||||
|
if (Configuration::is_configured("verbose"))
|
||||||
|
cerr << Stock::nb_mobiles() << " mobiles stored.\n" ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InputDataReader::initialise_mobiles_media()
|
||||||
|
{
|
||||||
|
const vector<string> &media_names =
|
||||||
|
Configuration::string_vector_value("data-input.mobile-medium") ;
|
||||||
|
|
||||||
|
for (vector<string>::const_iterator i = media_names.begin() ;
|
||||||
|
i != media_names.end() ; ++i)
|
||||||
|
{
|
||||||
|
if (*i == "CSV")
|
||||||
|
initialise_mobiles_csv() ;
|
||||||
|
|
||||||
|
else
|
||||||
|
throw bad_configuration(
|
||||||
|
"Mobiles' input medium type unknown « "+ *i +" »") ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void InputDataReader::initialise_mobiles_csv()
|
||||||
|
{
|
||||||
|
if (! Configuration::is_configured("data-input.mobile-csv-file"))
|
||||||
|
throw missing_configuration(
|
||||||
|
"No input CSV file specified for mobiles") ;
|
||||||
|
|
||||||
|
MobilesReaderCSV(
|
||||||
|
Configuration::string_value("data-input.mobile-csv-file")) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *** Topology *** */
|
/* *** Topology *** */
|
||||||
|
|
||||||
|
|
||||||
|
@ -193,27 +240,18 @@ void InputDataReader::read_from_reference_points_media()
|
||||||
while (! (*i)->eof())
|
while (! (*i)->eof())
|
||||||
{
|
{
|
||||||
const Request &request = (*i)->get_next_request() ;
|
const Request &request = (*i)->get_next_request() ;
|
||||||
|
|
||||||
if (! request)
|
if (! request)
|
||||||
continue ;
|
continue ;
|
||||||
|
|
||||||
CalibrationRequest *calibration_request =
|
CalibrationRequest *calibration_request =
|
||||||
dynamic_cast<CalibrationRequest*>(
|
dynamic_cast<CalibrationRequest*>(
|
||||||
const_cast<Request*>(&request)) ;
|
const_cast<Request*>(&request)) ;
|
||||||
|
|
||||||
if (calibration_request == NULL)
|
if (calibration_request == NULL)
|
||||||
cerr << "Warning! Invalid calibration request at line "
|
cerr << "Warning! Invalid calibration request at line "
|
||||||
<< (*i)->get_current_line_nb() << endl ;
|
<< (*i)->get_current_line_nb() << endl ;
|
||||||
else
|
else
|
||||||
stock_calibration_request(*calibration_request) ;
|
Stock::store_calibration_request(*calibration_request) ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InputDataReader::
|
|
||||||
stock_calibration_request(const CalibrationRequest &request) const
|
|
||||||
{
|
|
||||||
const CalibrationRequest &calibration_request =
|
|
||||||
Stock::find_create_calibration_request(request) ;
|
|
||||||
|
|
||||||
calibration_request.reference_point_backward_link() ;
|
|
||||||
}
|
|
||||||
|
|
|
@ -16,6 +16,10 @@ protected:
|
||||||
void initialise_access_points_media(void) ;
|
void initialise_access_points_media(void) ;
|
||||||
void initialise_access_points_csv(void) ;
|
void initialise_access_points_csv(void) ;
|
||||||
|
|
||||||
|
void read_mobiles(void) ;
|
||||||
|
void initialise_mobiles_media(void) ;
|
||||||
|
void initialise_mobiles_csv(void) ;
|
||||||
|
|
||||||
void read_topology(void) ;
|
void read_topology(void) ;
|
||||||
void initialise_topology_media(void) ;
|
void initialise_topology_media(void) ;
|
||||||
void initialise_topology_csv(void) ;
|
void initialise_topology_csv(void) ;
|
||||||
|
@ -24,8 +28,6 @@ protected:
|
||||||
void initialise_reference_points_media(void) ;
|
void initialise_reference_points_media(void) ;
|
||||||
void initialise_reference_points_csv(void) ;
|
void initialise_reference_points_csv(void) ;
|
||||||
void read_from_reference_points_media(void) ;
|
void read_from_reference_points_media(void) ;
|
||||||
void stock_calibration_request(
|
|
||||||
const CalibrationRequest &request) const ;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InputDataReader(void) ;
|
InputDataReader(void) ;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "inputudpsocket.hh"
|
#include "inputudpsocket.hh"
|
||||||
#include "posexcept.hh"
|
#include "posexcept.hh"
|
||||||
#include "stock.hh"
|
#include "stock.hh"
|
||||||
|
#include "configuration.hh"
|
||||||
|
|
||||||
#include <owlps.h>
|
#include <owlps.h>
|
||||||
|
|
||||||
|
@ -106,8 +107,14 @@ const Request& InputUDPSocket::get_next_request()
|
||||||
request.nb_info = ntohs(request.nb_info) ;
|
request.nb_info = ntohs(request.nb_info) ;
|
||||||
|
|
||||||
// Mobile MAC
|
// Mobile MAC
|
||||||
const char *const mac_mobile =
|
string mac_mobile(
|
||||||
owl_mac_bytes_to_string(request.mobile_mac_addr_bytes) ;
|
owl_mac_bytes_to_string(request.mobile_mac_addr_bytes)) ;
|
||||||
|
PosUtil::to_upper(mac_mobile) ;
|
||||||
|
|
||||||
|
if (! Configuration::bool_value("positioning.accept-new-mobiles") &&
|
||||||
|
! Stock::mobile_exists(mac_mobile))
|
||||||
|
return *current_request ;
|
||||||
|
|
||||||
const Mobile &mobile = Stock::find_create_mobile(mac_mobile) ;
|
const Mobile &mobile = Stock::find_create_mobile(mac_mobile) ;
|
||||||
current_request->set_mobile(&mobile) ;
|
current_request->set_mobile(&mobile) ;
|
||||||
|
|
||||||
|
@ -135,20 +142,50 @@ const Request& InputUDPSocket::get_next_request()
|
||||||
current_request->clear() ;
|
current_request->clear() ;
|
||||||
return *current_request ;
|
return *current_request ;
|
||||||
}
|
}
|
||||||
const char *const mac_ap =
|
string mac_ap(
|
||||||
owl_mac_bytes_to_string(request_info.ap_mac_addr_bytes) ;
|
owl_mac_bytes_to_string(request_info.ap_mac_addr_bytes)) ;
|
||||||
|
PosUtil::to_upper(mac_ap) ;
|
||||||
|
|
||||||
|
if (! Configuration::bool_value("positioning.accept-new-aps") &&
|
||||||
|
! Stock::ap_exists(mac_ap))
|
||||||
|
continue ;
|
||||||
|
|
||||||
const AccessPoint &ap = Stock::find_create_ap(mac_ap) ;
|
const AccessPoint &ap = Stock::find_create_ap(mac_ap) ;
|
||||||
measurements[mac_ap].set_ap(&ap) ;
|
measurements[mac_ap].set_ap(&ap) ;
|
||||||
measurements[mac_ap].add_ss(static_cast<int_fast8_t>
|
measurements[mac_ap].add_ss(static_cast<int_fast8_t>
|
||||||
(request_info.antenna_signal_dbm)) ;
|
(request_info.antenna_signal_dbm)) ;
|
||||||
}
|
}
|
||||||
|
if (measurements.empty())
|
||||||
|
{
|
||||||
|
current_request->clear() ;
|
||||||
|
return *current_request ;
|
||||||
|
}
|
||||||
current_request->set_measurements(measurements) ;
|
current_request->set_measurements(measurements) ;
|
||||||
|
|
||||||
// Calibration request?
|
// Calibration request?
|
||||||
if (request.type == OWL_REQUEST_CALIBRATION ||
|
if ((request.type == OWL_REQUEST_CALIBRATION ||
|
||||||
request.type == OWL_REQUEST_AUTOCALIBRATION)
|
request.type == OWL_REQUEST_AUTOCALIBRATION)
|
||||||
|
&&
|
||||||
|
(Configuration::bool_value("positioning.accept-new-aps") ||
|
||||||
|
Stock::ap_exists(mac_mobile)))
|
||||||
{
|
{
|
||||||
|
AccessPoint &transmitter =
|
||||||
|
const_cast<AccessPoint&>(Stock::find_create_ap(mac_mobile)) ;
|
||||||
|
|
||||||
|
// 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 =
|
const ReferencePoint &reference_point =
|
||||||
Stock::find_create_reference_point(position) ;
|
Stock::find_create_reference_point(position) ;
|
||||||
current_request_to_calibration_request(&reference_point,
|
current_request_to_calibration_request(&reference_point,
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include "mobilesreadercsv.hh"
|
||||||
|
#include "point3d.hh"
|
||||||
|
#include "stock.hh"
|
||||||
|
#include "posexcept.hh"
|
||||||
|
|
||||||
|
using namespace std ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Constructors *** */
|
||||||
|
|
||||||
|
|
||||||
|
MobilesReaderCSV::MobilesReaderCSV(const string &file_name):
|
||||||
|
file(file_name)
|
||||||
|
{
|
||||||
|
read_devices() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Operations *** */
|
||||||
|
|
||||||
|
|
||||||
|
void MobilesReaderCSV::read_devices()
|
||||||
|
{
|
||||||
|
while (file.next_line())
|
||||||
|
process_device_line() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MobilesReaderCSV::process_device_line()
|
||||||
|
{
|
||||||
|
string mac ;
|
||||||
|
if (! file.read_field(mac))
|
||||||
|
throw malformed_input_data("Cannot read mobile's MAC address!") ;
|
||||||
|
PosUtil::to_upper(mac) ;
|
||||||
|
|
||||||
|
float gain ;
|
||||||
|
if (! file.read_field(gain))
|
||||||
|
throw malformed_input_data("Cannot read mobile's gain!") ;
|
||||||
|
|
||||||
|
float power ;
|
||||||
|
if (! file.read_field(power))
|
||||||
|
throw malformed_input_data("Cannot read mobile's power!") ;
|
||||||
|
|
||||||
|
string ip("") ;
|
||||||
|
|
||||||
|
Mobile device(ip, mac, gain, power) ;
|
||||||
|
Stock::find_create_mobile(device) ;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef _OWLPS_POSITIONING_MOBILESREADERCSV_HH_
|
||||||
|
#define _OWLPS_POSITIONING_MOBILESREADERCSV_HH_
|
||||||
|
|
||||||
|
class Point3D ;
|
||||||
|
|
||||||
|
#include "csvfilereader.hh"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
/// Reads and registers to the Stock Mobile list from CSV files
|
||||||
|
/**
|
||||||
|
* CSV format for access points is:
|
||||||
|
* MAC;Antenna_gain_dBi;Trx_power_dBm
|
||||||
|
*/
|
||||||
|
class MobilesReaderCSV
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
CSVFileReader file ;
|
||||||
|
|
||||||
|
void read_devices(void) ;
|
||||||
|
void process_device_line(void) ;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MobilesReaderCSV(const std::string &file_name) ;
|
||||||
|
|
||||||
|
~MobilesReaderCSV(void) {}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
#endif // _OWLPS_POSITIONING_MOBILESREADERCSV_HH_
|
|
@ -70,7 +70,7 @@ Result MultilaterationAlgorithm::compute(const Request &_request)
|
||||||
compute_ap_distance_circles() ;
|
compute_ap_distance_circles() ;
|
||||||
Point3D position(multilaterate()) ;
|
Point3D position(multilaterate()) ;
|
||||||
|
|
||||||
return Result(position, name) ;
|
return Result(request, name, position) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "outputterminal.hh"
|
#include "outputterminal.hh"
|
||||||
#include "outputcsv.hh"
|
#include "outputcsv.hh"
|
||||||
#include "outputudpsocket.hh"
|
#include "outputudpsocket.hh"
|
||||||
|
#include "outputtcpsocketevaal.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -57,6 +58,9 @@ void Output::initialise_output_media()
|
||||||
else if (*i == "UDP")
|
else if (*i == "UDP")
|
||||||
initialise_output_udp_socket() ;
|
initialise_output_udp_socket() ;
|
||||||
|
|
||||||
|
else if (*i == "TCPEvAAL")
|
||||||
|
initialise_output_tcpevaal_socket() ;
|
||||||
|
|
||||||
else
|
else
|
||||||
throw bad_configuration(
|
throw bad_configuration(
|
||||||
"The specified output medium « "+ *i +" » is unknown!") ;
|
"The specified output medium « "+ *i +" » is unknown!") ;
|
||||||
|
@ -70,18 +74,6 @@ void Output::initialise_output_terminal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Output::initialise_output_udp_socket()
|
|
||||||
{
|
|
||||||
if (! Configuration::is_configured("output.udp-host"))
|
|
||||||
throw missing_configuration(
|
|
||||||
"No remote UDP host specified in the configuration!") ;
|
|
||||||
|
|
||||||
output_media.push_back(
|
|
||||||
new OutputUDPSocket(Configuration::string_value("output.udp-host"),
|
|
||||||
Configuration::int_value("output.udp-port"))) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Output::initialise_output_csv()
|
void Output::initialise_output_csv()
|
||||||
{
|
{
|
||||||
if (! Configuration::is_configured("output.csv-file"))
|
if (! Configuration::is_configured("output.csv-file"))
|
||||||
|
@ -94,6 +86,27 @@ void Output::initialise_output_csv()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Output::initialise_output_udp_socket()
|
||||||
|
{
|
||||||
|
if (! Configuration::is_configured("output.udp-host"))
|
||||||
|
throw missing_configuration(
|
||||||
|
"No remote UDP host specified in the configuration!") ;
|
||||||
|
|
||||||
|
output_media.push_back(
|
||||||
|
new OutputUDPSocket(Configuration::string_value("output.udp-host"),
|
||||||
|
Configuration::int_value("output.udp-port"))) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Output::initialise_output_tcpevaal_socket()
|
||||||
|
{
|
||||||
|
output_media.push_back(
|
||||||
|
new OutputTCPSocketEvAAL(
|
||||||
|
Configuration::string_value("output.tcpevaal-host"),
|
||||||
|
Configuration::int_value("output.tcpevaal-port"))) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Output::write(const ResultList &results) const
|
void Output::write(const ResultList &results) const
|
||||||
{
|
{
|
||||||
for (vector<OutputMedium*>::const_iterator i = output_media.begin() ;
|
for (vector<OutputMedium*>::const_iterator i = output_media.begin() ;
|
||||||
|
|
|
@ -19,6 +19,7 @@ protected:
|
||||||
void initialise_output_terminal(void) ;
|
void initialise_output_terminal(void) ;
|
||||||
void initialise_output_csv(void) ;
|
void initialise_output_csv(void) ;
|
||||||
void initialise_output_udp_socket(void) ;
|
void initialise_output_udp_socket(void) ;
|
||||||
|
void initialise_output_tcpevaal_socket(void) ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -11,5 +11,6 @@ void OutputCSV::write(const Result &result)
|
||||||
|
|
||||||
void OutputCSV::write(const ResultList &results)
|
void OutputCSV::write(const ResultList &results)
|
||||||
{
|
{
|
||||||
file.write_text(results.to_csv() + '\n') ;
|
if (! results.empty())
|
||||||
|
file.write_text(results.to_csv() + '\n') ;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
#include "outputtcpsocketevaal.hh"
|
||||||
|
#include "request.hh"
|
||||||
|
#include "resultlist.hh"
|
||||||
|
#include "area.hh"
|
||||||
|
#include "stock.hh"
|
||||||
|
#include "posexcept.hh"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <cstdio> // For perror()
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
|
using namespace std ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Constructors *** */
|
||||||
|
|
||||||
|
|
||||||
|
OutputTCPSocketEvAAL::OutputTCPSocketEvAAL(
|
||||||
|
const string &_remote_host,
|
||||||
|
const uint_fast16_t _remote_port):
|
||||||
|
remote_host(_remote_host), remote_port(_remote_port)
|
||||||
|
{
|
||||||
|
if (! init_socket())
|
||||||
|
throw error_opening_output_file("TCP socket") ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OutputTCPSocketEvAAL::~OutputTCPSocketEvAAL()
|
||||||
|
{
|
||||||
|
close_socket() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Operations *** */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \em true if the socket were successfully opened.
|
||||||
|
* @return \em false in case of error.
|
||||||
|
*/
|
||||||
|
bool OutputTCPSocketEvAAL::init_socket()
|
||||||
|
{
|
||||||
|
sockfd = socket(AF_INET, SOCK_STREAM, 0) ;
|
||||||
|
if (sockfd < 0)
|
||||||
|
{
|
||||||
|
perror("TCP socket creation failed") ;
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in server_description ;
|
||||||
|
memset(&server_description, 0, sizeof(server_description)) ;
|
||||||
|
server_description.sin_family = AF_INET ;
|
||||||
|
// Server IP address:
|
||||||
|
server_description.sin_addr.s_addr = inet_addr(remote_host.c_str()) ;
|
||||||
|
// Listening port on the server:
|
||||||
|
server_description.sin_port = htons(remote_port) ;
|
||||||
|
|
||||||
|
int ret = connect(sockfd, (struct sockaddr *)&server_description,
|
||||||
|
sizeof(server_description)) ;
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
perror("Cannot bind the TCP socket") ;
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
void OutputTCPSocketEvAAL::write(const ResultList &results)
|
||||||
|
{
|
||||||
|
assert(results.get_results().size() == 1) ;
|
||||||
|
write(results.get_results()[0]) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void OutputTCPSocketEvAAL::write(const Result &result)
|
||||||
|
{
|
||||||
|
const Point3D &position = result.get_position() ;
|
||||||
|
Timestamp request_time = result.get_request()->get_time_sent() ;
|
||||||
|
int area_of_interest = area_of_interest_number(position) ;
|
||||||
|
|
||||||
|
ostringstream str ;
|
||||||
|
str
|
||||||
|
<< "OwlPS "
|
||||||
|
<< position.get_x() << ' '
|
||||||
|
<< position.get_y() << ' '
|
||||||
|
<< static_cast<uint64_t>(request_time) << ' '
|
||||||
|
<< area_of_interest << '\n' ;
|
||||||
|
|
||||||
|
if (send_data(str.str()))
|
||||||
|
acknowledge() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int OutputTCPSocketEvAAL::
|
||||||
|
area_of_interest_number(const Point3D &position) const
|
||||||
|
{
|
||||||
|
const Area *area = Stock::in_which_area_is(position) ;
|
||||||
|
if (area == NULL)
|
||||||
|
return 0 ;
|
||||||
|
|
||||||
|
int aoi_number = 0 ;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
aoi_number = boost::lexical_cast<int>(area->get_name()) ;
|
||||||
|
}
|
||||||
|
catch (boost::bad_lexical_cast &e)
|
||||||
|
{
|
||||||
|
cerr
|
||||||
|
<< "Cannot convert the area of interest's name (« "
|
||||||
|
<< area->get_name() << " ») into an integer value: "
|
||||||
|
<< e.what() << '\n' ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return aoi_number ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the text buffer 'data'.
|
||||||
|
*/
|
||||||
|
bool OutputTCPSocketEvAAL::send_data(const string &data) const
|
||||||
|
{
|
||||||
|
ssize_t nsent = send(sockfd, data.c_str(), data.size(), 0) ;
|
||||||
|
if (nsent != static_cast<ssize_t>(data.size()))
|
||||||
|
{
|
||||||
|
perror("Error sending result data") ;
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
return true ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool OutputTCPSocketEvAAL::acknowledge() const
|
||||||
|
{
|
||||||
|
char ack_buf[10] ;
|
||||||
|
ssize_t nrecv = recv(sockfd, ack_buf, 10, 0) ;
|
||||||
|
if (nrecv < 0)
|
||||||
|
perror("Error receiving acknowledgement") ;
|
||||||
|
|
||||||
|
ack_buf[9] = '\0' ;
|
||||||
|
string ack(ack_buf) ;
|
||||||
|
if (ack == "Published")
|
||||||
|
return true ;
|
||||||
|
|
||||||
|
if (ack == "NotParsed")
|
||||||
|
{
|
||||||
|
cerr << "TCP server error: string not parsed.\n" ;
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
cerr
|
||||||
|
<< "TCP server error: unknown acknoledgment string « "
|
||||||
|
<< ack << " ».\n" ;
|
||||||
|
return false ;
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
#ifndef _OWLPS_POSITIONING_OUTPUTTCPSOCKETEVAAL_HH_
|
||||||
|
#define _OWLPS_POSITIONING_OUTPUTTCPSOCKETEVAAL_HH_
|
||||||
|
|
||||||
|
class Point3D ;
|
||||||
|
|
||||||
|
#include "outputmedium.hh"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <stdint.h> // <cstdint> is not C++ 98 compliant
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
{
|
||||||
|
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) ;
|
||||||
|
/// Sends a string through the socket
|
||||||
|
bool send_data(const std::string &data) const ;
|
||||||
|
/// Receives and parse the acknowledgement from the server
|
||||||
|
bool acknowledge(void) const ;
|
||||||
|
//@}
|
||||||
|
|
||||||
|
public:
|
||||||
|
OutputTCPSocketEvAAL(const std::string &_remote_host,
|
||||||
|
const uint_fast16_t _remote_port) ;
|
||||||
|
~OutputTCPSocketEvAAL(void) ;
|
||||||
|
|
||||||
|
/** @name Operations */
|
||||||
|
//@{
|
||||||
|
void write(const ResultList &results) ;
|
||||||
|
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) ;
|
||||||
|
//@}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _OWLPS_POSITIONING_OUTPUTTCPSOCKETEVAAL_HH_
|
|
@ -1,5 +1,6 @@
|
||||||
#include "outputterminal.hh"
|
#include "outputterminal.hh"
|
||||||
#include "resultlist.hh"
|
#include "resultlist.hh"
|
||||||
|
#include "configuration.hh"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,5 +13,10 @@ void OutputTerminal::write(const Result &result)
|
||||||
|
|
||||||
void OutputTerminal::write(const ResultList &results)
|
void OutputTerminal::write(const ResultList &results)
|
||||||
{
|
{
|
||||||
output_stream << results << '\n' ;
|
if (results.empty())
|
||||||
|
output_stream << "There is no result.\n" ;
|
||||||
|
else
|
||||||
|
output_stream << results << '\n' ;
|
||||||
|
if (Configuration::bool_value("flush-output-files"))
|
||||||
|
output_stream << std::flush ;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,8 @@ void OutputUDPSocket::write(const Result &result)
|
||||||
|
|
||||||
void OutputUDPSocket::write(const ResultList &results)
|
void OutputUDPSocket::write(const ResultList &results)
|
||||||
{
|
{
|
||||||
send_data(results.to_csv()) ;
|
if (! results.empty())
|
||||||
|
send_data(results.to_csv()) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "point3d.hh"
|
#include "point3d.hh"
|
||||||
|
#include "posutil.hh"
|
||||||
#include "posexcept.hh"
|
#include "posexcept.hh"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
@ -61,6 +62,33 @@ float Point3D::square_distance(const float _x,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A, B and C are three points, A being the current Point3D (*this).
|
||||||
|
* If the points are aligned, the angle returned is always 0° (and not
|
||||||
|
* 180°, even in the case where A is on BC).
|
||||||
|
* @returns The angle BÂC, in the interval [0, 180] degrees.
|
||||||
|
*/
|
||||||
|
double Point3D::angle(const Point3D &b, const Point3D &c) const
|
||||||
|
{
|
||||||
|
double
|
||||||
|
sq_ab = square_distance(b),
|
||||||
|
sq_ac = square_distance(c),
|
||||||
|
sq_bc = b.square_distance(c) ;
|
||||||
|
|
||||||
|
if (sq_ab == 0 || sq_ac == 0 || sq_bc == 0)
|
||||||
|
return 0 ;
|
||||||
|
|
||||||
|
double
|
||||||
|
ab = sqrt(sq_ab),
|
||||||
|
ac = sqrt(sq_ac) ;
|
||||||
|
|
||||||
|
double cos_bac = (sq_ab + sq_ac - sq_bc) / (2 * ab * ac) ;
|
||||||
|
double bac = acos(cos_bac) ;
|
||||||
|
|
||||||
|
return PosUtil::rad2deg(bac) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *** Operators *** */
|
/* *** Operators *** */
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
void set_coordinates(const Point3D &source) ;
|
void set_coordinates(const Point3D &source) ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/** @name Distance operations */
|
/** @name Distance & angles operations */
|
||||||
//@{
|
//@{
|
||||||
/// Square euclidean distance to a Point3D
|
/// Square euclidean distance to a Point3D
|
||||||
float square_distance(const Point3D &p) const ;
|
float square_distance(const Point3D &p) const ;
|
||||||
|
@ -61,6 +61,8 @@ public:
|
||||||
/// Euclidean distance to the radius of a sphere
|
/// Euclidean distance to the radius of a sphere
|
||||||
float distance_to_sphere(const Point3D ¢re,
|
float distance_to_sphere(const Point3D ¢re,
|
||||||
const float radius) const ;
|
const float radius) const ;
|
||||||
|
/// Angle BÂC (A being *this)
|
||||||
|
double angle(const Point3D &b, const Point3D &c) const ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/** @name Operators */
|
/** @name Operators */
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include <owlps.h>
|
#include <owlps.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace std ;
|
using namespace std ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -97,7 +99,21 @@ void Positioning::loop()
|
||||||
for (algo = algorithms.begin() ; algo != algorithms.end() ;
|
for (algo = algorithms.begin() ; algo != algorithms.end() ;
|
||||||
++algo)
|
++algo)
|
||||||
{
|
{
|
||||||
Result res((*algo)->compute(request)) ;
|
Result res ;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
res = (*algo)->compute(request) ;
|
||||||
|
}
|
||||||
|
catch (exception &e)
|
||||||
|
{
|
||||||
|
cerr
|
||||||
|
<< "Cannot compute with algorithm "
|
||||||
|
<< (*algo)->get_name() << ": « "
|
||||||
|
<< e.what() << " »\n" ;
|
||||||
|
continue ;
|
||||||
|
}
|
||||||
|
|
||||||
if (compute_error)
|
if (compute_error)
|
||||||
res.compute_error(real_position) ;
|
res.compute_error(real_position) ;
|
||||||
else if ((*algo)->get_name() == "Real")
|
else if ((*algo)->get_name() == "Real")
|
||||||
|
@ -105,6 +121,7 @@ void Positioning::loop()
|
||||||
compute_error = true ;
|
compute_error = true ;
|
||||||
real_position = res.get_position() ;
|
real_position = res.get_position() ;
|
||||||
}
|
}
|
||||||
|
|
||||||
results.add(res) ;
|
results.add(res) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,23 @@
|
||||||
|
|
||||||
#include <owlps.h>
|
#include <owlps.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
using namespace std ;
|
using namespace std ;
|
||||||
using std::tr1::unordered_map ;
|
using std::tr1::unordered_map ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Maths *** */
|
||||||
|
|
||||||
|
|
||||||
|
double PosUtil::rad2deg(const double &radians)
|
||||||
|
{
|
||||||
|
return radians * (180.0 / M_PI) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *** Measurements *** */
|
/* *** Measurements *** */
|
||||||
|
|
||||||
|
|
||||||
|
@ -151,3 +163,21 @@ unsigned long PosUtil::wifi_channel_to_hz(const unsigned long &channel)
|
||||||
// Error: wrong channel value
|
// Error: wrong channel value
|
||||||
throw bad_channel(channel) ;
|
throw bad_channel(channel) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Strings *** */
|
||||||
|
|
||||||
|
|
||||||
|
string PosUtil::int_to_mac(const uint32_t source)
|
||||||
|
{
|
||||||
|
uint8_t bytes[6] ;
|
||||||
|
memset(bytes, 0, 6) ;
|
||||||
|
for (int i = 0 ; i < 4 ; ++i)
|
||||||
|
bytes[i+2] = reinterpret_cast<const uint8_t*>(&source)[i] ;
|
||||||
|
char mac_cstr[OWL_ETHER_ADDR_STRLEN] ;
|
||||||
|
owl_mac_bytes_to_string_r(bytes, mac_cstr) ;
|
||||||
|
string mac(mac_cstr) ;
|
||||||
|
to_upper(mac) ;
|
||||||
|
return mac ;
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
class Measurement ;
|
class Measurement ;
|
||||||
|
|
||||||
#include <boost/tr1/unordered_map.hpp>
|
#include <boost/tr1/unordered_map.hpp>
|
||||||
|
#include <boost/algorithm/string/case_conv.hpp>
|
||||||
|
|
||||||
/// Utilitary class
|
/// Utilitary class
|
||||||
class PosUtil
|
class PosUtil
|
||||||
|
@ -12,6 +13,12 @@ public:
|
||||||
/// The speed of light, in m/s
|
/// The speed of light, in m/s
|
||||||
static const unsigned long LIGHT_SPEED = 299792458 ;
|
static const unsigned long LIGHT_SPEED = 299792458 ;
|
||||||
|
|
||||||
|
/** @name Maths */
|
||||||
|
//@{
|
||||||
|
/// Return the degree value of \em radians
|
||||||
|
static double rad2deg(const double &radians) ;
|
||||||
|
//@}
|
||||||
|
|
||||||
/** @name Measurements */
|
/** @name Measurements */
|
||||||
//@{
|
//@{
|
||||||
/// Mutually completes two Measurement lists with missing APs
|
/// Mutually completes two Measurement lists with missing APs
|
||||||
|
@ -29,6 +36,35 @@ public:
|
||||||
/// Converts a Wi-Fi channel to the corresponding frequency in Hz
|
/// Converts a Wi-Fi channel to the corresponding frequency in Hz
|
||||||
static unsigned long wifi_channel_to_hz(const unsigned long &channel) ;
|
static unsigned long wifi_channel_to_hz(const unsigned long &channel) ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
/** @name Strings */
|
||||||
|
//@{
|
||||||
|
static void to_upper(std::string &str) ;
|
||||||
|
static void assert_uppercase(const std::string &str) ;
|
||||||
|
static std::string int_to_mac(const uint32_t source) ;
|
||||||
|
//@}
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Strings *** */
|
||||||
|
|
||||||
|
|
||||||
|
inline void PosUtil::to_upper(std::string &str)
|
||||||
|
{
|
||||||
|
boost::to_upper(str) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void PosUtil::assert_uppercase(const std::string &str)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
std::string str_up(str) ;
|
||||||
|
to_upper(str_up) ;
|
||||||
|
assert(str_up == str) ;
|
||||||
|
#endif // NDEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // _OWLPS_POSITIONING_POSUTIL_HH_
|
#endif // _OWLPS_POSITIONING_POSUTIL_HH_
|
||||||
|
|
|
@ -17,7 +17,7 @@ Result RealPosition::compute(const Request &request)
|
||||||
|
|
||||||
coordinates = request.get_real_position() ;
|
coordinates = request.get_real_position() ;
|
||||||
if (coordinates)
|
if (coordinates)
|
||||||
return Result(*coordinates, name) ;
|
return Result(&request, name, *coordinates) ;
|
||||||
|
|
||||||
return Result(name) ;
|
return Result(&request, name) ;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,26 @@ ReferencePoint::~ReferencePoint()
|
||||||
/* *** Accessors *** */
|
/* *** Accessors *** */
|
||||||
|
|
||||||
|
|
||||||
|
double ReferencePoint::
|
||||||
|
average_measurements(const std::string &mac_transmitter) const
|
||||||
|
{
|
||||||
|
unordered_map<string, Measurement> measurements(
|
||||||
|
get_all_measurements(mac_transmitter)) ;
|
||||||
|
double avg = 0 ;
|
||||||
|
int n_ss = 0 ;
|
||||||
|
|
||||||
|
for (unordered_map<string, Measurement>::const_iterator i =
|
||||||
|
measurements.begin() ;
|
||||||
|
i != measurements.end() ; ++i)
|
||||||
|
{
|
||||||
|
avg += i->second.get_average_ss() ;
|
||||||
|
++n_ss ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (avg / n_ss) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
unordered_map<string, Measurement> ReferencePoint::
|
unordered_map<string, Measurement> ReferencePoint::
|
||||||
get_all_measurements() const
|
get_all_measurements() const
|
||||||
{
|
{
|
||||||
|
@ -45,6 +65,109 @@ get_all_measurements() const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unordered_map<string, Measurement> ReferencePoint::
|
||||||
|
get_all_measurements(const string &mac_transmitter) const
|
||||||
|
{
|
||||||
|
unordered_map<string, Measurement> all ;
|
||||||
|
vector<CalibrationRequest*> requests_trx(
|
||||||
|
get_requests(mac_transmitter)) ;
|
||||||
|
|
||||||
|
for (vector<CalibrationRequest*>::const_iterator i =
|
||||||
|
requests_trx.begin() ;
|
||||||
|
i != requests_trx.end() ; ++i)
|
||||||
|
{
|
||||||
|
unordered_map<string, Measurement> measurements =
|
||||||
|
(*i)->get_measurements() ;
|
||||||
|
for (unordered_map<string, Measurement>::const_iterator j =
|
||||||
|
measurements.begin() ; j != measurements.end() ; ++j)
|
||||||
|
if (! all.insert(*j).second)
|
||||||
|
all[j->first].merge(j->second) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return all ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mac_transmitter The MAC address of the transmitting mobile.
|
||||||
|
* @return A vector containing all the requests sent by the mobile.
|
||||||
|
* The returned vector is empty if no request was sent by the mobile.
|
||||||
|
*/
|
||||||
|
const vector<CalibrationRequest*> ReferencePoint::
|
||||||
|
get_requests(const string &mac_transmitter) const
|
||||||
|
{
|
||||||
|
vector<CalibrationRequest*> res ;
|
||||||
|
|
||||||
|
for (vector<CalibrationRequest*>::const_iterator i = requests.begin() ;
|
||||||
|
i != requests.end() ; ++i)
|
||||||
|
if ((*i)->get_mobile()->get_mac_addr() == mac_transmitter)
|
||||||
|
res.push_back(*i) ;
|
||||||
|
|
||||||
|
return res ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that the requests pointed by the elements of #requests are
|
||||||
|
* actually deleted from the Stock.
|
||||||
|
*/
|
||||||
|
void ReferencePoint::delete_requests()
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
int stock_nb_requests = Stock::nb_calibration_requests() ;
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
for (vector<CalibrationRequest*>::iterator r = requests.begin() ;
|
||||||
|
r != requests.end() ; ++r)
|
||||||
|
Stock::delete_calibration_request(**r) ;
|
||||||
|
|
||||||
|
assert(Stock::nb_calibration_requests() ==
|
||||||
|
stock_nb_requests - requests.size()) ;
|
||||||
|
|
||||||
|
requests.clear() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that the requests pointed by the elements of #requests are
|
||||||
|
* actually deleted from the Stock.
|
||||||
|
* @returns \em true if at least one request was deleted.
|
||||||
|
* @returns \em false if the ReferencePoint was left untouched.
|
||||||
|
*/
|
||||||
|
bool ReferencePoint::delete_generated_requests(void)
|
||||||
|
{
|
||||||
|
unsigned int nb_requests = requests.size() ;
|
||||||
|
vector<CalibrationRequest*>::iterator r = requests.begin() ;
|
||||||
|
while (r != requests.end())
|
||||||
|
{
|
||||||
|
assert(*r) ;
|
||||||
|
unordered_map<std::string, AccessPoint>::const_iterator ap ;
|
||||||
|
|
||||||
|
if ((*r)->get_mobile() == NULL)
|
||||||
|
goto delete_request ;
|
||||||
|
|
||||||
|
for (ap = Stock::get_aps().begin() ; ap != Stock::get_aps().end() ;
|
||||||
|
++ap)
|
||||||
|
if ((*r)->get_mobile()->get_mac_addr() ==
|
||||||
|
ap->second.get_mac_addr())
|
||||||
|
break ;
|
||||||
|
|
||||||
|
if (ap != Stock::get_aps().end()) // r still associated with an AP
|
||||||
|
{
|
||||||
|
++r ;
|
||||||
|
continue ; // Do not delete r
|
||||||
|
}
|
||||||
|
|
||||||
|
// r is not assotiated with an AP, delete it
|
||||||
|
delete_request:
|
||||||
|
Stock::delete_calibration_request(**r) ;
|
||||||
|
r = requests.erase(r) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nb_requests != requests.size() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *** Operations *** */
|
/* *** Operations *** */
|
||||||
|
|
||||||
|
@ -115,6 +238,7 @@ float ReferencePoint::friis_indexes_for_ap(
|
||||||
double friis_idx_sum = 0 ;
|
double friis_idx_sum = 0 ;
|
||||||
|
|
||||||
const string &ap_mac = ap.get_mac_addr() ;
|
const string &ap_mac = ap.get_mac_addr() ;
|
||||||
|
float distance = this->distance(ap.get_coordinates()) ;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute an index for each Measurement in each Request in the
|
* Compute an index for each Measurement in each Request in the
|
||||||
|
@ -130,8 +254,8 @@ float ReferencePoint::friis_indexes_for_ap(
|
||||||
measurements.find(ap_mac) ;
|
measurements.find(ap_mac) ;
|
||||||
if (measurement != measurements.end())
|
if (measurement != measurements.end())
|
||||||
{
|
{
|
||||||
float distance = this->distance(ap.get_coordinates()) ;
|
|
||||||
double ss = measurement->second.get_average_ss() ;
|
double ss = measurement->second.get_average_ss() ;
|
||||||
|
assert((*request)->get_mobile()) ;
|
||||||
float mobile_gain =
|
float mobile_gain =
|
||||||
(*request)->get_mobile()->get_antenna_gain() ;
|
(*request)->get_mobile()->get_antenna_gain() ;
|
||||||
friis_idx_sum +=
|
friis_idx_sum +=
|
||||||
|
|
|
@ -25,6 +25,12 @@ protected:
|
||||||
//@{
|
//@{
|
||||||
std::tr1::unordered_map<std::string, Measurement>
|
std::tr1::unordered_map<std::string, Measurement>
|
||||||
get_all_measurements(void) const ;
|
get_all_measurements(void) const ;
|
||||||
|
/// Returns all the measurements sent by the given mobile
|
||||||
|
std::tr1::unordered_map<std::string, Measurement>
|
||||||
|
get_all_measurements(const std::string &mac_transmitter) const ;
|
||||||
|
/// Returns the calibration requests sent by the given mobile
|
||||||
|
const std::vector<CalibrationRequest*> get_requests(
|
||||||
|
const std::string &mac_transmitter) const ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -42,12 +48,17 @@ public:
|
||||||
/** @name Read accessors */
|
/** @name Read accessors */
|
||||||
//@{
|
//@{
|
||||||
const std::vector<CalibrationRequest*>& get_requests(void) const ;
|
const std::vector<CalibrationRequest*>& get_requests(void) const ;
|
||||||
|
double average_measurements(const std::string &mac_transmitter) const ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/** @name Write accessors */
|
/** @name Write accessors */
|
||||||
//@{
|
//@{
|
||||||
/// Adds a Request to the \link #requests request list\endlink
|
/// Adds a Request to the \link #requests request list\endlink
|
||||||
void add_request(const CalibrationRequest *cm) ;
|
void add_request(const CalibrationRequest *r) ;
|
||||||
|
/// Deletes all the requests contained in #requests
|
||||||
|
void delete_requests(void) ;
|
||||||
|
/// Deletes the requests that are not sent by an AP
|
||||||
|
bool delete_generated_requests(void) ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/** @name Operations */
|
/** @name Operations */
|
||||||
|
@ -93,16 +104,16 @@ std::vector<CalibrationRequest*>& ReferencePoint::get_requests() const
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param cm A pointer to the CalibrationRequest to add. If it is
|
* @param r A pointer to the CalibrationRequest to add. If it is
|
||||||
* NULL, nothing will be done.
|
* NULL, nothing will be done.
|
||||||
* The memory pointed by this pointer must not be deallocated before
|
* The memory pointed by this pointer must not be deallocated before
|
||||||
* the ReferencePoint destruction (do \em not pass a pointer to a local
|
* the ReferencePoint destruction (do \em not pass a pointer to a local
|
||||||
* variable!).
|
* variable!).
|
||||||
*/
|
*/
|
||||||
inline void ReferencePoint::add_request(const CalibrationRequest *cm)
|
inline void ReferencePoint::add_request(const CalibrationRequest *r)
|
||||||
{
|
{
|
||||||
if (cm != NULL)
|
if (r != NULL)
|
||||||
requests.push_back(const_cast<CalibrationRequest*>(cm)) ;
|
requests.push_back(const_cast<CalibrationRequest*>(r)) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "result.hh"
|
#include "result.hh"
|
||||||
#include "request.hh"
|
#include "request.hh"
|
||||||
|
#include "area.hh"
|
||||||
|
#include "stock.hh"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
@ -10,15 +12,31 @@ using namespace std ;
|
||||||
/* *** Constructors *** */
|
/* *** Constructors *** */
|
||||||
|
|
||||||
|
|
||||||
Result::Result(const Point3D &_position, const std::string &_algorithm,
|
Result::Result(const Request *_request,
|
||||||
|
const std::string &_algorithm,
|
||||||
|
const Point3D &_position,
|
||||||
const Point3D &real_position):
|
const Point3D &real_position):
|
||||||
position(_position), algorithm(_algorithm)
|
request(_request), algorithm(_algorithm), position(_position)
|
||||||
{
|
{
|
||||||
compute_error(real_position) ;
|
compute_error(real_position) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Read accessors *** */
|
||||||
|
|
||||||
|
|
||||||
|
string Result::in_which_area() const
|
||||||
|
{
|
||||||
|
const Area *area = Stock::in_which_area_is(position) ;
|
||||||
|
if (area == NULL)
|
||||||
|
return "" ;
|
||||||
|
|
||||||
|
return area->get_name() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *** Write accessors *** */
|
/* *** Write accessors *** */
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,6 +55,7 @@ const Result& Result::operator=(const Result &source)
|
||||||
if (this == &source)
|
if (this == &source)
|
||||||
return *this ;
|
return *this ;
|
||||||
|
|
||||||
|
request = source.request ;
|
||||||
algorithm = source.algorithm ;
|
algorithm = source.algorithm ;
|
||||||
position = source.position ;
|
position = source.position ;
|
||||||
error = source.error ;
|
error = source.error ;
|
||||||
|
@ -48,6 +67,7 @@ const Result& Result::operator=(const Result &source)
|
||||||
bool Result::operator==(const Result &source) const
|
bool Result::operator==(const Result &source) const
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
request == source.request &&
|
||||||
algorithm == source.algorithm &&
|
algorithm == source.algorithm &&
|
||||||
position == source.position &&
|
position == source.position &&
|
||||||
error == source.error ;
|
error == source.error ;
|
||||||
|
@ -79,7 +99,8 @@ std::ostream& operator<<(ostream &os, const Result &r)
|
||||||
{
|
{
|
||||||
os
|
os
|
||||||
<< "The result of the algorithm " << r.algorithm
|
<< "The result of the algorithm " << r.algorithm
|
||||||
<< " is: " << r.position ;
|
<< " is: " << r.position
|
||||||
|
<< " (area: « " << r.in_which_area() << " »)" ;
|
||||||
if (r.error >= 0)
|
if (r.error >= 0)
|
||||||
os << ", error = " << r.error << " m" ;
|
os << ", error = " << r.error << " m" ;
|
||||||
return os ;
|
return os ;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef _OWLPS_POSITIONING_RESULT_HH_
|
#ifndef _OWLPS_POSITIONING_RESULT_HH_
|
||||||
#define _OWLPS_POSITIONING_RESULT_HH_
|
#define _OWLPS_POSITIONING_RESULT_HH_
|
||||||
|
|
||||||
|
class Request ;
|
||||||
|
|
||||||
#include "point3d.hh"
|
#include "point3d.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -9,28 +11,35 @@
|
||||||
class Result
|
class Result
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
/// Computed coordinates of the mobile
|
/// Request sent by the mobile
|
||||||
Point3D position ;
|
const Request *request ;
|
||||||
/// Algorithm used to compute the position
|
/// Algorithm used to compute the position
|
||||||
std::string algorithm ;
|
std::string algorithm ;
|
||||||
|
/// Computed coordinates of the mobile
|
||||||
|
Point3D position ;
|
||||||
/// Distance error between the real coordinates and the computed point
|
/// Distance error between the real coordinates and the computed point
|
||||||
/** The error is set to -1 if the real coordinates are unknown. */
|
/** The error is set to -1 if the real coordinates are unknown. */
|
||||||
float error ;
|
float error ;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Result(const std::string &_algorithm = "UnknownAlgorithm"):
|
Result(const Request *_request = NULL,
|
||||||
algorithm(_algorithm), error(-1) {}
|
const std::string &_algorithm = "UnknownAlgorithm"):
|
||||||
Result(const Point3D &_position, const std::string &_algorithm):
|
request(_request), algorithm(_algorithm), error(-1) {}
|
||||||
position(_position), algorithm(_algorithm), error(-1) {}
|
Result(const Request *_request, const std::string &_algorithm,
|
||||||
Result(const Point3D &_position, const std::string &_algorithm,
|
const Point3D &_position):
|
||||||
const Point3D &real_position) ;
|
request(_request), algorithm(_algorithm), position(_position),
|
||||||
|
error(-1) {}
|
||||||
|
Result(const Request *_request, const std::string &_algorithm,
|
||||||
|
const Point3D &_position, const Point3D &real_position) ;
|
||||||
~Result(void) {}
|
~Result(void) {}
|
||||||
|
|
||||||
/** @name Read accessors */
|
/** @name Read accessors */
|
||||||
//@{
|
//@{
|
||||||
|
const Request* get_request(void) const ;
|
||||||
const std::string& get_algorithm(void) const ;
|
const std::string& get_algorithm(void) const ;
|
||||||
const Point3D& get_position(void) const ;
|
const Point3D& get_position(void) const ;
|
||||||
float get_error(void) const ;
|
float get_error(void) const ;
|
||||||
|
std::string in_which_area(void) const ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/** @name Write accessors */
|
/** @name Write accessors */
|
||||||
|
@ -60,6 +69,12 @@ public:
|
||||||
/* *** Read accessors *** */
|
/* *** Read accessors *** */
|
||||||
|
|
||||||
|
|
||||||
|
inline const Request* Result::get_request() const
|
||||||
|
{
|
||||||
|
return request ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline const std::string& Result::get_algorithm() const
|
inline const std::string& Result::get_algorithm() const
|
||||||
{
|
{
|
||||||
return algorithm ;
|
return algorithm ;
|
||||||
|
|
|
@ -25,6 +25,8 @@ public:
|
||||||
|
|
||||||
/** @name Read accessors */
|
/** @name Read accessors */
|
||||||
//@{
|
//@{
|
||||||
|
/// Checks if there is at least one Result in the list
|
||||||
|
bool empty(void) const ;
|
||||||
const Request* get_request(void) const ;
|
const Request* get_request(void) const ;
|
||||||
const std::vector<Result>& get_results(void) const ;
|
const std::vector<Result>& get_results(void) const ;
|
||||||
//@}
|
//@}
|
||||||
|
@ -57,6 +59,12 @@ public:
|
||||||
/* *** Read accessors *** */
|
/* *** Read accessors *** */
|
||||||
|
|
||||||
|
|
||||||
|
inline bool ResultList::empty() const
|
||||||
|
{
|
||||||
|
return results.empty() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline const Request* ResultList::get_request() const
|
inline const Request* ResultList::get_request() const
|
||||||
{
|
{
|
||||||
return request ;
|
return request ;
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
#include "stock.hh"
|
#include "stock.hh"
|
||||||
|
#include "configuration.hh"
|
||||||
#include "posexcept.hh"
|
#include "posexcept.hh"
|
||||||
|
#include "area.hh"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
using namespace std ;
|
using namespace std ;
|
||||||
using std::tr1::unordered_map ;
|
using std::tr1::unordered_map ;
|
||||||
|
@ -15,6 +19,8 @@ unordered_map<Point3D, Waypoint> Stock::waypoints ;
|
||||||
|
|
||||||
unordered_map<string, Mobile> Stock::mobiles ;
|
unordered_map<string, Mobile> Stock::mobiles ;
|
||||||
|
|
||||||
|
uint32_t Stock::nb_virtual_mobiles = 0 ;
|
||||||
|
|
||||||
unordered_map<string, AccessPoint> Stock::aps ;
|
unordered_map<string, AccessPoint> Stock::aps ;
|
||||||
|
|
||||||
unordered_set<ReferencePoint,
|
unordered_set<ReferencePoint,
|
||||||
|
@ -77,6 +83,26 @@ 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)
|
||||||
|
{
|
||||||
|
for (unordered_map<string, Building>::const_iterator
|
||||||
|
b = buildings.begin() ; b != buildings.end() ; ++b)
|
||||||
|
{
|
||||||
|
const unordered_map<string, Area*> &areas = b->second.get_areas() ;
|
||||||
|
for (unordered_map<string, Area*>::const_iterator
|
||||||
|
a = areas.begin() ; a != areas.end() ; ++a)
|
||||||
|
if (a->second->contains_point(point))
|
||||||
|
return a->second ;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *** Waypoint operations *** */
|
/* *** Waypoint operations *** */
|
||||||
|
|
||||||
|
@ -115,6 +141,19 @@ void Stock::waypoint_remove_building(const Waypoint &point,
|
||||||
/* *** Mobile operations *** */
|
/* *** Mobile operations *** */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mac The MAC address of the Mobile to search for.
|
||||||
|
* It must be a valid MAC address, as no check is performed.
|
||||||
|
* @return \em true if a mobile with this MAC address exists.
|
||||||
|
* @return \em false if this MAC address was not found.
|
||||||
|
*/
|
||||||
|
bool Stock::mobile_exists(const std::string &mac)
|
||||||
|
{
|
||||||
|
unordered_map<string, Mobile>::const_iterator i = mobiles.find(mac) ;
|
||||||
|
return i != mobiles.end() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mac The MAC address of the Mobile to search for.
|
* @param mac The MAC address of the Mobile to search for.
|
||||||
* It must be a valid MAC address, as no check is performed.
|
* It must be a valid MAC address, as no check is performed.
|
||||||
|
@ -147,10 +186,38 @@ const Mobile& Stock::find_create_mobile(const string &mac)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the Mobile already exists, it is replaced by the \em source.
|
||||||
|
*/
|
||||||
|
const Mobile& Stock::find_create_mobile(const Mobile &source)
|
||||||
|
{
|
||||||
|
const string &mac = source.get_mac_addr() ;
|
||||||
|
unordered_map<string, Mobile>::const_iterator i = mobiles.find(mac) ;
|
||||||
|
if (i != mobiles.end())
|
||||||
|
return i->second ;
|
||||||
|
|
||||||
|
mobiles[mac] = source ;
|
||||||
|
return mobiles[mac] ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *** AccessPoint operations *** */
|
/* *** AccessPoint operations *** */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mac The MAC address of the AccessPoint to search for.
|
||||||
|
* It must be a valid MAC address, as no check is performed.
|
||||||
|
* @return \em true if an AP with this MAC address exists.
|
||||||
|
* @return \em false if this MAC address was not found.
|
||||||
|
*/
|
||||||
|
bool Stock::ap_exists(const std::string &mac)
|
||||||
|
{
|
||||||
|
unordered_map<string, AccessPoint>::const_iterator i = aps.find(mac) ;
|
||||||
|
return i != aps.end() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mac The MAC address of the AccessPoint to search for.
|
* @param mac The MAC address of the AccessPoint to search for.
|
||||||
* It must be a valid MAC address, as no check is performed.
|
* It must be a valid MAC address, as no check is performed.
|
||||||
|
@ -179,6 +246,12 @@ const AccessPoint& Stock::find_create_ap(const string &mac)
|
||||||
|
|
||||||
AccessPoint &ap = aps[mac] ;
|
AccessPoint &ap = aps[mac] ;
|
||||||
ap.set_mac_addr(mac) ;
|
ap.set_mac_addr(mac) ;
|
||||||
|
|
||||||
|
if (Configuration::is_configured("verbose"))
|
||||||
|
cerr
|
||||||
|
<< "New AP « " << mac
|
||||||
|
<< " » (total: " << nb_aps() << " APs).\n" ;
|
||||||
|
|
||||||
return ap ;
|
return ap ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,10 +312,62 @@ void Stock::update_all_friis_indexes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double Stock::ap_matrix_get_ss(const std::string &mac_transmitter,
|
||||||
|
const std::string &mac_receiver)
|
||||||
|
{
|
||||||
|
const AccessPoint &receiver = get_ap(mac_receiver) ;
|
||||||
|
const ReferencePoint &rp =
|
||||||
|
get_reference_point(receiver.get_coordinates()) ;
|
||||||
|
|
||||||
|
return rp.average_measurements(mac_transmitter) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns \em true if \em coord are the coordinates of an existing
|
||||||
|
* AP, \em false if not.
|
||||||
|
*/
|
||||||
|
bool Stock::is_ap_coordinate(const Point3D &coord)
|
||||||
|
{
|
||||||
|
for (unordered_map<string, AccessPoint>::const_iterator ap =
|
||||||
|
aps.begin() ; ap != aps.end() ; ++ap)
|
||||||
|
if (ap->second.get_coordinates() == coord)
|
||||||
|
return true ;
|
||||||
|
|
||||||
|
return false ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *** ReferencePoint operations *** */
|
/* *** ReferencePoint operations *** */
|
||||||
|
|
||||||
|
|
||||||
|
bool Stock::reference_point_exists(const ReferencePoint &point)
|
||||||
|
{
|
||||||
|
unordered_set<ReferencePoint>::const_iterator i =
|
||||||
|
reference_points.find(point) ;
|
||||||
|
return i != reference_points.end() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param point Coordinates of the wanted ReferencePoint.
|
||||||
|
* @return The ReferencePoint at the given coordinates, if found.
|
||||||
|
* @throw element_not_found is thrown if no ReferencePoint exists at the
|
||||||
|
* given coordinates.
|
||||||
|
*/
|
||||||
|
const ReferencePoint& Stock::
|
||||||
|
get_reference_point(const ReferencePoint &point)
|
||||||
|
{
|
||||||
|
unordered_set<ReferencePoint>::const_iterator i =
|
||||||
|
reference_points.find(point) ;
|
||||||
|
if (i != reference_points.end())
|
||||||
|
return *i ;
|
||||||
|
throw element_not_found("No ReferencePoint with coordinates " +
|
||||||
|
static_cast<string>(point) + "!") ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const ReferencePoint& Stock::
|
const ReferencePoint& Stock::
|
||||||
find_create_reference_point(const ReferencePoint &point)
|
find_create_reference_point(const ReferencePoint &point)
|
||||||
{
|
{
|
||||||
|
@ -262,13 +387,31 @@ closest_reference_point(const Request &request)
|
||||||
"Cannot search for the closest reference point: reference points'"
|
"Cannot search for the closest reference point: reference points'"
|
||||||
" list is empty!") ;
|
" list is empty!") ;
|
||||||
|
|
||||||
|
bool ignore_aps = Configuration::bool_value(
|
||||||
|
"positioning.radar-ignore-ap-reference-points") ;
|
||||||
unordered_set<ReferencePoint>::const_iterator i =
|
unordered_set<ReferencePoint>::const_iterator i =
|
||||||
reference_points.begin() ;
|
reference_points.begin() ;
|
||||||
|
|
||||||
|
if (ignore_aps)
|
||||||
|
{
|
||||||
|
// Fast-forward to the next non-AP reference point
|
||||||
|
while (i != reference_points.end() && is_ap_coordinate(*i))
|
||||||
|
++i ;
|
||||||
|
|
||||||
|
// No non-AP reference point was found, we are forced to consider
|
||||||
|
// the AP reference points
|
||||||
|
if (i == reference_points.end())
|
||||||
|
ignore_aps = false ;
|
||||||
|
}
|
||||||
|
|
||||||
float distance = i->ss_square_distance(request) ;
|
float distance = i->ss_square_distance(request) ;
|
||||||
unordered_set<ReferencePoint>::const_iterator closest = i ;
|
unordered_set<ReferencePoint>::const_iterator closest = i ;
|
||||||
|
|
||||||
for (++i ; i != reference_points.end() ; ++i)
|
for (++i ; i != reference_points.end() ; ++i)
|
||||||
{
|
{
|
||||||
|
if (ignore_aps && is_ap_coordinate(*i))
|
||||||
|
continue ;
|
||||||
|
|
||||||
float tmp_distance = i->ss_square_distance(request) ;
|
float tmp_distance = i->ss_square_distance(request) ;
|
||||||
if (tmp_distance < distance)
|
if (tmp_distance < distance)
|
||||||
{
|
{
|
||||||
|
@ -281,10 +424,258 @@ 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<ReferencePoint>::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 ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reference_points.size() < 3)
|
||||||
|
{
|
||||||
|
if (Configuration::is_configured("verbose"))
|
||||||
|
cerr
|
||||||
|
<< reference_points.size() << " true reference points is"
|
||||||
|
<< " not enough to generate reference points.\n" ;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate RPs */
|
||||||
|
if (! Configuration::is_configured("positioning.minmax-start") ||
|
||||||
|
! Configuration::is_configured("positioning.minmax-stop"))
|
||||||
|
throw missing_configuration(
|
||||||
|
"You must define the deployment area in order to generate"
|
||||||
|
" reference points.") ;
|
||||||
|
Point3D start(
|
||||||
|
Configuration::string_value("positioning.minmax-start")) ;
|
||||||
|
Point3D stop(
|
||||||
|
Configuration::string_value("positioning.minmax-stop")) ;
|
||||||
|
float step_x =
|
||||||
|
Configuration::float_value("positioning.generated-meshing-grain-x") ;
|
||||||
|
float step_y =
|
||||||
|
Configuration::float_value("positioning.generated-meshing-grain-y") ;
|
||||||
|
float z = 1 ; // FIXME
|
||||||
|
for (float x = start.get_x() ; x <= stop.get_x() ; x += step_x)
|
||||||
|
for (float y = start.get_y() ; y <= stop.get_y() ; y += step_y)
|
||||||
|
//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<string, Measurement> 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<string, AccessPoint>::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<double,
|
||||||
|
unordered_map<string, AccessPoint>::const_iterator>
|
||||||
|
sorted_angles ;
|
||||||
|
for (unordered_map<string, AccessPoint>::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<double,
|
||||||
|
unordered_map<string, AccessPoint>::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<double,
|
||||||
|
unordered_map<string, AccessPoint>::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<double>(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) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *** CalibrationRequest operations *** */
|
/* *** CalibrationRequest operations *** */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The CalibrationRequest created or found.
|
||||||
|
*/
|
||||||
|
const CalibrationRequest& Stock::
|
||||||
|
store_calibration_request(const CalibrationRequest &request)
|
||||||
|
{
|
||||||
|
const CalibrationRequest &calibration_request =
|
||||||
|
find_create_calibration_request(request) ;
|
||||||
|
calibration_request.reference_point_backward_link() ;
|
||||||
|
return calibration_request ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Stock::
|
||||||
|
delete_calibration_request(const CalibrationRequest &request)
|
||||||
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
unordered_set<CalibrationRequest>::const_iterator found =
|
||||||
|
calibration_requests.find(request) ;
|
||||||
|
if (found == calibration_requests.end())
|
||||||
|
{
|
||||||
|
cerr
|
||||||
|
<< "Error! Cannot delete an unstored CalibrationRequest: "
|
||||||
|
<< request << endl ;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
calibration_requests.erase(request) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const CalibrationRequest& Stock::
|
const CalibrationRequest& Stock::
|
||||||
find_create_calibration_request(const CalibrationRequest &request)
|
find_create_calibration_request(const CalibrationRequest &request)
|
||||||
{
|
{
|
||||||
|
@ -302,13 +693,32 @@ closest_calibration_request(const Request &request)
|
||||||
"Cannot search for the closest calibration request: calibration"
|
"Cannot search for the closest calibration request: calibration"
|
||||||
" requests' list is empty!") ;
|
" requests' list is empty!") ;
|
||||||
|
|
||||||
|
bool ignore_aps = Configuration::bool_value(
|
||||||
|
"positioning.radar-ignore-ap-reference-points") ;
|
||||||
unordered_set<CalibrationRequest>::const_iterator i =
|
unordered_set<CalibrationRequest>::const_iterator i =
|
||||||
calibration_requests.begin() ;
|
calibration_requests.begin() ;
|
||||||
|
|
||||||
|
if (ignore_aps)
|
||||||
|
{
|
||||||
|
// Fast-forward to the next non-AP reference point
|
||||||
|
while (i != calibration_requests.end() &&
|
||||||
|
is_ap_coordinate(*i->get_reference_point()))
|
||||||
|
++i ;
|
||||||
|
|
||||||
|
// No non-AP reference point was found, we are forced to consider
|
||||||
|
// the AP reference points
|
||||||
|
if (i == calibration_requests.end())
|
||||||
|
ignore_aps = false ;
|
||||||
|
}
|
||||||
|
|
||||||
float distance = i->ss_square_distance(request) ;
|
float distance = i->ss_square_distance(request) ;
|
||||||
unordered_set<CalibrationRequest>::const_iterator closest = i ;
|
unordered_set<CalibrationRequest>::const_iterator closest = i ;
|
||||||
|
|
||||||
for (++i ; i != calibration_requests.end() ; ++i)
|
for (++i ; i != calibration_requests.end() ; ++i)
|
||||||
{
|
{
|
||||||
|
if (ignore_aps && is_ap_coordinate(*i->get_reference_point()))
|
||||||
|
continue ;
|
||||||
|
|
||||||
float tmp_distance = i->ss_square_distance(request) ;
|
float tmp_distance = i->ss_square_distance(request) ;
|
||||||
if (tmp_distance < distance)
|
if (tmp_distance < distance)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,9 @@ private:
|
||||||
/** The string key of the map is the Mobile MAC address. */
|
/** The string key of the map is the Mobile MAC address. */
|
||||||
static std::tr1::unordered_map<std::string, Mobile> mobiles ;
|
static std::tr1::unordered_map<std::string, Mobile> mobiles ;
|
||||||
|
|
||||||
|
/// Number of generated "virtual" mobiles
|
||||||
|
static uint32_t nb_virtual_mobiles ;
|
||||||
|
|
||||||
/// List of known AccessPoint
|
/// List of known AccessPoint
|
||||||
/** The string key of the map is the AccessPoint MAC address. */
|
/** The string key of the map is the AccessPoint MAC address. */
|
||||||
static std::tr1::unordered_map<std::string, AccessPoint> aps ;
|
static std::tr1::unordered_map<std::string, AccessPoint> aps ;
|
||||||
|
@ -47,6 +50,8 @@ public:
|
||||||
static const Building& get_building(const std::string &name) ;
|
static const Building& get_building(const std::string &name) ;
|
||||||
/// Searches for a Building and creates it if it does not exist
|
/// Searches for a Building and creates it if it does not exist
|
||||||
static const Building& find_create_building(const std::string &name) ;
|
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) ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/** @name Waypoint operations */
|
/** @name Waypoint operations */
|
||||||
|
@ -68,10 +73,17 @@ public:
|
||||||
|
|
||||||
/** @name Mobile operations */
|
/** @name Mobile operations */
|
||||||
//@{
|
//@{
|
||||||
|
/// Returns the number of mobiles
|
||||||
|
static unsigned int nb_mobiles(void) ;
|
||||||
|
/// Verify the existence of a mobile
|
||||||
|
static bool mobile_exists(const std::string &mac) ;
|
||||||
/// Reads the Mobile corresponding to a given MAC address
|
/// Reads the Mobile corresponding to a given MAC address
|
||||||
static const Mobile& get_mobile(const std::string &mac) ;
|
static const Mobile& get_mobile(const std::string &mac) ;
|
||||||
/// Searches for a Mobile and creates it if it does not exist
|
/// \brief Searches for a Mobile given its MAC address and creates
|
||||||
|
/// it if it does not exist
|
||||||
static const Mobile& find_create_mobile(const std::string &mac) ;
|
static const Mobile& find_create_mobile(const std::string &mac) ;
|
||||||
|
/// Searches for a Mobile and create it if it does not exist
|
||||||
|
static const Mobile& find_create_mobile(const Mobile &source) ;
|
||||||
/// \brief Returns a reference to the Mobile corresponding to a
|
/// \brief Returns a reference to the Mobile corresponding to a
|
||||||
/// given MAC address
|
/// given MAC address
|
||||||
static Mobile& getw_mobile(const std::string &mac) ;
|
static Mobile& getw_mobile(const std::string &mac) ;
|
||||||
|
@ -81,24 +93,40 @@ public:
|
||||||
//@{
|
//@{
|
||||||
/// Returns the number of access points
|
/// Returns the number of access points
|
||||||
static unsigned int nb_aps(void) ;
|
static unsigned int nb_aps(void) ;
|
||||||
|
/// Returns a reference to the AP list
|
||||||
|
static
|
||||||
|
std::tr1::unordered_map<std::string, AccessPoint>& get_aps(void) ;
|
||||||
|
/// Verify the existence of an AP
|
||||||
|
static bool ap_exists(const std::string &mac) ;
|
||||||
/// Reads the AccessPoint corresponding to a given MAC address
|
/// Reads the AccessPoint corresponding to a given MAC address
|
||||||
static const AccessPoint& get_ap(const std::string &mac) ;
|
static const AccessPoint& get_ap(const std::string &mac) ;
|
||||||
/// Searches for an AccessPoint and create it if it does not exist
|
|
||||||
static const AccessPoint& find_create_ap(const AccessPoint &source) ;
|
|
||||||
/// \brief Searches for an AccessPoint given its MAC address and
|
/// \brief Searches for an AccessPoint given its MAC address and
|
||||||
/// creates it if it does not exist
|
/// creates it if it does not exist
|
||||||
static const AccessPoint& find_create_ap(const std::string &mac) ;
|
static const AccessPoint& find_create_ap(const std::string &mac) ;
|
||||||
|
/// Searches for an AccessPoint and create it if it does not exist
|
||||||
|
static const AccessPoint& find_create_ap(const AccessPoint &source) ;
|
||||||
/// \brief Returns a reference to the AccessPoint corresponding to a
|
/// \brief Returns a reference to the AccessPoint corresponding to a
|
||||||
/// given MAC address
|
/// given MAC address
|
||||||
static AccessPoint& getw_ap(const std::string &mac) ;
|
static AccessPoint& getw_ap(const std::string &mac) ;
|
||||||
/// Updates the friis indexes of all the APs
|
/// Updates the friis indexes of all the APs
|
||||||
static void update_all_friis_indexes(void) ;
|
static void update_all_friis_indexes(void) ;
|
||||||
|
/// \brief Returns the signal strenth received by an AP mac_receiver
|
||||||
|
/// from an AP mac_transmitter
|
||||||
|
static double ap_matrix_get_ss(const std::string &mac_transmitter,
|
||||||
|
const std::string &mac_receiver) ;
|
||||||
|
/// Checks if a Point3D is the coordinate of an existing AP
|
||||||
|
static bool is_ap_coordinate(const Point3D &coord) ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/** @name ReferencePoint operations */
|
/** @name ReferencePoint operations */
|
||||||
//@{
|
//@{
|
||||||
/// Returns the number of reference points
|
/// Returns the number of reference points
|
||||||
static unsigned int nb_reference_points(void) ;
|
static unsigned int nb_reference_points(void) ;
|
||||||
|
/// Verify the existence of a reference point at the given coordinates
|
||||||
|
static bool reference_point_exists(const ReferencePoint &point) ;
|
||||||
|
/// Reads the ReferencePoint at the given coordinates
|
||||||
|
static const ReferencePoint&
|
||||||
|
get_reference_point(const ReferencePoint &point) ;
|
||||||
/// Searches for a ReferencePoint and adds it if it does not exist
|
/// Searches for a ReferencePoint and adds it if it does not exist
|
||||||
static const ReferencePoint&
|
static const ReferencePoint&
|
||||||
find_create_reference_point(const ReferencePoint &point) ;
|
find_create_reference_point(const ReferencePoint &point) ;
|
||||||
|
@ -106,12 +134,22 @@ public:
|
||||||
/// strength space) to a given Request
|
/// strength space) to a given Request
|
||||||
static const ReferencePoint&
|
static const ReferencePoint&
|
||||||
closest_reference_point(const Request &request) ;
|
closest_reference_point(const Request &request) ;
|
||||||
|
/// \brief Generates reference points from the reference points
|
||||||
|
/// corresponding to APs
|
||||||
|
static void regenerate_reference_points(void) ;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
/** @name CalibrationRequest operations */
|
/** @name CalibrationRequest operations */
|
||||||
//@{
|
//@{
|
||||||
/// Returns the number of calibration requests
|
/// Returns the number of calibration requests
|
||||||
static unsigned int nb_calibration_requests(void) ;
|
static unsigned int nb_calibration_requests(void) ;
|
||||||
|
/// \brief Searches for a CalibrationRequest, adds it if it does
|
||||||
|
/// not exist, and links it to its reference point
|
||||||
|
static const CalibrationRequest& store_calibration_request(
|
||||||
|
const CalibrationRequest &request) ;
|
||||||
|
/// Deletes a CalibrationRequest
|
||||||
|
static void delete_calibration_request(
|
||||||
|
const CalibrationRequest &request) ;
|
||||||
/// Searches for a CalibrationRequest and adds it if it does not exist
|
/// Searches for a CalibrationRequest and adds it if it does not exist
|
||||||
static const CalibrationRequest&
|
static const CalibrationRequest&
|
||||||
find_create_calibration_request(const CalibrationRequest &request) ;
|
find_create_calibration_request(const CalibrationRequest &request) ;
|
||||||
|
@ -161,6 +199,12 @@ find_create_waypoint(const Waypoint &point)
|
||||||
/* *** Mobile operations *** */
|
/* *** Mobile operations *** */
|
||||||
|
|
||||||
|
|
||||||
|
inline unsigned int Stock::nb_mobiles()
|
||||||
|
{
|
||||||
|
return mobiles.size() ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the Mobile corresponding to \em mac does not exist, it is created.
|
* If the Mobile corresponding to \em mac does not exist, it is created.
|
||||||
* @param mac The MAC address of the Mobile to search for. It must be a
|
* @param mac The MAC address of the Mobile to search for. It must be a
|
||||||
|
@ -183,6 +227,13 @@ inline unsigned int Stock::nb_aps()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline
|
||||||
|
std::tr1::unordered_map<std::string, AccessPoint>& Stock::get_aps()
|
||||||
|
{
|
||||||
|
return aps ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the AccessPoint corresponding to \em mac does not exist, it is
|
* If the AccessPoint corresponding to \em mac does not exist, it is
|
||||||
* created.
|
* created.
|
||||||
|
|
|
@ -17,6 +17,9 @@ namespace po = boost::program_options ;
|
||||||
#define DEFAULT_CONFIG_FILE_NAME \
|
#define DEFAULT_CONFIG_FILE_NAME \
|
||||||
"/usr/local/etc/owlps/owlps-positioning.cfg"
|
"/usr/local/etc/owlps/owlps-positioning.cfg"
|
||||||
|
|
||||||
|
#define DEFAULT_TCPEVAAL_HOST "127.0.0.1"
|
||||||
|
#define DEFAULT_TCPEVAAL_PORT 4444
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *** Constructors *** */
|
/* *** Constructors *** */
|
||||||
|
@ -106,6 +109,13 @@ void UserInterface::fill_data_input_options()
|
||||||
("data-input.ap-csv-file", po::value<string>(),
|
("data-input.ap-csv-file", po::value<string>(),
|
||||||
"CSV file to use for access points input (when"
|
"CSV file to use for access points input (when"
|
||||||
" data-input.ap-medium = CSV).")
|
" data-input.ap-medium = CSV).")
|
||||||
|
("data-input.mobile-medium", po::value< vector<string> >()
|
||||||
|
->composing(),
|
||||||
|
"Medium from which mobiles are read. You can specify this"
|
||||||
|
" option more than once. Allowed: CSV.")
|
||||||
|
("data-input.mobile-csv-file", po::value<string>(),
|
||||||
|
"CSV file to use for mobiles input (when"
|
||||||
|
" data-input.mobile-medium = CSV).")
|
||||||
("data-input.topology-medium,T", po::value< vector<string> >()
|
("data-input.topology-medium,T", po::value< vector<string> >()
|
||||||
->composing(),
|
->composing(),
|
||||||
"Medium from which topology (buildings, areas and waypoints) is"
|
"Medium from which topology (buildings, areas and waypoints) is"
|
||||||
|
@ -186,6 +196,49 @@ void UserInterface::fill_positioning_options()
|
||||||
" before to compute the SS distance."
|
" before to compute the SS distance."
|
||||||
" The default is false, i.e the positioning request is compared"
|
" The default is false, i.e the positioning request is compared"
|
||||||
" directly to each calibration request.")
|
" directly to each calibration request.")
|
||||||
|
("positioning.generate-reference-points",
|
||||||
|
po::value<bool>()->default_value(false),
|
||||||
|
"Generate reference points from the (auto)calibration requests"
|
||||||
|
" received.")
|
||||||
|
("positioning.generated-meshing-grain-x",
|
||||||
|
po::value<float>()->default_value(0.5),
|
||||||
|
"When generating reference points, this distance (in meters) will"
|
||||||
|
" separate each point to the next in X.")
|
||||||
|
("positioning.generated-meshing-grain-y",
|
||||||
|
po::value<float>()->default_value(0.5),
|
||||||
|
"When generating reference points, this distance (in meters) will"
|
||||||
|
" separate each point to the next in Y.")
|
||||||
|
("positioning.radar-ignore-ap-reference-points",
|
||||||
|
po::value<bool>()->default_value(false),
|
||||||
|
"With the RADAR algorithm, try to avoid selecting the reference"
|
||||||
|
" points which are coordinates of an AP.")
|
||||||
|
("positioning.accept-new-calibration-requests",
|
||||||
|
po::value<bool>()->default_value(false),
|
||||||
|
"Add the calibration requests received during the run-time to"
|
||||||
|
" the calibration requests' list; this is required for the"
|
||||||
|
" self-calibration. If unactivated, the calibration requests"
|
||||||
|
" are handled as positioning requests (default is unactivated,"
|
||||||
|
" for security purposes).")
|
||||||
|
("positioning.position-calibration-requests",
|
||||||
|
po::value<bool>()->default_value(false),
|
||||||
|
"When accept-new-calibration-requests is activated, allow the"
|
||||||
|
" calibration requests to be positioned as normal requests."
|
||||||
|
" The default is to add them to the calibration requests' list"
|
||||||
|
" without position them.")
|
||||||
|
("positioning.accept-new-aps",
|
||||||
|
po::value<bool>()->default_value(false),
|
||||||
|
"When receiving requests, add unknown APs (APs which are not"
|
||||||
|
" declared in the APs' configuration file) to the APs' list"
|
||||||
|
" (default is false, for security purposes).")
|
||||||
|
("positioning.update-ap-coordinates-online",
|
||||||
|
po::value<bool>()->default_value(false),
|
||||||
|
"Allow AP's coordinates to be updated when a calibration request"
|
||||||
|
" with new coordinates is received from the AP (default is false,"
|
||||||
|
" for security purposes).")
|
||||||
|
("positioning.accept-new-mobiles",
|
||||||
|
po::value<bool>()->default_value(false),
|
||||||
|
"When receiving requests, add unknown mobiles (mobiles which are not"
|
||||||
|
" declared in the mobiles' configuration file) to the mobiles' list.")
|
||||||
;
|
;
|
||||||
|
|
||||||
file_options->add(options) ;
|
file_options->add(options) ;
|
||||||
|
@ -199,8 +252,9 @@ void UserInterface::fill_output_options()
|
||||||
options.add_options()
|
options.add_options()
|
||||||
("output.medium,O", po::value< vector<string> >()->composing(),
|
("output.medium,O", po::value< vector<string> >()->composing(),
|
||||||
"Medium to which the results will be wrote. You can specify"
|
"Medium to which the results will be wrote. You can specify"
|
||||||
" this option more than once. Allowed: Terminal, CSV, UDP."
|
" this option more than once."
|
||||||
" If this option is absent, results will be printed on the terminal.")
|
" Allowed: Terminal, CSV, UDP, TCPEvAAL."
|
||||||
|
" If this option is absent, the results are printed on the terminal.")
|
||||||
("output.csv-file", po::value<string>(),
|
("output.csv-file", po::value<string>(),
|
||||||
"CSV file to use for output (when output.medium = CSV).")
|
"CSV file to use for output (when output.medium = CSV).")
|
||||||
("output.udp-host", po::value<string>(),
|
("output.udp-host", po::value<string>(),
|
||||||
|
@ -208,6 +262,12 @@ void UserInterface::fill_output_options()
|
||||||
("output.udp-port", po::value<int>()
|
("output.udp-port", po::value<int>()
|
||||||
->default_value(MOBILE_DEFAULT_PORT),
|
->default_value(MOBILE_DEFAULT_PORT),
|
||||||
"Port on which the UDP data is sent (when output.medium = UDP).")
|
"Port on which the UDP data is sent (when output.medium = UDP).")
|
||||||
|
("output.tcpevaal-host", po::value<string>()
|
||||||
|
->default_value(DEFAULT_TCPEVAAL_HOST),
|
||||||
|
"Host to which the TCP data is sent (when output.medium = TCPEvAAL).")
|
||||||
|
("output.tcpevaal-port", po::value<int>()
|
||||||
|
->default_value(DEFAULT_TCPEVAAL_PORT),
|
||||||
|
"Port on which the TCP data is sent (when output.medium = TCPEvAAL).")
|
||||||
;
|
;
|
||||||
|
|
||||||
file_options->add(options) ;
|
file_options->add(options) ;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef _OWLPS_POSITIONING_WIFIDEVICE_HH_
|
#ifndef _OWLPS_POSITIONING_WIFIDEVICE_HH_
|
||||||
#define _OWLPS_POSITIONING_WIFIDEVICE_HH_
|
#define _OWLPS_POSITIONING_WIFIDEVICE_HH_
|
||||||
|
|
||||||
|
#include "posutil.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
|
@ -21,12 +23,10 @@ protected:
|
||||||
float trx_power ; ///< Transmit power in dBm
|
float trx_power ; ///< Transmit power in dBm
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WifiDevice(const std::string &_ip_addr = "",
|
WifiDevice(const std::string &_ip_addr,
|
||||||
const std::string &_mac_addr = "",
|
const std::string &_mac_addr,
|
||||||
const float _antenna_gain = WIFIDEVICE_DEFAULT_ANTENNA_GAIN,
|
const float _antenna_gain,
|
||||||
const float _trx_power = WIFIDEVICE_DEFAULT_TRX_POWER):
|
const float _trx_power) ;
|
||||||
ip_addr(_ip_addr), mac_addr(_mac_addr),
|
|
||||||
antenna_gain(_antenna_gain), trx_power(_trx_power) {}
|
|
||||||
|
|
||||||
WifiDevice(const WifiDevice &source):
|
WifiDevice(const WifiDevice &source):
|
||||||
ip_addr(source.ip_addr), mac_addr(source.mac_addr),
|
ip_addr(source.ip_addr), mac_addr(source.mac_addr),
|
||||||
|
@ -63,6 +63,22 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* *** Constructors *** */
|
||||||
|
|
||||||
|
|
||||||
|
inline WifiDevice::
|
||||||
|
WifiDevice(const std::string &_ip_addr = "",
|
||||||
|
const std::string &_mac_addr = "",
|
||||||
|
const float _antenna_gain = WIFIDEVICE_DEFAULT_ANTENNA_GAIN,
|
||||||
|
const float _trx_power = WIFIDEVICE_DEFAULT_TRX_POWER):
|
||||||
|
ip_addr(_ip_addr), mac_addr(_mac_addr),
|
||||||
|
antenna_gain(_antenna_gain), trx_power(_trx_power)
|
||||||
|
{
|
||||||
|
PosUtil::assert_uppercase(mac_addr) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* *** Read accessors *** */
|
/* *** Read accessors *** */
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,6 +118,7 @@ inline void WifiDevice::set_ip_addr(const std::string &_ip_addr)
|
||||||
|
|
||||||
inline void WifiDevice::set_mac_addr(const std::string &_mac_addr)
|
inline void WifiDevice::set_mac_addr(const std::string &_mac_addr)
|
||||||
{
|
{
|
||||||
|
PosUtil::assert_uppercase(_mac_addr) ;
|
||||||
mac_addr = _mac_addr ;
|
mac_addr = _mac_addr ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue