Add libowlps-resultreader-udp
This new library is to help external programs to receive and interpret results sent by OwlPS Positioning through an UDP socket.
This commit is contained in:
parent
c61c4b3a22
commit
084daed33f
6
Makefile
6
Makefile
|
@ -2,6 +2,7 @@
|
||||||
all c clean purge help \
|
all c clean purge help \
|
||||||
libowlps \
|
libowlps \
|
||||||
libowlps-client \
|
libowlps-client \
|
||||||
|
libowlps-resultreader-udp \
|
||||||
owlps-client \
|
owlps-client \
|
||||||
owlps-listener \
|
owlps-listener \
|
||||||
owlps-aggregator \
|
owlps-aggregator \
|
||||||
|
@ -26,6 +27,7 @@ all: \
|
||||||
c: \
|
c: \
|
||||||
libowlps \
|
libowlps \
|
||||||
libowlps-client \
|
libowlps-client \
|
||||||
|
libowlps-resultreader-udp \
|
||||||
owlps-client \
|
owlps-client \
|
||||||
owlps-listener \
|
owlps-listener \
|
||||||
owlps-aggregator
|
owlps-aggregator
|
||||||
|
@ -34,6 +36,8 @@ libowlps:
|
||||||
@make -C $@
|
@make -C $@
|
||||||
libowlps-client: libowlps
|
libowlps-client: libowlps
|
||||||
@make -C $@
|
@make -C $@
|
||||||
|
libowlps-resultreader-udp: libowlps
|
||||||
|
@make -C $@
|
||||||
owlps-client: libowlps libowlps-client
|
owlps-client: libowlps libowlps-client
|
||||||
@make -C $@
|
@make -C $@
|
||||||
owlps-listener: libowlps libowlps-client
|
owlps-listener: libowlps libowlps-client
|
||||||
|
@ -91,6 +95,7 @@ uninstall-owlps-positioning:
|
||||||
clean :
|
clean :
|
||||||
@make -C libowlps clean
|
@make -C libowlps clean
|
||||||
@make -C libowlps-client clean
|
@make -C libowlps-client clean
|
||||||
|
@make -C libowlps-resultreader-udp clean
|
||||||
@make -C owlps-client clean
|
@make -C owlps-client clean
|
||||||
@make -C owlps-listener clean
|
@make -C owlps-listener clean
|
||||||
@make -C owlps-aggregator clean
|
@make -C owlps-aggregator clean
|
||||||
|
@ -99,6 +104,7 @@ clean :
|
||||||
purge :
|
purge :
|
||||||
@make -C libowlps purge
|
@make -C libowlps purge
|
||||||
@make -C libowlps-client purge
|
@make -C libowlps-client purge
|
||||||
|
@make -C libowlps-resultreader-udp purge
|
||||||
@make -C owlps-client purge
|
@make -C owlps-client purge
|
||||||
@make -C owlps-listener purge
|
@make -C owlps-listener purge
|
||||||
@make -C owlps-aggregator purge
|
@make -C owlps-aggregator purge
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
# Compilateur
|
||||||
|
COLORGCC := $(shell which colorgcc >/dev/null 2>&1 ; echo $$?)
|
||||||
|
ifeq ($(COLORGCC), 0)
|
||||||
|
CC = colorgcc
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Autres outils
|
||||||
|
AR = ar
|
||||||
|
RANLIB = ranlib
|
||||||
|
RM = rm -f
|
||||||
|
|
||||||
|
# Variables générales
|
||||||
|
LIB_CIBLE = libowlps-resultreader-udp
|
||||||
|
VERSION = 1.0
|
||||||
|
|
||||||
|
# Cibles à construire
|
||||||
|
STATIC = $(LIB_CIBLE).a
|
||||||
|
HEADER = owlps-resultreader-udp.h
|
||||||
|
EXAMPLE = owlps-resultreader-udp
|
||||||
|
|
||||||
|
# Composition de la bibliothèque
|
||||||
|
OBJS = $(LIB_CIBLE).o
|
||||||
|
|
||||||
|
# Flags
|
||||||
|
LIBOWLPS_DIR = ../libowlps
|
||||||
|
CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes -O -I$(LIBOWLPS_DIR)
|
||||||
|
CFLAGS += -D DEBUG
|
||||||
|
DEPFLAGS = -MMD
|
||||||
|
XCFLAGS = $(CFLAGS) $(DEPFLAGS) $(WARN) $(HEADERS)
|
||||||
|
PICFLAG = -fPIC
|
||||||
|
#STRIPFLAGS = -Wl,-s
|
||||||
|
#LDFLAGS =
|
||||||
|
|
||||||
|
|
||||||
|
## Cibles de compilation standard ##
|
||||||
|
|
||||||
|
.PHONY : all static clean purge help
|
||||||
|
|
||||||
|
all : static example
|
||||||
|
static : $(STATIC)
|
||||||
|
example : $(EXAMPLE)
|
||||||
|
|
||||||
|
# Cancel implicit make rule
|
||||||
|
%: %.c
|
||||||
|
|
||||||
|
%.o : %.c $(HEADER)
|
||||||
|
$(CC) $(XCFLAGS) -c $<
|
||||||
|
|
||||||
|
% : %.o $(HEADER) $(STATIC)
|
||||||
|
$(CC) $(STRIPFLAGS) $(XCFLAGS) -o $@ $< \
|
||||||
|
$(STATIC) -L$(LIBOWLPS_DIR) -lowlps -lrt
|
||||||
|
|
||||||
|
# Compilation de la bibliothèque statique
|
||||||
|
$(STATIC) : $(OBJS)
|
||||||
|
$(RM) $@
|
||||||
|
$(AR) cru $@ $^
|
||||||
|
$(RANLIB) $@
|
||||||
|
|
||||||
|
|
||||||
|
## Nettoyage ##
|
||||||
|
|
||||||
|
clean :
|
||||||
|
@$(RM) *~ *.o *.d
|
||||||
|
|
||||||
|
purge : clean
|
||||||
|
@$(RM) $(STATIC) $(EXAMPLE)
|
||||||
|
|
||||||
|
|
||||||
|
## Aide ##
|
||||||
|
|
||||||
|
help :
|
||||||
|
@echo "Bibliothèques nécessaires à la compilation :"
|
||||||
|
@echo " libowlps-dev"
|
||||||
|
@echo
|
||||||
|
@echo "Cibles possibles :"
|
||||||
|
@echo " static : Compile la bibliothèque statique (.a)."
|
||||||
|
@echo " example : Compile le programme d'exemple."
|
||||||
|
@echo " (Cible par défaut : static et example.)"
|
||||||
|
@echo
|
||||||
|
@echo " clean : Supprime les fichiers temporaires."
|
||||||
|
@echo " purge : Supprime le résultat de la compilation."
|
|
@ -0,0 +1,267 @@
|
||||||
|
#include "owlps-resultreader-udp.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define CSV_DELIMITER ";"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Receives a result from the socket of file descriptor 'sockfd' and
|
||||||
|
* fills an owl_result structure 'result'.
|
||||||
|
*
|
||||||
|
* Note that *result will be set by this function, and **result will
|
||||||
|
* point on a valid owl_result structure if everything goes well.
|
||||||
|
* You will have to free *result yourself with owl_free_result().
|
||||||
|
*
|
||||||
|
* In case of error, *result is set to NULL.
|
||||||
|
*/
|
||||||
|
void owl_receive_position(int sockfd, owl_result **result)
|
||||||
|
{
|
||||||
|
ssize_t nread ; // recvfrom return value
|
||||||
|
char csv[OWL_CSV_RESULT_STRLEN] ; // Read string
|
||||||
|
|
||||||
|
nread = recvfrom(sockfd, &csv, OWL_CSV_RESULT_STRLEN,
|
||||||
|
0, NULL, NULL) ;
|
||||||
|
|
||||||
|
if (nread <= 0)
|
||||||
|
{
|
||||||
|
perror("No request received from listener") ;
|
||||||
|
*result = NULL ;
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
owl_fill_result(result, csv) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Splits the 'csv' string received from OwlPS Positioning and stores
|
||||||
|
* the fields in 'result' (which is allocated).
|
||||||
|
*
|
||||||
|
* Handled CSV format:
|
||||||
|
* Mobile_MAC;Request_type;Request_timestamp;Algorithm;X;Y;Z;Error;Area
|
||||||
|
* The Request_timestamp format is:
|
||||||
|
* seconds.nanoseconds
|
||||||
|
*/
|
||||||
|
void owl_fill_result(owl_result **result, char *csv)
|
||||||
|
{
|
||||||
|
char *csv_field = NULL ;
|
||||||
|
int nb_algorithms = 0 ;
|
||||||
|
owl_algorithm_result *current_algo = NULL ;
|
||||||
|
|
||||||
|
*result = malloc(sizeof(owl_result)) ;
|
||||||
|
(*result)->results = NULL ;
|
||||||
|
|
||||||
|
/* Mobile MAC address */
|
||||||
|
csv_field = strsep(&csv, CSV_DELIMITER) ;
|
||||||
|
if (! csv_field)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error reading the mobile's MAC address from the CSV"
|
||||||
|
" string (empty string?)!\n") ;
|
||||||
|
goto error ;
|
||||||
|
}
|
||||||
|
(*result)->mobile_mac_addr =
|
||||||
|
strndup(csv_field, OWL_ETHER_ADDR_STRLEN) ;
|
||||||
|
|
||||||
|
/* Request type */
|
||||||
|
csv_field = strsep(&csv, CSV_DELIMITER) ;
|
||||||
|
if (! csv_field)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error reading the request type from the CSV string!\n") ;
|
||||||
|
goto error ;
|
||||||
|
}
|
||||||
|
(*result)->request_type = atoi(csv_field) ;
|
||||||
|
|
||||||
|
/* Timestamp */
|
||||||
|
// Seconds
|
||||||
|
csv_field = strsep(&csv, ".") ;
|
||||||
|
if (! csv_field)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error reading the timestamp (seconds) from the CSV"
|
||||||
|
" string!\n") ;
|
||||||
|
goto error ;
|
||||||
|
}
|
||||||
|
(*result)->mobile_timestamp.tv_sec = atol(csv_field) ;
|
||||||
|
// Nanoseconds
|
||||||
|
csv_field = strsep(&csv, CSV_DELIMITER) ;
|
||||||
|
if (! csv_field)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error reading the timestamp (nanoseconds) from the CSV"
|
||||||
|
" string!\n") ;
|
||||||
|
goto error ;
|
||||||
|
}
|
||||||
|
(*result)->mobile_timestamp.tv_nsec = atol(csv_field) ;
|
||||||
|
|
||||||
|
/* Algorithm results */
|
||||||
|
csv_field = strsep(&csv, CSV_DELIMITER) ;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
++nb_algorithms ;
|
||||||
|
current_algo = malloc(sizeof(owl_algorithm_result)) ;
|
||||||
|
|
||||||
|
// Algorithm name
|
||||||
|
if (! csv_field)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error reading the algorithm name from the CSV"
|
||||||
|
" string (algorithm #%d)!\n", nb_algorithms) ;
|
||||||
|
goto error ;
|
||||||
|
}
|
||||||
|
current_algo->algorithm =
|
||||||
|
strndup(csv_field, OWL_ALGORITHM_STRLEN) ;
|
||||||
|
|
||||||
|
// X coordinate
|
||||||
|
csv_field = strsep(&csv, CSV_DELIMITER) ;
|
||||||
|
if (! csv_field)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error reading the X coordinate from the CSV"
|
||||||
|
" string (algorithm #%d)!\n", nb_algorithms) ;
|
||||||
|
goto error ;
|
||||||
|
}
|
||||||
|
current_algo->x = atof(csv_field) ;
|
||||||
|
|
||||||
|
// Y coordinate
|
||||||
|
csv_field = strsep(&csv, CSV_DELIMITER) ;
|
||||||
|
if (! csv_field)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error reading the Y coordinate from the CSV"
|
||||||
|
" string (algorithm #%d)!\n", nb_algorithms) ;
|
||||||
|
goto error ;
|
||||||
|
}
|
||||||
|
current_algo->y = atof(csv_field) ;
|
||||||
|
|
||||||
|
// Z coordinate
|
||||||
|
csv_field = strsep(&csv, CSV_DELIMITER) ;
|
||||||
|
if (! csv_field)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error reading the Z coordinate from the CSV"
|
||||||
|
" string (algorithm #%d)!\n", nb_algorithms) ;
|
||||||
|
goto error ;
|
||||||
|
}
|
||||||
|
current_algo->z = atof(csv_field) ;
|
||||||
|
|
||||||
|
// Distance error
|
||||||
|
csv_field = strsep(&csv, CSV_DELIMITER) ;
|
||||||
|
if (! csv_field)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error reading the distance error from the CSV"
|
||||||
|
" string (algorithm #%d)!\n", nb_algorithms) ;
|
||||||
|
goto error ;
|
||||||
|
}
|
||||||
|
current_algo->error = atof(csv_field) ;
|
||||||
|
|
||||||
|
// Area name (optional)
|
||||||
|
csv_field = strsep(&csv, CSV_DELIMITER) ;
|
||||||
|
if (csv_field)
|
||||||
|
current_algo->area = strndup(csv_field, OWL_AREA_STRLEN) ;
|
||||||
|
|
||||||
|
// Insert the current algorithm at the begining of the list
|
||||||
|
current_algo->next = (*result)->results ;
|
||||||
|
(*result)->results = current_algo ;
|
||||||
|
}
|
||||||
|
while ((csv_field = strsep(&csv, CSV_DELIMITER))) ;
|
||||||
|
|
||||||
|
return ; // Success
|
||||||
|
|
||||||
|
error:
|
||||||
|
owl_free_result(*result) ;
|
||||||
|
*result = NULL ;
|
||||||
|
free(current_algo) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prints an owl_result to the given stream.
|
||||||
|
*/
|
||||||
|
void owl_fprint_result(FILE *stream, owl_result *result)
|
||||||
|
{
|
||||||
|
char timestamp_str[OWL_TIMESTAMP_STRLEN] ;
|
||||||
|
owl_timestamp_to_string(timestamp_str, result->mobile_timestamp) ;
|
||||||
|
|
||||||
|
fprintf(stream,
|
||||||
|
"Mobile MAC: %s\n"
|
||||||
|
"Request type: %"PRIu8"\n"
|
||||||
|
"Mobile timestamp: %s\n"
|
||||||
|
"Results:\n"
|
||||||
|
,
|
||||||
|
result->mobile_mac_addr,
|
||||||
|
result->request_type,
|
||||||
|
timestamp_str
|
||||||
|
) ;
|
||||||
|
|
||||||
|
owl_algorithm_result *algo = result->results ;
|
||||||
|
while (algo)
|
||||||
|
{
|
||||||
|
owl_fprint_algorithm_result(stream, algo) ;
|
||||||
|
algo = algo->next ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prints an owl_result to the given stream.
|
||||||
|
*/
|
||||||
|
void owl_fprint_algorithm_result(FILE *stream,
|
||||||
|
owl_algorithm_result *algo)
|
||||||
|
{
|
||||||
|
fprintf(stream,
|
||||||
|
"* Algorithm: %s\n"
|
||||||
|
" X: %f\n"
|
||||||
|
" Y: %f\n"
|
||||||
|
" Z: %f\n"
|
||||||
|
" Error: %f\n"
|
||||||
|
" Area: %s\n"
|
||||||
|
,
|
||||||
|
algo->algorithm,
|
||||||
|
algo->x,
|
||||||
|
algo->y,
|
||||||
|
algo->z,
|
||||||
|
algo->error,
|
||||||
|
algo->area ? algo->area : ""
|
||||||
|
) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Frees the memory allocated by an owl_result.
|
||||||
|
* Note that the pointer will not set to NULL.
|
||||||
|
*/
|
||||||
|
void owl_free_result(owl_result *result)
|
||||||
|
{
|
||||||
|
if (! result)
|
||||||
|
return ;
|
||||||
|
while (result->results)
|
||||||
|
{
|
||||||
|
owl_algorithm_result *algo = result->results ;
|
||||||
|
result->results = algo->next ;
|
||||||
|
owl_free_algorithm_result(algo) ;
|
||||||
|
}
|
||||||
|
free(result->mobile_mac_addr) ;
|
||||||
|
free(result) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Frees the memory allocated by a single owl_algorithm_result (*not*
|
||||||
|
* recursively).
|
||||||
|
* Note that the pointer will not set to NULL.
|
||||||
|
*/
|
||||||
|
void owl_free_algorithm_result(owl_algorithm_result *algo)
|
||||||
|
{
|
||||||
|
if (! algo)
|
||||||
|
return ;
|
||||||
|
free(algo->algorithm) ;
|
||||||
|
free(algo->area) ;
|
||||||
|
free(algo) ;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* This is a simple program to demonstrate the use of
|
||||||
|
* libowlps-resultreader-udp.
|
||||||
|
* It must be linked against libowlps and its dependencies
|
||||||
|
* (see the Makefile).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "owlps-resultreader-udp.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
owl_result *result ;
|
||||||
|
int sockfd ;
|
||||||
|
|
||||||
|
sockfd = owl_create_udp_listening_socket(MOBILE_DEFAULT_PORT) ;
|
||||||
|
if (sockfd < 0)
|
||||||
|
return 1 ;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
owl_receive_position(sockfd, &result) ;
|
||||||
|
if (result == NULL)
|
||||||
|
return 1 ;
|
||||||
|
owl_print_result(result) ;
|
||||||
|
owl_free_result(result) ;
|
||||||
|
printf("--------------\n") ;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sockfd) ;
|
||||||
|
|
||||||
|
return 0 ;
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* This library provides functions to read results sent on UDP by OwlPS
|
||||||
|
* Positioning.
|
||||||
|
* See the example program owlps-resultreader-udp.c.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LIBOWLPS_RESULTREADER_CSV_
|
||||||
|
#define _LIBOWLPS_RESULTREADER_CSV_
|
||||||
|
|
||||||
|
#include <owlps.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* Maximum size of a result CSV string sent by OwlPS Positioning.
|
||||||
|
* Request's information:
|
||||||
|
* = 18 (MAC) + 2 (type) + 22 (timestamp) = 42
|
||||||
|
* Plus, for each algorithm, about 60 characters (say 100, as the length
|
||||||
|
* of the algorithm and area names can vary).
|
||||||
|
* Let's keep room for 10 algorithms :
|
||||||
|
* 10×100 + 42 = 1042 characters + '\0' = 1043.
|
||||||
|
*/
|
||||||
|
#define OWL_CSV_RESULT_STRLEN 1043
|
||||||
|
|
||||||
|
|
||||||
|
/* Linked list of algorithms' results.
|
||||||
|
* Each structure is the result of a single algorithm.
|
||||||
|
*/
|
||||||
|
typedef struct _owl_algorithm_result
|
||||||
|
{
|
||||||
|
char *algorithm ;
|
||||||
|
float x ;
|
||||||
|
float y ;
|
||||||
|
float z ;
|
||||||
|
float error ;
|
||||||
|
char *area ;
|
||||||
|
|
||||||
|
struct _owl_algorithm_result *next ;
|
||||||
|
} owl_algorithm_result ;
|
||||||
|
|
||||||
|
|
||||||
|
/* Results for a request. Includes the request's data, and the
|
||||||
|
* list of algorithms' results.
|
||||||
|
*/
|
||||||
|
typedef struct _owl_result
|
||||||
|
{
|
||||||
|
char *mobile_mac_addr ;
|
||||||
|
uint8_t request_type ;
|
||||||
|
owl_timestamp mobile_timestamp ;
|
||||||
|
owl_algorithm_result *results ;
|
||||||
|
} owl_result ;
|
||||||
|
|
||||||
|
|
||||||
|
void owl_receive_position(int sockfd, owl_result **result) ;
|
||||||
|
void owl_fill_result(owl_result **result, char *csv) ;
|
||||||
|
|
||||||
|
void owl_fprint_result(FILE *stream, owl_result *result) ;
|
||||||
|
void owl_fprint_algorithm_result(FILE *stream,
|
||||||
|
owl_algorithm_result *algo) ;
|
||||||
|
#define owl_print_result(RESULT) \
|
||||||
|
(owl_fprint_result(stdout, (RESULT)))
|
||||||
|
#define owl_print_algorithm_result(ALGO) \
|
||||||
|
(owl_fprint_algorithm_result(stdout, (ALGO)))
|
||||||
|
|
||||||
|
void owl_free_result(owl_result *result) ;
|
||||||
|
void owl_free_algorithm_result(owl_algorithm_result *algo) ;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _LIBOWLPS_RESULTREADER_CSV_
|
|
@ -160,6 +160,10 @@ typedef struct _owl_autocalibration_order
|
||||||
/* Misc. */
|
/* Misc. */
|
||||||
// Length of a MAC address in string format (including '\0')
|
// Length of a MAC address in string format (including '\0')
|
||||||
#define OWL_ETHER_ADDR_STRLEN 18
|
#define OWL_ETHER_ADDR_STRLEN 18
|
||||||
|
// Maximum length of an algorithm name (including '\0')
|
||||||
|
#define OWL_ALGORITHM_STRLEN 31
|
||||||
|
// Maximum length of an area name (including '\0')
|
||||||
|
#define OWL_AREA_STRLEN 31
|
||||||
|
|
||||||
|
|
||||||
/* Global variables */
|
/* Global variables */
|
||||||
|
|
Loading…
Reference in New Issue