Merge branch dev (v1.1.7) into dev-drone

This commit is contained in:
Matteo Cypriani 2011-08-03 09:51:16 +02:00
commit e823014708
46 changed files with 1549 additions and 131 deletions

36
TODO
View File

@ -1,11 +1,14 @@
* Global
- Add option dump-configuration (displays the config & exits).
- Makefiles:
° Translate comments & help.
° Merge Makefile and Makefile_atheros*. Use template makefiles,
autohell, cmake…?
- Use string for network exchanges?
- Mark arguments as const in function headers if needed
That is (mostly) done in the owlps-positioning C++ code, but not
constantly in C modules.
Mostly done in the owlps-positioning C++ code (should check that),
but not constantly in C modules.
[Done in libowlps & libowlps-client.]
- Allow to use hostnames instead of IP addresses in all modules
getaddrinfo(3) (or gethostbyname(3)) should be used when opening
@ -25,10 +28,14 @@
* 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
(But it is currently used by only one thread.) Use inet_ntop()
instead?
- Refactor got_request().
- Use the type of a request to identify it?
(along with the mobile MAC address and the request 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
request. We should define an option to allow user to choose the
time he wants.
- Allow blank parameters for output options.
* Listener
- 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?
- read_packet(): use ieee80211_header_size for all implicit 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
- Handle signals.
- Add verbose & quiet options.
- Log sent requests?
- Allow to use a string for the direction?
Could be nice, but probably useless.
* Positioning
- Has its own fat TODO file, which I should translate.
* writeInDb
- Do something about that
° Merge in owlps-positioning?
° Delete?
- Has its own fat TODO file, which I could merge in here.

View File

@ -119,6 +119,7 @@ typedef struct _owl_autocalibration_order
#define OWL_REQUEST_NORMAL 0
#define OWL_REQUEST_CALIBRATION 1
#define OWL_REQUEST_AUTOCALIBRATION 2
#define OWL_REQUEST_GENERATED 3
#define OWL_REQUEST_IMPLICIT 10
#define OWL_REQUEST_UNDEFINED 255

View File

@ -82,6 +82,7 @@ OBJ_LIST = \
userinterface.o \
inputdatareader.o \
accesspointsreadercsv.o \
mobilesreadercsv.o \
topologyreadercsv.o \
textfilereader.o \
csvfilereader.o \
@ -90,6 +91,7 @@ OBJ_LIST = \
outputterminal.o \
outputcsv.o \
outputudpsocket.o \
outputtcpsocketevaal.o \
positioning.o \
input.o \
inputcsv.o \
@ -139,6 +141,7 @@ $(OBJ_DIR)/%.o: $(SRC_DIR)/%.cc $(SRC_DIR)/%.hh
# Dependencies
$(OBJ_DIR)/point3d.o: \
$(OBJ_DIR)/posutil.o \
$(OBJ_DIR)/posexcept.o
$(OBJ_DIR)/posutil.o: \
$(OBJ_DIR)/stock.o \
@ -154,6 +157,7 @@ $(OBJ_DIR)/userinterface.o: \
$(OBJ_DIR)/configuration.o
$(OBJ_DIR)/inputdatareader.o: \
$(OBJ_DIR)/accesspointsreadercsv.o \
$(OBJ_DIR)/mobilesreadercsv.o \
$(OBJ_DIR)/topologyreadercsv.o \
$(OBJ_DIR)/configuration.o \
$(OBJ_DIR)/posexcept.o
@ -161,6 +165,10 @@ $(OBJ_DIR)/accesspointsreadercsv.o: \
$(OBJ_DIR)/csvfilereader.o \
$(OBJ_DIR)/accesspoint.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)/csvfilereader.o \
$(OBJ_DIR)/area.o \
@ -195,6 +203,8 @@ $(OBJ_DIR)/calibrationrequest.o: \
$(OBJ_DIR)/referencepoint.o \
$(OBJ_DIR)/direction.o
$(OBJ_DIR)/result.o: \
$(OBJ_DIR)/stock.o \
$(OBJ_DIR)/area.o \
$(OBJ_DIR)/request.o
$(OBJ_DIR)/resultlist.o: \
$(OBJ_DIR)/result.o
@ -239,6 +249,9 @@ $(OBJ_DIR)/outputcsv.o: \
$(OBJ_DIR)/outputudpsocket.o: \
$(SRC_DIR)/outputmedium.hh \
$(OBJ_DIR)/result.o
$(OBJ_DIR)/outputtcpsocketevaal.o: \
$(SRC_DIR)/outputmedium.hh \
$(OBJ_DIR)/result.o
$(OBJ_DIR)/outputcsv.o: \
$(SRC_DIR)/outputmedium.hh \
$(OBJ_DIR)/result.o
@ -246,6 +259,7 @@ $(OBJ_DIR)/output.o: \
$(OBJ_DIR)/outputterminal.o \
$(OBJ_DIR)/outputcsv.o \
$(OBJ_DIR)/outputudpsocket.o \
$(OBJ_DIR)/outputtcpsocketevaal.o \
$(OBJ_DIR)/configuration.o \
$(OBJ_DIR)/posexcept.o
$(OBJ_DIR)/multilaterationalgorithm.o: \

View File

@ -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
not Request::type? That would simplify writing of the type to
streams (no need to cast each time anymore).
° Wi-Fi devices' list
. Merge Stock::mobiles & Stock::aps?
. Factorise AccessPointsReaderCSV & MobilesReaderCSV?
° Members renaming
. InputMedium:
. - current_line_nb & get_current_line_nb()
. - get_next_request() > read_next_request()
. Input: get_next_request() > read_next_request()
. Area: p_min et p_max > coord_min et coord_max
- User interface
° Add the area to the result in OutputCSV.
° When reading the APs, add them to the mobiles' list (or another
way to be able to have a single entry for an AP).
° Rename minmax-start & stop, since it is used elsewhere (grep
minmax-start).
° Review the option names & descriptions.
° Add option positioning.self-calibrate (or autocalibrate), to
activate automatically the options needed by the autocalibration.
° Improve --verbose (and/or debug level): print the options, etc.
° Case-insensitive string comparison (for algorithm names, etc.).
° Use a prefix for configuration files (search for config files set
with relative path in owlps-positioning.cfg in the same directory).
- Optimisation & code improvement
° Multithread algorithm calls.
° ReferencePoint: the request list should be an unordered_set
instead of a vector, to guarantee the unicity of the elements.
- Unit tests
° Update tests (currently unmaintained).
° Unfinished tests:
@ -20,6 +63,9 @@
. Output
. Positioning
° Test InterlinkNetworks::compute() ?
° Timestamp: there is a probability of 10^-6 that the value in
nanoseconds and the rounded value in milliseconds are identical, in
which case some tests can fail.
- Revoir le diagramme UML
° Associations : devraient êtres représentées par des attributs
@ -27,25 +73,6 @@
° Compositions : devraient être représentées par des attributs
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 »
° Espaces de noms ? 109
° Réserver l'espace mémoire des vector avec reserve(). 217
@ -59,11 +86,3 @@
publics. La classe Direction (et maintenant Timestamp) tend à
respecter ce principe en utilisant mieux les opérateurs et en ne
proposant pas d'accesseur direct.
- 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.

View File

@ -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
1 # Mobiles' physical description file.
2 #
3 # Each line follows this format:
4 # MAC address;Antenna gain (dBi);Trx power (dBm)
5 #
6 # Blank lines are ignored. Commented lines must have a sharp (#) as
7 # their FIRST character.
8 # Example mobile:
9 #aa:bb:cc:dd:ee:ff;1.8;18.0

View File

@ -10,6 +10,10 @@
ap-medium = 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.
# You probably don't need a full description of the topology, see the
# topology example file for details.
@ -59,6 +63,59 @@ csv-file = /tmp/owlps-positioning.log
# request is compared directly to each calibration request.
#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]
# This is the default output if none is specified.

View File

@ -13,7 +13,7 @@ using namespace std ;
AccessPointsReaderCSV::AccessPointsReaderCSV(const string &file_name):
file(file_name)
{
read_access_points() ;
read_devices() ;
}
@ -21,18 +21,19 @@ AccessPointsReaderCSV::AccessPointsReaderCSV(const string &file_name):
/* *** Operations *** */
void AccessPointsReaderCSV::read_access_points()
void AccessPointsReaderCSV::read_devices()
{
while (file.next_line())
process_access_point_line() ;
process_device_line() ;
}
void AccessPointsReaderCSV::process_access_point_line()
void AccessPointsReaderCSV::process_device_line()
{
string mac ;
if (! file.read_field(mac))
throw malformed_input_data("Cannot read access point MAC address!") ;
PosUtil::to_upper(mac) ;
Point3D coord ;
if (! file.read_point3d(coord))
@ -52,6 +53,6 @@ void AccessPointsReaderCSV::process_access_point_line()
string ip("") ;
AccessPoint ap(coord, ip, mac, gain, power, frequency) ;
Stock::find_create_ap(ap) ;
AccessPoint device(coord, ip, mac, gain, power, frequency) ;
Stock::find_create_ap(device) ;
}

View File

@ -17,8 +17,8 @@ class AccessPointsReaderCSV
protected:
CSVFileReader file ;
void read_access_points(void) ;
void process_access_point_line(void) ;
void read_devices(void) ;
void process_device_line(void) ;
public:
AccessPointsReaderCSV(const std::string &file_name) ;

View File

@ -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
* deleted and nullified, unless it is the same pointer (see the code to
* understand!); hmm, maybe we should handle that with exceptions

View File

@ -30,6 +30,12 @@ CalibrationRequest(const Request &source,
/* *** Write accessors *** */
void CalibrationRequest::reference_point_delete_requests() const
{
reference_point->delete_requests() ;
}
void CalibrationRequest::reference_point_backward_link() const
{
reference_point->add_request(this) ;

View File

@ -41,6 +41,8 @@ public:
void set_reference_point(const ReferencePoint *_rp) ;
/// Adds the CalibrationRequest to the #reference_point list of requests
void reference_point_backward_link(void) const ;
/// Deletes all the requests of #reference_point
void reference_point_delete_requests(void) const ;
void clear(void) ;
//@}

View File

@ -5,5 +5,5 @@
Result CartographyAlgorithm::compute(const Request &request)
{
Point3D position(select_point(request)) ;
return Result(position, name) ;
return Result(&request, name, position) ;
}

View File

@ -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)
{
return configuration[key].as<bool>() ;

View File

@ -21,6 +21,8 @@ public:
static const std::string& string_value(const std::string &key) ;
/// Returns the int value corresponding to \em 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
static bool bool_value(const std::string &key) ;
/// Checks if a given string value exists in \em key

View File

@ -101,9 +101,9 @@ bool CSVFileReader::read_point3d(Point3D &p)
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() ;
return false ;

View File

@ -12,7 +12,7 @@ Result FRBHMBasic::compute(const Request &_request)
compute_ap_distance_circles() ;
Point3D position(multilaterate_2d(closest_in_ss->get_z())) ;
return Result(position, name) ;
return Result(request, name, position) ;
}

View File

@ -7,6 +7,7 @@
#include "posexcept.hh"
#include "stock.hh"
#include <iostream>
#include <string>
using namespace std ;
@ -113,8 +114,39 @@ const Request& Input::get_next_request() const
{
if (! eof())
{
medium->get_next_request() ;
const Request& request = medium->get_next_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() ;

View File

@ -45,6 +45,12 @@ const Request& InputCSV::get_next_request()
cerr << "InputCSV: cannot read mac_mobile.\n" ;
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) ;
current_request->set_mobile(&mobile) ;
@ -114,11 +120,21 @@ const Request& InputCSV::get_next_request()
cerr << "InputCSV: cannot read mac_ap.\n" ;
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) ;
measurements[mac_ap].set_ap(&ap) ;
measurements[mac_ap].add_ss(ss) ;
}
if (measurements.empty())
{
current_request->clear() ;
return *current_request ;
}
current_request->set_measurements(measurements) ;
// Calibration request?

View File

@ -1,5 +1,6 @@
#include "inputdatareader.hh"
#include "accesspointsreadercsv.hh"
#include "mobilesreadercsv.hh"
#include "topologyreadercsv.hh"
#include "inputcsv.hh"
#include "calibrationrequest.hh"
@ -19,6 +20,7 @@ using namespace std ;
InputDataReader::InputDataReader()
{
read_access_points() ;
read_mobiles() ;
read_topology() ;
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 *** */
@ -193,27 +240,18 @@ void InputDataReader::read_from_reference_points_media()
while (! (*i)->eof())
{
const Request &request = (*i)->get_next_request() ;
if (! request)
continue ;
CalibrationRequest *calibration_request =
dynamic_cast<CalibrationRequest*>(
const_cast<Request*>(&request)) ;
if (calibration_request == NULL)
cerr << "Warning! Invalid calibration request at line "
<< (*i)->get_current_line_nb() << endl ;
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() ;
}

View File

@ -16,6 +16,10 @@ protected:
void initialise_access_points_media(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 initialise_topology_media(void) ;
void initialise_topology_csv(void) ;
@ -24,8 +28,6 @@ protected:
void initialise_reference_points_media(void) ;
void initialise_reference_points_csv(void) ;
void read_from_reference_points_media(void) ;
void stock_calibration_request(
const CalibrationRequest &request) const ;
public:
InputDataReader(void) ;

View File

@ -1,6 +1,7 @@
#include "inputudpsocket.hh"
#include "posexcept.hh"
#include "stock.hh"
#include "configuration.hh"
#include <owlps.h>
@ -106,8 +107,14 @@ const Request& InputUDPSocket::get_next_request()
request.nb_info = ntohs(request.nb_info) ;
// Mobile MAC
const char *const mac_mobile =
owl_mac_bytes_to_string(request.mobile_mac_addr_bytes) ;
string mac_mobile(
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) ;
current_request->set_mobile(&mobile) ;
@ -135,20 +142,50 @@ const Request& InputUDPSocket::get_next_request()
current_request->clear() ;
return *current_request ;
}
const char *const mac_ap =
owl_mac_bytes_to_string(request_info.ap_mac_addr_bytes) ;
string mac_ap(
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) ;
measurements[mac_ap].set_ap(&ap) ;
measurements[mac_ap].add_ss(static_cast<int_fast8_t>
(request_info.antenna_signal_dbm)) ;
}
if (measurements.empty())
{
current_request->clear() ;
return *current_request ;
}
current_request->set_measurements(measurements) ;
// Calibration request?
if (request.type == OWL_REQUEST_CALIBRATION ||
request.type == OWL_REQUEST_AUTOCALIBRATION)
if ((request.type == OWL_REQUEST_CALIBRATION ||
request.type == OWL_REQUEST_AUTOCALIBRATION)
&&
(Configuration::bool_value("positioning.accept-new-aps") ||
Stock::ap_exists(mac_mobile)))
{
AccessPoint &transmitter =
const_cast<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 =
Stock::find_create_reference_point(position) ;
current_request_to_calibration_request(&reference_point,

View File

@ -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) ;
}

View File

@ -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_

View File

@ -70,7 +70,7 @@ Result MultilaterationAlgorithm::compute(const Request &_request)
compute_ap_distance_circles() ;
Point3D position(multilaterate()) ;
return Result(position, name) ;
return Result(request, name, position) ;
}

View File

@ -5,6 +5,7 @@
#include "outputterminal.hh"
#include "outputcsv.hh"
#include "outputudpsocket.hh"
#include "outputtcpsocketevaal.hh"
#include <string>
@ -57,6 +58,9 @@ void Output::initialise_output_media()
else if (*i == "UDP")
initialise_output_udp_socket() ;
else if (*i == "TCPEvAAL")
initialise_output_tcpevaal_socket() ;
else
throw bad_configuration(
"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()
{
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
{
for (vector<OutputMedium*>::const_iterator i = output_media.begin() ;

View File

@ -19,6 +19,7 @@ protected:
void initialise_output_terminal(void) ;
void initialise_output_csv(void) ;
void initialise_output_udp_socket(void) ;
void initialise_output_tcpevaal_socket(void) ;
//@}
public:

View File

@ -11,5 +11,6 @@ void OutputCSV::write(const Result &result)
void OutputCSV::write(const ResultList &results)
{
file.write_text(results.to_csv() + '\n') ;
if (! results.empty())
file.write_text(results.to_csv() + '\n') ;
}

View File

@ -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 ;
}

View File

@ -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_

View File

@ -1,5 +1,6 @@
#include "outputterminal.hh"
#include "resultlist.hh"
#include "configuration.hh"
@ -12,5 +13,10 @@ void OutputTerminal::write(const Result &result)
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 ;
}

View File

@ -80,7 +80,8 @@ void OutputUDPSocket::write(const Result &result)
void OutputUDPSocket::write(const ResultList &results)
{
send_data(results.to_csv()) ;
if (! results.empty())
send_data(results.to_csv()) ;
}

View File

@ -1,4 +1,5 @@
#include "point3d.hh"
#include "posutil.hh"
#include "posexcept.hh"
#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 *** */

View File

@ -44,7 +44,7 @@ public:
void set_coordinates(const Point3D &source) ;
//@}
/** @name Distance operations */
/** @name Distance & angles operations */
//@{
/// Square euclidean distance to a Point3D
float square_distance(const Point3D &p) const ;
@ -61,6 +61,8 @@ public:
/// Euclidean distance to the radius of a sphere
float distance_to_sphere(const Point3D &centre,
const float radius) const ;
/// Angle BÂC (A being *this)
double angle(const Point3D &b, const Point3D &c) const ;
//@}
/** @name Operators */

View File

@ -11,6 +11,8 @@
#include <owlps.h>
#include <iostream>
using namespace std ;
@ -97,7 +99,21 @@ void Positioning::loop()
for (algo = algorithms.begin() ; algo != algorithms.end() ;
++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)
res.compute_error(real_position) ;
else if ((*algo)->get_name() == "Real")
@ -105,6 +121,7 @@ void Positioning::loop()
compute_error = true ;
real_position = res.get_position() ;
}
results.add(res) ;
}

View File

@ -5,11 +5,23 @@
#include <owlps.h>
#include <cmath>
using namespace std ;
using std::tr1::unordered_map ;
/* *** Maths *** */
double PosUtil::rad2deg(const double &radians)
{
return radians * (180.0 / M_PI) ;
}
/* *** Measurements *** */
@ -151,3 +163,21 @@ unsigned long PosUtil::wifi_channel_to_hz(const unsigned long &channel)
// Error: wrong channel value
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 ;
}

View File

@ -4,6 +4,7 @@
class Measurement ;
#include <boost/tr1/unordered_map.hpp>
#include <boost/algorithm/string/case_conv.hpp>
/// Utilitary class
class PosUtil
@ -12,6 +13,12 @@ public:
/// The speed of light, in m/s
static const unsigned long LIGHT_SPEED = 299792458 ;
/** @name Maths */
//@{
/// Return the degree value of \em radians
static double rad2deg(const double &radians) ;
//@}
/** @name Measurements */
//@{
/// Mutually completes two Measurement lists with missing APs
@ -29,6 +36,35 @@ public:
/// Converts a Wi-Fi channel to the corresponding frequency in Hz
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_

View File

@ -17,7 +17,7 @@ Result RealPosition::compute(const Request &request)
coordinates = request.get_real_position() ;
if (coordinates)
return Result(*coordinates, name) ;
return Result(&request, name, *coordinates) ;
return Result(name) ;
return Result(&request, name) ;
}

View File

@ -25,6 +25,26 @@ ReferencePoint::~ReferencePoint()
/* *** 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::
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 *** */
@ -115,6 +238,7 @@ float ReferencePoint::friis_indexes_for_ap(
double friis_idx_sum = 0 ;
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
@ -130,8 +254,8 @@ float ReferencePoint::friis_indexes_for_ap(
measurements.find(ap_mac) ;
if (measurement != measurements.end())
{
float distance = this->distance(ap.get_coordinates()) ;
double ss = measurement->second.get_average_ss() ;
assert((*request)->get_mobile()) ;
float mobile_gain =
(*request)->get_mobile()->get_antenna_gain() ;
friis_idx_sum +=

View File

@ -25,6 +25,12 @@ protected:
//@{
std::tr1::unordered_map<std::string, Measurement>
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:
@ -42,12 +48,17 @@ public:
/** @name Read accessors */
//@{
const std::vector<CalibrationRequest*>& get_requests(void) const ;
double average_measurements(const std::string &mac_transmitter) const ;
//@}
/** @name Write accessors */
//@{
/// 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 */
@ -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.
* The memory pointed by this pointer must not be deallocated before
* the ReferencePoint destruction (do \em not pass a pointer to a local
* variable!).
*/
inline void ReferencePoint::add_request(const CalibrationRequest *cm)
inline void ReferencePoint::add_request(const CalibrationRequest *r)
{
if (cm != NULL)
requests.push_back(const_cast<CalibrationRequest*>(cm)) ;
if (r != NULL)
requests.push_back(const_cast<CalibrationRequest*>(r)) ;
}

View File

@ -1,5 +1,7 @@
#include "result.hh"
#include "request.hh"
#include "area.hh"
#include "stock.hh"
#include <sstream>
@ -10,15 +12,31 @@ using namespace std ;
/* *** 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):
position(_position), algorithm(_algorithm)
request(_request), algorithm(_algorithm), position(_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 *** */
@ -37,6 +55,7 @@ const Result& Result::operator=(const Result &source)
if (this == &source)
return *this ;
request = source.request ;
algorithm = source.algorithm ;
position = source.position ;
error = source.error ;
@ -48,6 +67,7 @@ const Result& Result::operator=(const Result &source)
bool Result::operator==(const Result &source) const
{
return
request == source.request &&
algorithm == source.algorithm &&
position == source.position &&
error == source.error ;
@ -79,7 +99,8 @@ std::ostream& operator<<(ostream &os, const Result &r)
{
os
<< "The result of the algorithm " << r.algorithm
<< " is: " << r.position ;
<< " is: " << r.position
<< " (area: « " << r.in_which_area() << " »)" ;
if (r.error >= 0)
os << ", error = " << r.error << " m" ;
return os ;

View File

@ -1,6 +1,8 @@
#ifndef _OWLPS_POSITIONING_RESULT_HH_
#define _OWLPS_POSITIONING_RESULT_HH_
class Request ;
#include "point3d.hh"
#include <string>
@ -9,28 +11,35 @@
class Result
{
protected:
/// Computed coordinates of the mobile
Point3D position ;
/// Request sent by the mobile
const Request *request ;
/// Algorithm used to compute the position
std::string algorithm ;
/// Computed coordinates of the mobile
Point3D position ;
/// Distance error between the real coordinates and the computed point
/** The error is set to -1 if the real coordinates are unknown. */
float error ;
public:
Result(const std::string &_algorithm = "UnknownAlgorithm"):
algorithm(_algorithm), error(-1) {}
Result(const Point3D &_position, const std::string &_algorithm):
position(_position), algorithm(_algorithm), error(-1) {}
Result(const Point3D &_position, const std::string &_algorithm,
const Point3D &real_position) ;
Result(const Request *_request = NULL,
const std::string &_algorithm = "UnknownAlgorithm"):
request(_request), algorithm(_algorithm), error(-1) {}
Result(const Request *_request, const std::string &_algorithm,
const Point3D &_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) {}
/** @name Read accessors */
//@{
const Request* get_request(void) const ;
const std::string& get_algorithm(void) const ;
const Point3D& get_position(void) const ;
float get_error(void) const ;
std::string in_which_area(void) const ;
//@}
/** @name Write accessors */
@ -60,6 +69,12 @@ public:
/* *** Read accessors *** */
inline const Request* Result::get_request() const
{
return request ;
}
inline const std::string& Result::get_algorithm() const
{
return algorithm ;

View File

@ -25,6 +25,8 @@ public:
/** @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 std::vector<Result>& get_results(void) const ;
//@}
@ -57,6 +59,12 @@ public:
/* *** Read accessors *** */
inline bool ResultList::empty() const
{
return results.empty() ;
}
inline const Request* ResultList::get_request() const
{
return request ;

View File

@ -1,5 +1,9 @@
#include "stock.hh"
#include "configuration.hh"
#include "posexcept.hh"
#include "area.hh"
#include <iostream>
using namespace std ;
using std::tr1::unordered_map ;
@ -15,6 +19,8 @@ unordered_map<Point3D, Waypoint> Stock::waypoints ;
unordered_map<string, Mobile> Stock::mobiles ;
uint32_t Stock::nb_virtual_mobiles = 0 ;
unordered_map<string, AccessPoint> Stock::aps ;
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 *** */
@ -115,6 +141,19 @@ void Stock::waypoint_remove_building(const Waypoint &point,
/* *** 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.
* 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 *** */
/**
* @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.
* 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] ;
ap.set_mac_addr(mac) ;
if (Configuration::is_configured("verbose"))
cerr
<< "New AP « " << mac
<< " » (total: " << nb_aps() << " APs).\n" ;
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 *** */
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::
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'"
" list is empty!") ;
bool ignore_aps = Configuration::bool_value(
"positioning.radar-ignore-ap-reference-points") ;
unordered_set<ReferencePoint>::const_iterator i =
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) ;
unordered_set<ReferencePoint>::const_iterator closest = i ;
for (++i ; i != reference_points.end() ; ++i)
{
if (ignore_aps && is_ap_coordinate(*i))
continue ;
float tmp_distance = i->ss_square_distance(request) ;
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 &current_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(&current_rp) ;
store_calibration_request(cr) ;
}
}
/* *** 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::
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"
" requests' list is empty!") ;
bool ignore_aps = Configuration::bool_value(
"positioning.radar-ignore-ap-reference-points") ;
unordered_set<CalibrationRequest>::const_iterator i =
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) ;
unordered_set<CalibrationRequest>::const_iterator closest = 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) ;
if (tmp_distance < distance)
{

View File

@ -26,6 +26,9 @@ private:
/** The string key of the map is the Mobile MAC address. */
static std::tr1::unordered_map<std::string, Mobile> mobiles ;
/// Number of generated "virtual" mobiles
static uint32_t nb_virtual_mobiles ;
/// List of known AccessPoint
/** The string key of the map is the AccessPoint MAC address. */
static std::tr1::unordered_map<std::string, AccessPoint> aps ;
@ -47,6 +50,8 @@ public:
static const Building& get_building(const std::string &name) ;
/// Searches for a Building and creates it if it does not exist
static const Building& find_create_building(const std::string &name) ;
/// Searches the Area in which \em point is
static const Area* in_which_area_is(const Point3D point) ;
//@}
/** @name Waypoint operations */
@ -68,10 +73,17 @@ public:
/** @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
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) ;
/// 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
/// given MAC address
static Mobile& getw_mobile(const std::string &mac) ;
@ -81,24 +93,40 @@ public:
//@{
/// Returns the number of access points
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
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
/// creates it if it does not exist
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
/// given MAC address
static AccessPoint& getw_ap(const std::string &mac) ;
/// Updates the friis indexes of all the APs
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 */
//@{
/// Returns the number of reference points
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
static const ReferencePoint&
find_create_reference_point(const ReferencePoint &point) ;
@ -106,12 +134,22 @@ public:
/// strength space) to a given Request
static const ReferencePoint&
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 */
//@{
/// Returns the number of calibration requests
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
static const CalibrationRequest&
find_create_calibration_request(const CalibrationRequest &request) ;
@ -161,6 +199,12 @@ find_create_waypoint(const Waypoint &point)
/* *** Mobile operations *** */
inline unsigned int Stock::nb_mobiles()
{
return mobiles.size() ;
}
/**
* 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
@ -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
* created.

View File

@ -17,6 +17,9 @@ namespace po = boost::program_options ;
#define DEFAULT_CONFIG_FILE_NAME \
"/usr/local/etc/owlps/owlps-positioning.cfg"
#define DEFAULT_TCPEVAAL_HOST "127.0.0.1"
#define DEFAULT_TCPEVAAL_PORT 4444
/* *** Constructors *** */
@ -106,6 +109,13 @@ void UserInterface::fill_data_input_options()
("data-input.ap-csv-file", po::value<string>(),
"CSV file to use for access points input (when"
" 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> >()
->composing(),
"Medium from which topology (buildings, areas and waypoints) is"
@ -186,6 +196,49 @@ void UserInterface::fill_positioning_options()
" before to compute the SS distance."
" The default is false, i.e the positioning request is compared"
" 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) ;
@ -199,8 +252,9 @@ void UserInterface::fill_output_options()
options.add_options()
("output.medium,O", po::value< vector<string> >()->composing(),
"Medium to which the results will be wrote. You can specify"
" this option more than once. Allowed: Terminal, CSV, UDP."
" If this option is absent, results will be printed on the terminal.")
" this option more than once."
" Allowed: Terminal, CSV, UDP, TCPEvAAL."
" If this option is absent, the results are printed on the terminal.")
("output.csv-file", po::value<string>(),
"CSV file to use for output (when output.medium = CSV).")
("output.udp-host", po::value<string>(),
@ -208,6 +262,12 @@ void UserInterface::fill_output_options()
("output.udp-port", po::value<int>()
->default_value(MOBILE_DEFAULT_PORT),
"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) ;

View File

@ -1,6 +1,8 @@
#ifndef _OWLPS_POSITIONING_WIFIDEVICE_HH_
#define _OWLPS_POSITIONING_WIFIDEVICE_HH_
#include "posutil.hh"
#include <string>
#include <ostream>
@ -21,12 +23,10 @@ protected:
float trx_power ; ///< Transmit power in dBm
public:
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) {}
WifiDevice(const std::string &_ip_addr,
const std::string &_mac_addr,
const float _antenna_gain,
const float _trx_power) ;
WifiDevice(const WifiDevice &source):
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 *** */
@ -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)
{
PosUtil::assert_uppercase(_mac_addr) ;
mac_addr = _mac_addr ;
}