/* * This file is part of the Owl Positioning System (OwlPS). * OwlPS is a project of the University of Franche-Comte * (Université de Franche-Comté), France. * * Copyright © Université de Franche-Comté 2007-2012. * * Corresponding author: Matteo Cypriani * *********************************************************************** * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/or redistribute the software under the terms of the CeCILL * license as circulated by CEA, CNRS and INRIA at the following URL: * http://www.cecill.info * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided * only with a limited warranty and the software's authors, the holder * of the economic rights, and the successive licensors have only * limited liability. * * In this respect, the user's attention is drawn to the risks * associated with loading, using, modifying and/or developing or * reproducing the software by the user in light of its specific status * of free software, that may mean that it is complicated to manipulate, * and that also therefore means that it is reserved for developers and * experienced professionals having in-depth computer knowledge. Users * are therefore encouraged to load and test the software's suitability * as regards their requirements in conditions enabling the security of * their systems and/or data to be ensured and, more generally, to use * and operate it in the same conditions as regards security. * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL license and that you accept its terms. * *********************************************************************** * * This is the main source file of libowlps-resultreader. */ #include "owlps-resultreader.h" #include #include #include #include #define CSV_DELIMITER ";" /* * Receives a result from the socket of file descriptor 'sockfd', fills * an owl_result structure with the received information, and returns a * pointer to it. * * Note that the new owl_result is allocated with malloc() and must be * deleted using free(). * * In case of error, a message is printed, except if owl_run (from * libowlps) is false, and NULL is returned. */ owl_result* owl_receive_position(int sockfd) { 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) { if (owl_run) perror("No request received from listener") ; return NULL ; } return owl_fill_result(csv) ; } /* * Splits the 'csv' string received from OwlPS Positioner and stores * the fields in a new owl_result, and returns a pointer to it (or NULL * in case of error). * * Note that the new owl_result is allocated with malloc() and must be * deleted using free(). * * Handled CSV format: * Mobile_MAC;Request_type;Request_timestamp;Algorithm;X;Y;Z;Error;Area * The Request_timestamp format is: * seconds.nanoseconds * The Area field can be empty. */ owl_result* owl_fill_result(char *csv) { char *csv_field = NULL ; owl_result *result = NULL ; result = malloc(sizeof(owl_result)) ; memset(result, 0, sizeof(*result)) ; /* 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 */ do { owl_algorithm_result *current_algo = owl_fill_algorithm_result(&csv) ; if (current_algo == NULL) { fprintf(stderr, "Error reading the algorithm #%d!\n", result->nb_results + 1) ; break ; } // Insert the current algorithm at the begining of the list current_algo->next = result->results ; result->results = current_algo ; ++result->nb_results ; } while (csv) ; return result ; // Success error: owl_free_result(result) ; return NULL ; } /* * Splits the 'csv' string, stores the fields in a new * owl_algorithm_result, and returns a pointer to it (or NULL * in case of error). * * Note that the new owl_algorithm_result is allocated with malloc() * and must be deleted using free(). * * 'csv' must follow this CSV format: * Algorithm;X;Y;Z;Error;Area * The Area field can be empty. */ owl_algorithm_result* owl_fill_algorithm_result(char **csv) { owl_algorithm_result *algo ; char *csv_field = NULL ; algo = malloc(sizeof(owl_algorithm_result)) ; memset(algo, 0, sizeof(*algo)) ; // Algorithm name csv_field = strsep(csv, CSV_DELIMITER) ; if (! csv_field) { fprintf(stderr, "Error reading the algorithm name from the CSV string!\n") ; goto error ; } 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!\n") ; goto error ; } 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!\n") ; goto error ; } 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!\n") ; goto error ; } 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!\n") ; goto error ; } algo->error = atof(csv_field) ; // Area name (optional) csv_field = strsep(csv, CSV_DELIMITER) ; if (csv_field) algo->area = strndup(csv_field, OWL_AREA_STRLEN) ; return algo ; // Success error: owl_free_algorithm_result(algo) ; return NULL ; } /* * Converts an owl_result back to a CSV string. * 'dst' must be an allocated string of at least OWL_CSV_RESULT_STRLEN * characters. * * CSV format: * Mobile_MAC;Request_type;Request_timestamp;Nb_algo;Algo_1;…;Algo_n * Nb_algo is the number of algorithms in the result. * The format of Algo_i is documented in owl_algorithm_result_to_csv(). */ void owl_result_to_csv(char dst[OWL_CSV_RESULT_STRLEN], const owl_result *const src) { size_t dst_len ; char timestamp_str[OWL_TIMESTAMP_STRLEN] ; assert(src) ; owl_timestamp_to_string(&src->mobile_timestamp, timestamp_str) ; snprintf(dst, OWL_CSV_RESULT_REQUEST_STRLEN, "%s;%"PRIu8";%s;%u", src->mobile_mac_addr, src->request_type, timestamp_str, src->nb_results) ; dst_len = strlen(dst) ; owl_algorithm_result *algo = src->results ; while (algo) { char algo_str[OWL_CSV_ALGORITHM_RESULT_STRLEN] ; owl_algorithm_result_to_csv(algo_str, algo) ; dst[dst_len++] = ';' ; strncpy(dst + dst_len, algo_str, OWL_CSV_ALGORITHM_RESULT_STRLEN) ; dst_len += strlen(algo_str) ; algo = algo->next ; } } /* * Converts an owl_algorithm_result back to a CSV string. * 'dst' must be an allocated string of at least * OWL_CSV_ALGORITHM_RESULT_STRLEN characters. * * CSV format: * Algorithm_name;X;Y;Z;Error;Area_name * Error is the distance from the true coordinates of the mobile, if * known; if unknown, Error is set to -1. * Area_name is the name of the area or room in which the mobile is (may * be empty). */ void owl_algorithm_result_to_csv(char dst[OWL_CSV_ALGORITHM_RESULT_STRLEN], const owl_algorithm_result *const src) { assert(src) ; snprintf(dst, OWL_CSV_ALGORITHM_RESULT_STRLEN, "%s;%f;%f;%f;%f;%s", src->algorithm, src->x, src->y, src->z, src->error, src->area ? src->area : "") ; } /* * Converts an owl_result back to a CSV string, in a simplified format. * Only the *first* algorithm in the result's algorithm list will be * included in the string. * 'dst' must be an allocated string of at least * OWL_CSV_RESULT_SIMPLE_STRLEN characters. * * CSV format: * Mobile_MAC;First_algorithm * First_algorithm is the first algorithm in src->results. Its format * is documented in owl_algorithm_result_to_csv_simple(). */ void owl_result_to_csv_simple(char dst[OWL_CSV_RESULT_SIMPLE_STRLEN], const owl_result *const src) { size_t dst_len ; char algo_str[OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN] ; assert(src) ; strncpy(dst, src->mobile_mac_addr, OWL_ETHER_ADDR_STRLEN) ; dst[OWL_ETHER_ADDR_STRLEN - 1] = ';' ; dst_len = OWL_ETHER_ADDR_STRLEN ; if (! src->results) return ; owl_algorithm_result_to_csv_simple(algo_str, src->results) ; strncpy(dst + dst_len, algo_str, OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN) ; } /* * Converts an owl_algorithm_result back to a CSV string, in a * simplified format. * 'dst' must be an allocated string of at least * OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN characters. * * CSV format: * X;Y;Z;Area_name * Area_name is the name of the area or room in which the mobile is (may * be empty). */ void owl_algorithm_result_to_csv_simple (char dst[OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN], const owl_algorithm_result *const src) { assert(src) ; snprintf(dst, OWL_CSV_ALGORITHM_RESULT_SIMPLE_STRLEN, "%f;%f;%f;%s", src->x, src->y, src->z, src->area ? src->area : "") ; } /* * Prints an owl_result to the given stream. */ void owl_fprint_result(FILE *stream, const owl_result *const src) { char timestamp_str[OWL_TIMESTAMP_STRLEN] ; assert(src) ; owl_timestamp_to_string(&src->mobile_timestamp, timestamp_str) ; fprintf(stream, "Mobile MAC: %s\n" "Request type: %"PRIu8"\n" "Mobile timestamp: %s\n" "%u results:\n" , src->mobile_mac_addr, src->request_type, timestamp_str, src->nb_results) ; owl_algorithm_result *algo = src->results ; while (algo) { owl_fprint_algorithm_result(stream, algo) ; algo = algo->next ; } } /* * Prints an owl_algorithm_result to the given stream. */ void owl_fprint_algorithm_result(FILE *stream, const owl_algorithm_result *const src) { assert(src) ; fprintf(stream, "* Algorithm: %s\n" " X: %f\n" " Y: %f\n" " Z: %f\n" " Error: %f\n" " Area: %s\n" , src->algorithm, src->x, src->y, src->z, src->error, src->area ? src->area : "" ) ; } /* * Frees the memory allocated by an owl_result. The 'results' and * 'mobile_mac_addr' fields *must* be defined, either to NULL or to a * valid memory block allocated with malloc(). * 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). The 'algorithm' and 'area' fields *must* be defined, * either to NULL or to a valid memory block allocated with malloc(). * 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) ; }