Owl Positioning System: a Wi-Fi-based, infrastructure-centred indoor positioning system. http://owlps.pu-pm.univ-fcomte.fr/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

owlps-client.c 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  1. /*
  2. * This file is part of the Owl Positioning System (OwlPS) project.
  3. * It is subject to the copyright notice and license terms in the
  4. * COPYRIGHT.t2t file found in the top-level directory of this
  5. * distribution and at
  6. * https://code.lm7.fr/mcy/owlps/src/master/COPYRIGHT.t2t
  7. * No part of the OwlPS Project, including this file, may be copied,
  8. * modified, propagated, or distributed except according to the terms
  9. * contained in the COPYRIGHT.t2t file; the COPYRIGHT.t2t file must be
  10. * distributed along with this file, either separately or by replacing
  11. * this notice by the COPYRIGHT.t2t file's contents.
  12. *
  13. ***********************************************************************
  14. *
  15. * This is the main source file of OwlPS Client, the program used to
  16. * send positioning requests to the infrastructure.
  17. */
  18. #include <owlps-client-config.h>
  19. #include <owlps-client.h>
  20. #ifdef OWLPS_CLIENT_RECEIVES_POSITION
  21. # include <owlps-resultreader.h>
  22. #endif // OWLPS_CLIENT_RECEIVES_POSITION
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <unistd.h>
  26. #include <inttypes.h>
  27. #include <string.h>
  28. #include <signal.h>
  29. #include <net/if.h>
  30. #include <sys/param.h> // for MAXHOSTNAMELEN
  31. /* Number of packets to send */
  32. #define DEFAULT_NBPKT_CALIB 20 // 20 packets when calibrating
  33. #define DEFAULT_NBPKT_NORMAL 10 // 10 packets when requesting the position
  34. /* Delay between two packet transmissions (in milliseconds) */
  35. #define DEFAULT_DELAY_CALIB 50 // Calibration request
  36. #define DEFAULT_DELAY_NORMAL 25 // Localisation request
  37. /* Delay between two requests in loop mode (in milliseconds) */
  38. #define DEFAULT_FLOOD_DELAY 1000
  39. /* Maximal size of a packet */
  40. #define MAX_PKT_SIZE 1450u
  41. /* Program arguments (getopt string) */
  42. #define OPTIONS "DF::hi:I:l::n:N:p:qs:t:vV"
  43. /* Function headers */
  44. void parse_command_line(const int argc, char *const *argv) ;
  45. void parse_main_options(const int argc, char *const *argv) ;
  46. void check_destination_host(void) ;
  47. void parse_calibration_data(const int argc, char *const *argv) ;
  48. void check_configuration(void) ;
  49. void print_configuration(void) ;
  50. void create_socket(void) ;
  51. void send_request(void) ;
  52. void make_packet(void) ;
  53. void add_padding(void) ;
  54. uint_fast16_t initialise_common_fields(const uint_fast8_t packet_type) ;
  55. uint_fast16_t initialise_calibration_fields(uint_fast16_t offset) ;
  56. #ifdef OWLPS_CLIENT_RECEIVES_POSITION
  57. int receive_position(void) ;
  58. #endif // OWLPS_CLIENT_RECEIVES_POSITION
  59. void print_usage(void) ;
  60. void print_version(void) ;
  61. /* Options */
  62. // TODO: the size of this structure could be reduced by reordering its fields.
  63. struct {
  64. bool daemon ;
  65. bool verbose ;
  66. char dest_host[MAXHOSTNAMELEN] ; // Destination host of the packets
  67. // 6 bytes alignment
  68. uint_fast16_t dest_port ;
  69. char iface[IFNAMSIZ + 1] ; // Source network interface
  70. // 7 bytes alignment
  71. int_fast32_t delay ; // Time between two packet transmissions
  72. uint_fast16_t nb_pkt ; // Number of packets to send
  73. uint_fast16_t pkt_size ; // Size of the packet to send
  74. int_fast32_t flood_delay ; // Time between two request transmissions
  75. bool add_flood_delay ; // Add the delay to the transmission time?
  76. // 7 bytes alignment
  77. uint_fast16_t nb_requests ; // Number of requests to send
  78. uint_fast16_t listening_port ;
  79. // Calibration data:
  80. owl_direction direction ;
  81. // 3 bytes alignment
  82. float x ;
  83. float y ;
  84. float z ;
  85. } options = {
  86. false, // daemon
  87. true, // verbose
  88. "", // dest_host
  89. OWL_DEFAULT_REQUEST_PORT, // dest_port
  90. "", // iface
  91. -1, // delay
  92. 0, // nb_pkt
  93. 0, // pkt_size
  94. -1, // flood_delay
  95. false, // add_flood_delay
  96. 0, // nb_requests
  97. 0, // listening_port
  98. 0, 0, 0, 0 // Calibration data
  99. } ;
  100. char *program_name = NULL ;
  101. // true if the packet is a calibration request, false if it is
  102. // a simple positioning request:
  103. bool is_calibration_request = false ;
  104. int sockfd ; // Sending socket descriptor
  105. struct sockaddr server ; // Server info
  106. uint8_t *packet = NULL ; // Packet to send
  107. uint_fast16_t packet_size ; // Packet size
  108. int main(int argc, char *argv[])
  109. {
  110. struct sigaction action ; // Signal handler structure
  111. int ret = 0 ;
  112. // Number of requests we still have to transmit:
  113. uint_fast16_t nb_requests_left = 1 ;
  114. owl_timestamp start_time ; // Time of the transmission's start
  115. owl_run = true ;
  116. program_name = argv[0] ;
  117. parse_command_line(argc, argv) ;
  118. if (options.daemon)
  119. {
  120. if (options.verbose)
  121. fprintf(stderr, "Detaching to background...\n") ;
  122. if (daemon(0, 0))
  123. perror("Cannot daemonize") ;
  124. }
  125. /* Set up signal handlers */
  126. action.sa_flags = 0 ;
  127. sigemptyset(&action.sa_mask) ;
  128. action.sa_handler = owl_sigint_handler ;
  129. sigaction(SIGINT, &action, NULL) ;
  130. action.sa_handler = owl_sigterm_handler ;
  131. sigaction(SIGTERM, &action, NULL) ;
  132. create_socket() ;
  133. /* Transmit the first request */
  134. if (! options.add_flood_delay)
  135. owl_timestamp_now(&start_time) ;
  136. send_request() ;
  137. if (options.nb_requests)
  138. nb_requests_left = options.nb_requests - 1 ;
  139. /* Transmit the next requests, if any */
  140. while (owl_run && options.flood_delay >= 0 && nb_requests_left > 0)
  141. {
  142. uint_fast32_t trx_time, sleep_time ;
  143. owl_timestamp now ;
  144. if (options.verbose && options.nb_requests)
  145. printf("%"PRIuFAST16" more requests to transmit.\n",
  146. nb_requests_left) ;
  147. if (options.add_flood_delay)
  148. owl_msleep(options.flood_delay) ;
  149. else
  150. {
  151. owl_timestamp_now(&now) ;
  152. trx_time = owl_time_elapsed_ms(&start_time, &now) ;
  153. if (options.verbose)
  154. printf("Transmission time was %"PRIuFAST32" ms", trx_time) ;
  155. // Sleep only if the sleep delay is greater than the
  156. // transmission time
  157. if (trx_time < (uint_fast32_t) options.flood_delay)
  158. {
  159. sleep_time = options.flood_delay - trx_time ;
  160. if (options.verbose)
  161. printf(", sleeping for %"PRIuFAST32" ms...\n",
  162. sleep_time) ;
  163. owl_msleep(sleep_time) ;
  164. }
  165. else if (options.verbose)
  166. printf(" > %"PRIdFAST32" ms, no sleeping required.\n",
  167. options.flood_delay) ;
  168. owl_timestamp_now(&start_time) ;
  169. }
  170. if (owl_run) // owl_run can have been set to false during the sleep
  171. {
  172. send_request() ;
  173. if (options.nb_requests)
  174. --nb_requests_left ;
  175. }
  176. }
  177. close(sockfd) ;
  178. #ifdef OWLPS_CLIENT_RECEIVES_POSITION
  179. if (options.listening_port > 0)
  180. ret = receive_position() ;
  181. #endif // OWLPS_CLIENT_RECEIVES_POSITION
  182. return ret ;
  183. }
  184. void parse_command_line(const int argc, char *const *argv)
  185. {
  186. parse_main_options(argc, argv) ;
  187. check_destination_host() ;
  188. parse_calibration_data(argc, argv) ;
  189. check_configuration() ;
  190. if (options.verbose)
  191. print_configuration() ;
  192. }
  193. void parse_main_options(const int argc, char *const *argv)
  194. {
  195. int opt ;
  196. long arg_long ; // Integer value of optarg
  197. char *endptr ; // Return value of strto*()
  198. while ((opt = getopt(argc, argv, OPTIONS)) != -1)
  199. {
  200. switch (opt)
  201. {
  202. case 'D' :
  203. options.daemon = true ;
  204. break ;
  205. case 'F' :
  206. /* If -F is present, first set the flood delay to its default
  207. * value (this can appear suboptimal when the user supplies a
  208. * value, but will simplify the operations).
  209. */
  210. options.flood_delay = DEFAULT_FLOOD_DELAY ;
  211. /* Facultative getopt options do not handle separated values
  212. * (like -F <delay>), so we have to test separately.
  213. */
  214. if (optarg) // We got an option like -F<delay>, it's OK
  215. {
  216. arg_long = strtol(optarg, &endptr, 10) ;
  217. if (endptr != optarg)
  218. options.flood_delay = arg_long ;
  219. else
  220. fprintf(stderr, "Warning! Bad flood_delay:"
  221. " failing back to the default value.\n") ;
  222. if (optarg[0] == '+')
  223. options.add_flood_delay = true ;
  224. }
  225. else // We got -F alone or -F <delay>
  226. {
  227. /* If we are not at the end of the string and the next
  228. * optind is not an option, we have the option with a
  229. * separate argument. Otherwise we got the option alone,
  230. * but we have nothing to do since we already set the
  231. * default value.
  232. */
  233. if (argv[optind] != NULL && argv[optind][0] != '-')
  234. {
  235. // Take the optind value:
  236. arg_long = strtol(argv[optind], &endptr, 10) ;
  237. if (endptr != argv[optind])
  238. options.flood_delay = arg_long ;
  239. else
  240. fprintf(stderr, "Warning! Bad flood_delay:"
  241. " failing back to the default value.\n") ;
  242. if (argv[optind][0] == '+')
  243. options.add_flood_delay = true ;
  244. ++optind ;
  245. }
  246. }
  247. break ;
  248. case 'h' :
  249. print_usage() ;
  250. exit(0) ;
  251. case 'I' :
  252. strncpy(options.iface, optarg, IFNAMSIZ + 1) ;
  253. break ;
  254. case 'i' :
  255. strncpy(options.dest_host, optarg, MAXHOSTNAMELEN) ;
  256. break ;
  257. case 'l' :
  258. #ifdef OWLPS_CLIENT_RECEIVES_POSITION
  259. /* If -l is present, first set the listening port to its
  260. * default value (this can appear suboptimal when the user
  261. * supplies a port number, but will simplify the operations).
  262. */
  263. options.listening_port = OWL_DEFAULT_RESULT_PORT ;
  264. /* Facultative getopt options do not handle separated values
  265. * (like -l <port>), so we have to test separately.
  266. */
  267. if (optarg) // We got an option like -l<port>, it's OK
  268. {
  269. unsigned long arg_ulong = strtoul(optarg, &endptr, 10) ;
  270. if (endptr != optarg)
  271. options.listening_port = arg_ulong ;
  272. else
  273. fprintf(stderr, "Warning! Bad listening_port:"
  274. " failing back to the default value.\n") ;
  275. }
  276. else // We got -l alone or -l <port>
  277. {
  278. /* If we are not at the end of the string and the next
  279. * optind is not an option, we have the option with a
  280. * separate argument. Otherwise we got the option alone,
  281. * but we have nothing to do since we already set the
  282. * default value.
  283. */
  284. if (argv[optind] != NULL && argv[optind][0] != '-')
  285. {
  286. // Take the optind value:
  287. unsigned long arg_ulong = strtoul(argv[optind],
  288. &endptr, 10) ;
  289. if (endptr != argv[optind])
  290. options.listening_port = arg_ulong ;
  291. else
  292. fprintf(stderr, "Warning! Bad listening_port:"
  293. " failing back to the default value.\n") ;
  294. ++optind ;
  295. }
  296. }
  297. #else // OWLPS_CLIENT_RECEIVES_POSITION
  298. fprintf(stderr, "Warning! The program was compiled without"
  299. " enabling the -l option (receive the position from"
  300. " the positioning server).\n") ;
  301. #endif // OWLPS_CLIENT_RECEIVES_POSITION
  302. break ;
  303. case 'n' :
  304. options.nb_pkt = strtoul(optarg, NULL, 10) ;
  305. break ;
  306. case 'N' :
  307. options.nb_requests = strtoul(optarg, NULL, 10) ;
  308. break ;
  309. case 'p' :
  310. options.dest_port = strtoul(optarg, NULL, 10) ;
  311. break ;
  312. case 'q' :
  313. options.verbose = false ;
  314. break ;
  315. case 's' :
  316. options.pkt_size = strtoul(optarg, NULL, 10) ;
  317. break ;
  318. case 't' :
  319. arg_long = strtol(optarg, &endptr, 10) ;
  320. if (endptr != optarg)
  321. options.delay = arg_long ;
  322. else
  323. fprintf(stderr, "Warning! Bad delay:"
  324. " failing back to the default value.\n") ;
  325. break ;
  326. case 'v' :
  327. options.verbose = true ;
  328. break ;
  329. case 'V' :
  330. print_version() ;
  331. exit(0) ;
  332. default :
  333. print_usage() ;
  334. exit(OWL_ERR_BAD_USAGE) ;
  335. }
  336. }
  337. }
  338. void check_destination_host()
  339. {
  340. /* Check if we got a destination host */
  341. if (options.dest_host[0] == '\0')
  342. {
  343. fprintf(stderr, "Error! You must specify a destination host"
  344. " (-i) .\n") ;
  345. print_usage() ;
  346. exit(OWL_ERR_BAD_USAGE) ;
  347. }
  348. }
  349. /* Parses remaining arguments (possible calibration data) */
  350. void parse_calibration_data(const int argc, char *const *argv)
  351. {
  352. /* No more arguments to parse */
  353. if (argc - optind == 0)
  354. return ;
  355. /* Exactly 4 more arguments */
  356. if (argc - optind == 4)
  357. {
  358. char *endptr ;
  359. is_calibration_request = true ;
  360. options.direction = strtoul(argv[optind], &endptr, 10) ;
  361. if (endptr == argv[optind])
  362. {
  363. fprintf(stderr,
  364. "Error in calibration data: wrong direction!\n") ;
  365. goto error ;
  366. }
  367. optind++ ;
  368. options.x = strtod(argv[optind], &endptr) ;
  369. if (endptr == argv[optind])
  370. {
  371. fprintf(stderr,
  372. "Error in calibration data: wrong X coordinate!\n") ;
  373. goto error ;
  374. }
  375. optind++ ;
  376. options.y = strtod(argv[optind], &endptr) ;
  377. if (endptr == argv[optind])
  378. {
  379. fprintf(stderr,
  380. "Error in calibration data: wrong Y coordinate!\n") ;
  381. goto error ;
  382. }
  383. optind++ ;
  384. options.z = strtod(argv[optind], &endptr) ;
  385. if (endptr == argv[optind])
  386. {
  387. fprintf(stderr,
  388. "Error in calibration data: wrong Z coordinate!\n") ;
  389. goto error ;
  390. }
  391. return ; // No error occurred
  392. }
  393. /* Bad number of arguments or parse error */
  394. error:
  395. print_usage() ;
  396. exit(OWL_ERR_BAD_USAGE) ;
  397. }
  398. void check_configuration()
  399. {
  400. // Delay not specified (or bad delay):
  401. if (options.delay < 0)
  402. {
  403. if (options.verbose)
  404. fprintf(stderr,
  405. "Warning! delay: failing back to default value.\n") ;
  406. if (is_calibration_request)
  407. options.delay = DEFAULT_DELAY_CALIB ;
  408. else
  409. options.delay = DEFAULT_DELAY_NORMAL ;
  410. }
  411. // Number of packet not specified (or bad number)
  412. if (options.nb_pkt < 1)
  413. {
  414. if (options.verbose)
  415. fprintf(stderr,
  416. "Warning! nb_pkt: failing back to default value.\n") ;
  417. if (is_calibration_request)
  418. options.nb_pkt = DEFAULT_NBPKT_CALIB ;
  419. else
  420. options.nb_pkt = DEFAULT_NBPKT_NORMAL ;
  421. }
  422. // Packet size too big
  423. if (options.pkt_size > MAX_PKT_SIZE)
  424. {
  425. if (options.verbose)
  426. fprintf(stderr,
  427. "Warning! pkt_size cannot be greater than %d bytes:"
  428. " failing back to %d.\n", MAX_PKT_SIZE, MAX_PKT_SIZE) ;
  429. options.pkt_size = MAX_PKT_SIZE ;
  430. }
  431. // Calibration request but bad direction
  432. if (is_calibration_request)
  433. if (options.direction < OWL_DIRECTION_MIN ||
  434. options.direction > OWL_DIRECTION_MAX)
  435. {
  436. fprintf(stderr, "Error! \"%"PRIu8"\" is not a valid"
  437. " direction.\n", options.direction) ;
  438. exit(OWL_ERR_BAD_USAGE) ;
  439. }
  440. // Check port numbers
  441. if (options.dest_port < 1 || options.dest_port > 65535)
  442. {
  443. fprintf(stderr, "Warning! Bad dest_port:"
  444. " failing back to default value.\n") ;
  445. options.dest_port = OWL_DEFAULT_REQUEST_PORT ;
  446. }
  447. if (options.listening_port > 65535)
  448. {
  449. fprintf(stderr, "Warning! listening_port too high: ignored.\n") ;
  450. options.listening_port = 0 ;
  451. }
  452. // We want to send a calibration request AND to be located, which is
  453. // not allowed:
  454. if (is_calibration_request && options.listening_port > 0)
  455. {
  456. fprintf(stderr, "Warning! You cannot wait for a server answer when"
  457. " you calibrate. Option -l ignored.\n") ;
  458. options.listening_port = 0 ;
  459. }
  460. if (options.flood_delay >= 0)
  461. {
  462. // We want to flood AND to be located, which is not allowed:
  463. if (options.listening_port > 0)
  464. {
  465. fprintf(stderr, "Warning! You cannot wait for a server answer"
  466. " when you flood. Option -l ignored.\n") ;
  467. options.listening_port = 0 ;
  468. }
  469. }
  470. else // Flood is unactivated
  471. {
  472. if (options.nb_requests)
  473. {
  474. fprintf(stderr, "Warning! The -N option can be used only along"
  475. " with -F. Option -N ignored.\n") ;
  476. options.nb_requests = 0 ;
  477. }
  478. if (options.daemon)
  479. {
  480. fprintf(stderr, "Warning! It is useless to detach from"
  481. " the foreground if the flood mode is not activated"
  482. " Option -D ignored.\n") ;
  483. options.daemon = false ;
  484. }
  485. }
  486. }
  487. void print_configuration()
  488. {
  489. printf("Options:\n"
  490. "\tDaemon: %s\n"
  491. "\tVerbose: %s\n"
  492. "\tDestination host: %s\n"
  493. "\tDestination port: %"PRIuFAST16"\n"
  494. "\tInterface: %s\n"
  495. "\tDelay (ms): %"PRIdFAST32"\n"
  496. "\tNumber of packets: %"PRIuFAST16"\n"
  497. "\tPacket size: %"PRIuFAST16"\n"
  498. "\tFlood delay (ms): %"PRIdFAST32"\n"
  499. "\tCumulative flood delay: %s\n"
  500. "\tNumber of requests: %"PRIuFAST16"\n"
  501. "\tListening port: %"PRIuFAST16"\n"
  502. "\tDirection: %"PRIu8"\n"
  503. "\tX: %f\n"
  504. "\tY: %f\n"
  505. "\tZ: %f\n"
  506. ,
  507. OWL_BOOL_TO_STRING(options.daemon),
  508. OWL_BOOL_TO_STRING(options.verbose),
  509. options.dest_host,
  510. options.dest_port,
  511. options.iface,
  512. options.delay,
  513. options.nb_pkt,
  514. options.pkt_size,
  515. options.flood_delay,
  516. OWL_BOOL_TO_STRING(options.add_flood_delay),
  517. options.nb_requests,
  518. options.listening_port,
  519. options.direction,
  520. options.x,
  521. options.y,
  522. options.z
  523. ) ;
  524. }
  525. void create_socket()
  526. {
  527. sockfd =
  528. owl_create_trx_socket(options.dest_host, options.dest_port,
  529. &server, options.iface) ;
  530. }
  531. /*
  532. * Prepares a new request and sends it.
  533. */
  534. void send_request()
  535. {
  536. make_packet() ;
  537. owl_send_request(sockfd, &server, packet, packet_size,
  538. options.nb_pkt, options.delay, options.verbose) ;
  539. free(packet) ;
  540. }
  541. /*
  542. * Creates the packet to send.
  543. */
  544. void make_packet()
  545. {
  546. uint_fast16_t offset ; // Index used to create the packet
  547. if (is_calibration_request) // Calibration packet
  548. {
  549. if (options.verbose)
  550. printf("\nPreparing calibration request packet...\n") ;
  551. packet_size =
  552. sizeof(uint8_t) * 2 + sizeof(owl_timestamp) + sizeof(float) * 3 +
  553. sizeof(uint16_t) * 2 ;
  554. add_padding() ;
  555. packet = malloc(packet_size) ;
  556. if (! packet)
  557. {
  558. perror("Cannot allocate memory") ;
  559. abort() ;
  560. }
  561. offset = initialise_common_fields(OWL_REQUEST_CALIBRATION) ;
  562. offset += initialise_calibration_fields(offset) ;
  563. }
  564. else // Standard packet
  565. {
  566. if (options.verbose)
  567. printf("\nPreparing request packet...\n") ;
  568. packet_size =
  569. sizeof(uint8_t) + sizeof(owl_timestamp) + sizeof(uint16_t) * 2 ;
  570. add_padding() ;
  571. packet = malloc(packet_size) ;
  572. if (! packet)
  573. {
  574. perror("Cannot allocate memory") ;
  575. abort() ;
  576. }
  577. offset = initialise_common_fields(OWL_REQUEST_NORMAL) ;
  578. }
  579. // Initialize padding bytes with 0xFF:
  580. while (offset < packet_size)
  581. packet[offset++] = 0xFF ;
  582. }
  583. /*
  584. * Increases the packet size to add padding.
  585. */
  586. void add_padding()
  587. {
  588. if (options.pkt_size > packet_size)
  589. packet_size = options.pkt_size ;
  590. if (options.verbose)
  591. printf("Packet size: %"PRIuFAST16"\n", packet_size) ;
  592. }
  593. /*
  594. * Initialises the fields of a normal positioning request.
  595. */
  596. uint_fast16_t initialise_common_fields(const uint_fast8_t packet_type)
  597. {
  598. uint_fast16_t offset = 0 ;
  599. uint16_t npkt ;
  600. owl_timestamp request_time ;
  601. char request_time_str[OWL_TIMESTAMP_STRLEN] ;
  602. // Get the current time and copy it as a string before to switch it to
  603. // network endianness:
  604. owl_timestamp_now(&request_time) ;
  605. owl_timestamp_to_string(&request_time, request_time_str) ;
  606. owl_hton_timestamp(&request_time) ;
  607. // Packet type:
  608. memset(&packet[offset++], packet_type, 1) ;
  609. // Number of the current packet (1 for the first):
  610. npkt = htons(1u) ;
  611. memcpy(&packet[offset], &npkt, sizeof(uint16_t)) ;
  612. offset += sizeof(uint16_t) ;
  613. // Number of packets:
  614. npkt = htons(options.nb_pkt) ;
  615. memcpy(&packet[offset], &npkt, sizeof(uint16_t)) ;
  616. offset += sizeof(uint16_t) ;
  617. // Request time:
  618. memcpy(&packet[offset], &request_time, sizeof(request_time)) ;
  619. offset += sizeof(request_time) ;
  620. if (options.verbose)
  621. printf("Packet timestamp: %s\n", request_time_str) ;
  622. return offset ;
  623. }
  624. /*
  625. * Initialises the calibration data fields.
  626. */
  627. uint_fast16_t initialise_calibration_fields(uint_fast16_t offset)
  628. {
  629. float x, y, z ;
  630. // Direction:
  631. packet[offset++] = options.direction ;
  632. if (options.verbose)
  633. printf("Direction = %d, X = %f, Y = %f, Z = %f\n",
  634. packet[offset - 1], options.x, options.y, options.z) ;
  635. // Convert the coordinates to the network endianness:
  636. x = owl_htonf(options.x) ;
  637. y = owl_htonf(options.y) ;
  638. z = owl_htonf(options.z) ;
  639. // Copy the coordinates to the packet:
  640. memcpy(&packet[offset], &x, sizeof(float)) ;
  641. offset += sizeof(float) ;
  642. memcpy(&packet[offset], &y, sizeof(float)) ;
  643. offset += sizeof(float) ;
  644. memcpy(&packet[offset], &z, sizeof(float)) ;
  645. offset += sizeof(float) ;
  646. return offset ;
  647. }
  648. #ifdef OWLPS_CLIENT_RECEIVES_POSITION
  649. /*
  650. * Receives a position computed by the infrastructure.
  651. * Note that it is currently not guaranteed that the received result
  652. * correspond to the request sent.
  653. * Returns 0, or a non-zero value in case of error.
  654. */
  655. int receive_position()
  656. {
  657. owl_result *result ;
  658. printf("Waiting for the result from the infrastructure...\n") ;
  659. sockfd = owl_create_udp_listening_socket(options.listening_port) ;
  660. if (sockfd < 0)
  661. return OWL_ERR_SOCKET_CREATE ;
  662. result = owl_receive_position(sockfd) ;
  663. if (result == NULL)
  664. return OWL_ERR_SOCKET_RECV ;
  665. close(sockfd) ;
  666. owl_print_result(result) ;
  667. owl_free_result(result) ;
  668. return 0 ;
  669. }
  670. #endif // OWLPS_CLIENT_RECEIVES_POSITION
  671. /*
  672. * Prints the usage message on the standard output.
  673. *
  674. * /!\ Don't forget to update the documentation when modifying something
  675. * here!
  676. */
  677. void print_usage()
  678. {
  679. printf("Usage:\n"
  680. "Localisation request:\n"
  681. "\t%s"
  682. " [-v | -q]"
  683. " -i dest_host"
  684. " [-p dest_port]"
  685. " [-I iface]"
  686. " [-t delay]"
  687. "\n\t"
  688. " [-n nb_packets]"
  689. " [-s packet_size]"
  690. " [-F [[+]delay] [-N nb_requests] [-D]]"
  691. "\n\t"
  692. " [-l [port]]\n"
  693. "Calibration request:\n"
  694. "\t%s"
  695. " [-v | -q]"
  696. " -i dest_host"
  697. " [-p dest_port]"
  698. " [-I iface]"
  699. " [-t delay]"
  700. "\n\t"
  701. " [-n nb_packets]"
  702. " [-s packet_size]"
  703. " [-F [[+]delay] [-N nb_requests] [-D]]"
  704. "\n\t"
  705. " direction x y z\n"
  706. "Options:\n"
  707. "\t-h\t\tPrint this help.\n"
  708. "\t-V\t\tPrint version information.\n"
  709. "\t-v\t\tTurn on verbose mode (default).\n"
  710. "\t-q\t\tDo not print informational messages and some (less\n"
  711. "\t\t\timportant) warnings.\n"
  712. "\t-i dest_host\tName or IP address of the destination host of"
  713. " the\n\t\t\tlocalisation request.\n"
  714. "\t-p dest_port\tDestination port of the localisation request"
  715. " (default:\n\t\t\t%d).\n"
  716. "\t-t delay\tTime between each packet transmission in"
  717. " milliseconds\n\t\t\t(default: %d ms for a normal request,"
  718. " %d ms for a\n\t\t\tcalibration request).\n"
  719. "\t-n nb_packets\tNumber of packet transmitted for the request"
  720. " (default:\n\t\t\t%d for a normal request, %d for a"
  721. " calibration request).\n"
  722. "\t-s packet_size\tData size of the transmitted packets. The"
  723. " minimal value\n\t\t\tis the size of the request's data"
  724. " fields; if\n\t\t\t<packet_size> is less than this size, it is"
  725. " ignored.\n\t\t\tNote that this size does not take into"
  726. " account the\n\t\t\theaders, so the whole 802.11 frame will be"
  727. " bigger.\n"
  728. "\t-I iface\tName of the network interface used to transmit the"
  729. "\n\t\t\trequest (e.g. \"eth2\"). If this option is absent, the"
  730. "\n\t\t\tinterface is selected automatically. You must be root"
  731. " to\n\t\t\tuse this option.\n"
  732. "\t-F [delay]\t\"Flood mode\": loop indefinitely, sending a"
  733. " new request\n\t\t\tevery <delay> milliseconds (default:"
  734. " %d ms). If\n\t\t\t<delay> starts with a +, it is the time"
  735. " between two\n\t\t\trequests instead of the time between the"
  736. " start of the\n\t\t\ttransmission of two requests.\n"
  737. "\t-N nb_requests\tWith -F, stop after <nb_requests> requests"
  738. " transmitted\n\t\t\tinstead of looping indefinitely.\n"
  739. "\t-D\t\tDaemon mode. Useful only in flood mode.\n"
  740. "\t-l [port]\tWait for the computed position and display it."
  741. " The\n\t\t\toptional argument <port> allows to specify the"
  742. " listening\n\t\t\tport (default: %d). Available only if the"
  743. " program was\n\t\t\tcompiled with the compilation-time option"
  744. "\n\t\t\tOWLPS_CLIENT_RECEIVES_POSITION.\n"
  745. ,
  746. program_name,
  747. program_name,
  748. OWL_DEFAULT_REQUEST_PORT,
  749. DEFAULT_DELAY_NORMAL,
  750. DEFAULT_DELAY_CALIB,
  751. DEFAULT_NBPKT_NORMAL,
  752. DEFAULT_NBPKT_CALIB,
  753. DEFAULT_FLOOD_DELAY,
  754. OWL_DEFAULT_RESULT_PORT
  755. ) ;
  756. }
  757. void print_version()
  758. {
  759. printf("This is OwlPS Client, part of the Owl Positioning System"
  760. " project.\n"
  761. "Version: %s.\n"
  762. "Compilation-time options:\n"
  763. "\tOption -l: %s.\n",
  764. #ifdef OWLPS_VERSION
  765. OWLPS_VERSION
  766. #else // OWLPS_VERSION
  767. "unknown version"
  768. #endif // OWLPS_VERSION
  769. ,
  770. #ifdef OWLPS_CLIENT_RECEIVES_POSITION
  771. "YES"
  772. #else // OWLPS_CLIENT_RECEIVES_POSITION
  773. "NO"
  774. #endif // OWLPS_CLIENT_RECEIVES_POSITION
  775. ) ;
  776. }