commit
1d14968446
10 changed files with 66270 additions and 0 deletions
@ -0,0 +1,213 @@ |
|||
cmake_minimum_required(VERSION 2.8.3) |
|||
project(acquisition_biosemi) |
|||
|
|||
set(CMAKE_BUILD_TYPE Debug) |
|||
#set(CMAKE_BUILD_TYPE Release) |
|||
|
|||
|
|||
|
|||
## Find catkin macros and libraries |
|||
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) |
|||
## is used, also find other catkin packages |
|||
find_package(catkin REQUIRED COMPONENTS |
|||
roscpp |
|||
rospy |
|||
std_msgs |
|||
message_generation |
|||
) |
|||
|
|||
|
|||
## System dependencies are found with CMake's conventions |
|||
# find_package(Boost REQUIRED COMPONENTS system) |
|||
|
|||
|
|||
## Uncomment this if the package has a setup.py. This macro ensures |
|||
## modules and global scripts declared therein get installed |
|||
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html |
|||
# catkin_python_setup() |
|||
|
|||
################################################ |
|||
## Declare ROS messages, services and actions ## |
|||
################################################ |
|||
|
|||
## To declare and build messages, services or actions from within this |
|||
## package, follow these steps: |
|||
## * Let MSG_DEP_SET be the set of packages whose message types you use in |
|||
## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). |
|||
## * In the file package.xml: |
|||
## * add a build_depend tag for "message_generation" |
|||
## * add a build_depend and a run_depend tag for each package in MSG_DEP_SET |
|||
## * If MSG_DEP_SET isn't empty the following dependency has been pulled in |
|||
## but can be declared for certainty nonetheless: |
|||
## * add a run_depend tag for "message_runtime" |
|||
## * In this file (CMakeLists.txt): |
|||
## * add "message_generation" and every package in MSG_DEP_SET to |
|||
## find_package(catkin Rset(CMAKE_BUILD_TYPE Debug) |
|||
## * add "message_runtime" and every package in MSG_DEP_SET to |
|||
## catkin_package(CATKIN_DEPENDS ...) |
|||
## * uncomment the add_*_files sections below as needed |
|||
## and list every .msg/.srv/.action file to be processed |
|||
## * uncomment the generate_messages entry below |
|||
## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) |
|||
|
|||
## Generate messages in the 'msg' folder |
|||
add_message_files( |
|||
FILES |
|||
biosemi_result.msg |
|||
biosemi_echantillon.msg |
|||
) |
|||
|
|||
## Generate services in the 'srv' folder |
|||
# add_service_files( |
|||
# FILES |
|||
# Service1.srv |
|||
# Service2.srv |
|||
# ) |
|||
|
|||
## Generate actions in the 'action' folder |
|||
# add_action_files( |
|||
# FILES |
|||
# Action1.action |
|||
# Action2.action |
|||
# ) |
|||
|
|||
## Generate added messages and services with any dependencies listed here |
|||
generate_messages( |
|||
DEPENDENCIES |
|||
std_msgs |
|||
) |
|||
|
|||
################################################ |
|||
## Declare ROS dynamic reconfigure parameters ## |
|||
################################################ |
|||
|
|||
## To declare and build dynamic reconfigure parameters within this |
|||
## package, follow these steps: |
|||
## * In the file package.xml: |
|||
## * add a build_depend and a run_depend tag for "dynamic_reconfigure" |
|||
## * In this file (CMakeLists.txt): |
|||
## * add "dynamic_reconfigure" to |
|||
## find_package(catkin REQUIRED COMPONENTS ...) |
|||
## * uncomment the "generate_dynamic_reconfigure_options" section below |
|||
## and list every .cfg file to be processed |
|||
|
|||
## Generate dynamic reconfigure parameters in the 'cfg' folder |
|||
# generate_dynamic_reconfigure_options( |
|||
# cfg/DynReconf1.cfg |
|||
# cfg/DynReconf2.cfg |
|||
# ) |
|||
|
|||
################################### |
|||
## catkin specific configuration ## |
|||
################################### |
|||
## The catkin_package macro generates cmake config files for your package |
|||
## Declare things to be passed to dependent projects |
|||
## INCLUDE_DIRS: uncomment this if you package contains header files |
|||
## LIBRARIES: libraries you create in this project that dependent projects also need |
|||
## CATKIN_DEPENDS: catkin_packages dependent projects also need |
|||
## DEPENDS: system dependencies of this project that dependent projects also need |
|||
catkin_package( |
|||
# INCLUDE_DIRS include |
|||
# LIBRARIES acquisition_biosemi |
|||
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime |
|||
# DEPENDS system_lib |
|||
) |
|||
|
|||
########### |
|||
## Build ## |
|||
########### |
|||
|
|||
## Specify additional locations of header files |
|||
## Your package locations should be listed before other locations |
|||
# include_directories(include) |
|||
include_directories( |
|||
${catkin_INCLUDE_DIRS} |
|||
) |
|||
|
|||
## Declare a C++ library |
|||
# add_library(acquisition_biosemi |
|||
# src/${PROJECT_NAME}/acquisition_biosemi.cpp |
|||
# ) |
|||
|
|||
## Add cmake target dependencies of the library |
|||
## as an example, code may need to be generated before libraries |
|||
## either from message generation or dynamic reconfigure |
|||
# add_dependencies(acquisition_biosemi ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) |
|||
|
|||
## Declare a C++ executable |
|||
# add_executable(acquisition_biosemi_node src/acquisition_biosemi_node.cpp) |
|||
|
|||
## Add cmake target dependencies of the executable |
|||
## same as for the library above |
|||
# add_dependencies(acquisition_biosemi_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) |
|||
|
|||
## Specify libraries to link a library or executable target against |
|||
# target_link_libraries(acquisition_biosemi_node |
|||
# ${catkin_LIBRARIES} |
|||
# ) |
|||
|
|||
############# |
|||
## Install ## |
|||
############# |
|||
|
|||
# all install targets should use catkin DESTINATION variables |
|||
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html |
|||
|
|||
## Mark executable scripts (Python etc.) for installation |
|||
## in contrast to setup.py, you can choose the destination |
|||
# install(PROGRAMS |
|||
# scripts/my_python_script |
|||
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} |
|||
# ) |
|||
|
|||
## Mark executables and/or libraries for installation |
|||
# install(TARGETS acquisition_biosemi acquisition_biosemi_node |
|||
# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} |
|||
# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} |
|||
# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} |
|||
# ) |
|||
|
|||
## Mark cpp header files for installation |
|||
# install(DIRECTORY include/${PROJECT_NAME}/ |
|||
# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} |
|||
# FILES_MATCHING PATTERN "*.h" |
|||
# PATTERN ".svn" EXCLUDE |
|||
# ) |
|||
|
|||
## Mark other files for installation (e.g. launch and bag files, etc.) |
|||
# install(FILES |
|||
# # myfile1 |
|||
# # myfile2 |
|||
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} |
|||
# ) |
|||
|
|||
############# |
|||
## Testing ## |
|||
############# |
|||
|
|||
## Add gtest based cpp test target and link libraries |
|||
# catkin_add_gtest(${PROJECT_NAME}-test test/test_acquisition_biosemi.cpp) |
|||
# if(TARGET ${PROJECT_NAME}-test) |
|||
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}) |
|||
# endif() |
|||
|
|||
## Add folders to be run by python nosetests |
|||
# catkin_add_nosetests(test) |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
include_directories(include ${catkin_INCLUDE_DIRS}) |
|||
|
|||
add_executable(biosemi_talker src/biosemi_talker.cpp) |
|||
target_link_libraries(biosemi_talker ${catkin_LIBRARIES}) |
|||
add_dependencies(biosemi_talker acquisition_biosemi_generate_messages_cpp) |
|||
|
|||
add_executable(biosemi_listener src/biosemi_listener.cpp) |
|||
target_link_libraries(biosemi_listener ${catkin_LIBRARIES}) |
|||
add_dependencies(biosemi_listener acquisition_biosemi_generate_messages_cpp) |
|||
|
|||
add_executable(biosemi_simul src/biosemi_simul.cpp) |
|||
target_link_libraries(biosemi_simul ${catkin_LIBRARIES}) |
|||
add_dependencies(biosemi_simul acquisition_biosemi_generate_messages_cpp) |
|||
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,4 @@ |
|||
uint32 numero |
|||
uint32 frequence |
|||
float64[] valeurs |
|||
string extra |
|||
@ -0,0 +1,5 @@ |
|||
uint32 numero |
|||
uint32 nombre |
|||
uint32 frequence |
|||
float64[] valeurs |
|||
string extra |
|||
@ -0,0 +1,56 @@ |
|||
<?xml version="1.0"?> |
|||
<package> |
|||
<name>acquisition_biosemi</name> |
|||
<version>0.0.0</version> |
|||
<description>The acquisition_biosemi package</description> |
|||
|
|||
<!-- One maintainer tag required, multiple allowed, one person per tag --> |
|||
<!-- Example: --> |
|||
<!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> --> |
|||
<maintainer email="gutzwiller@todo.todo">gutzwiller</maintainer> |
|||
|
|||
|
|||
<!-- One license tag required, multiple allowed, one license per tag --> |
|||
<!-- Commonly used license strings: --> |
|||
<!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 --> |
|||
<license>TODO</license> |
|||
|
|||
|
|||
<!-- Url tags are optional, but mutiple are allowed, one per tag --> |
|||
<!-- Optional attribute type can be: website, bugtracker, or repository --> |
|||
<!-- Example: --> |
|||
<!-- <url type="website">http://wiki.ros.org/acquisition_biosemi</url> --> |
|||
|
|||
|
|||
<!-- Author tags are optional, mutiple are allowed, one per tag --> |
|||
<!-- Authors do not have to be maintianers, but could be --> |
|||
<!-- Example: --> |
|||
<!-- <author email="jane.doe@example.com">Jane Doe</author> --> |
|||
|
|||
|
|||
<!-- The *_depend tags are used to specify dependencies --> |
|||
<!-- Dependencies can be catkin packages or system dependencies --> |
|||
<!-- Examples: --> |
|||
<!-- Use build_depend for packages you need at compile time: --> |
|||
<build_depend>message_generation</build_depend> |
|||
<!-- Use buildtool_depend for build tool packages: --> |
|||
<!-- <buildtool_depend>catkin</buildtool_depend> --> |
|||
<!-- Use run_depend for packages you need at runtime: --> |
|||
<run_depend>message_runtime</run_depend> |
|||
<!-- Use test_depend for packages you need only for testing: --> |
|||
<!-- <test_depend>gtest</test_depend> --> |
|||
<buildtool_depend>catkin</buildtool_depend> |
|||
<build_depend>roscpp</build_depend> |
|||
<build_depend>rospy</build_depend> |
|||
<build_depend>std_msgs</build_depend> |
|||
<run_depend>roscpp</run_depend> |
|||
<run_depend>rospy</run_depend> |
|||
<run_depend>std_msgs</run_depend> |
|||
|
|||
|
|||
<!-- The export tag contains other, unspecified, tags --> |
|||
<export> |
|||
<!-- Other tools can request additional information be placed here --> |
|||
|
|||
</export> |
|||
</package> |
|||
@ -0,0 +1,50 @@ |
|||
#include "ros/ros.h" |
|||
#include "acquisition_biosemi/biosemi_result.h" |
|||
#include <iostream> |
|||
|
|||
|
|||
static unsigned long int numero; |
|||
|
|||
|
|||
/* Cette fonction est appelée à chaque réception de message */ |
|||
void biosemiCallback(const acquisition_biosemi::biosemi_result msg) |
|||
{ |
|||
int num, taille; |
|||
|
|||
taille = msg.valeurs.size(); |
|||
std::vector<double>::const_iterator i = msg.valeurs.begin(); |
|||
for(num = 0; num < msg.nombre; num ++ ) { |
|||
std::cout.setf(std::ios::fixed, std::ios::floatfield); |
|||
std::cout.precision(12); |
|||
std::cout.width(12); std::cout.fill('0'); |
|||
std::cout << msg.numero + num; |
|||
std::cout.width(0); std::cout.fill(' '); |
|||
std::cout << "[" << msg.frequence << "]: "; |
|||
for(int k = 0; k < taille / msg.nombre; k++) { |
|||
std::cout << " " << *i; |
|||
++i; |
|||
} |
|||
std::cout << " " << msg.extra << std::endl; |
|||
|
|||
|
|||
if (numero != 0) { |
|||
if (msg.numero + num != numero + 1) { |
|||
std::cerr << "Perte de synchronisation : numero = " << msg.numero << ", ancien = " << numero << std::endl; |
|||
ros::shutdown(); |
|||
} |
|||
} |
|||
numero = msg.numero + num; |
|||
} |
|||
} |
|||
|
|||
int main(int argc, char **argv) |
|||
{ |
|||
numero = 0; |
|||
ros::init(argc, argv, "biosemi_listener"); |
|||
ros::NodeHandle n; |
|||
ros::Subscriber sub = n.subscribe("biosemi_result", 1000, biosemiCallback); |
|||
|
|||
ros::spin(); |
|||
|
|||
return 0; |
|||
} |
|||
@ -0,0 +1,236 @@ |
|||
/*
|
|||
* biosemi_talker.cpp |
|||
* |
|||
* |
|||
* Programme permettant de diffuser sous ROS les échantillons en provenance |
|||
* du système d'acquisition biosemi. |
|||
* Note : un message est diffusé par échantillon, un échantillon peut |
|||
* contenir plusieurs canaux. |
|||
* |
|||
* |
|||
* |
|||
* Ce programme transmet des messages qui contiennt : |
|||
* - le numéro d'ordre de l'échantillon |
|||
* - la fréquence d'échantillonnage |
|||
* - un tableau de valeurs réelles (double) dont la taille dépend |
|||
* des paramètres de lancement du serveur d'acquistion (nombre de canaux) |
|||
* - une chaîne de caractères extra (pour les codes d'erreurs). |
|||
* |
|||
*/ |
|||
|
|||
#include "ros/ros.h" |
|||
#include "acquisition_biosemi/biosemi_result.h" |
|||
#include "acquisition_biosemi/biosemi_echantillon.h" |
|||
#include <sys/types.h> |
|||
#include <sys/stat.h> |
|||
#include <fcntl.h> |
|||
|
|||
|
|||
|
|||
|
|||
#define TAILLE_BUFFER 20000 |
|||
#define FREQUENCE 256 |
|||
|
|||
using namespace std; |
|||
|
|||
|
|||
static int frequence = FREQUENCE; |
|||
static int fin_de_donnees = 0; |
|||
|
|||
|
|||
/*************************************************************************************************************/ |
|||
|
|||
void lecture_fichier(int fd, char * buffer, int * entree) { |
|||
ssize_t taille; |
|||
|
|||
if (fin_de_donnees) return; |
|||
taille = 2 * TAILLE_BUFFER - (*entree); |
|||
if (taille > SSIZE_MAX) taille = SSIZE_MAX; |
|||
taille = read(fd, buffer + (*entree), taille); |
|||
if (taille <= 0) { |
|||
fin_de_donnees = 1; |
|||
} else { |
|||
*entree += taille; |
|||
buffer[*entree] = 0; |
|||
} |
|||
} |
|||
|
|||
/*************************************************************************************************************/ |
|||
|
|||
int recupere_ligne(acquisition_biosemi::biosemi_echantillon & echantillon, const char * buffer, int & lecture, int & entree) { |
|||
int local_lect = 0; |
|||
int local_fin; |
|||
char * fin; |
|||
double valeur; |
|||
int ok; |
|||
char local_buffer[TAILLE_BUFFER+1]; |
|||
int i; |
|||
|
|||
static int compteur = 0; |
|||
|
|||
|
|||
// Récupération d'une ligne au maximum dans un buffer local.
|
|||
for(i = 0; (i+lecture < entree) && (buffer[i+lecture] != '\n') && (buffer[i+lecture] != 0); i++) { |
|||
local_buffer[i] = buffer[i+lecture]; |
|||
local_buffer[i+1] = '\0'; |
|||
} |
|||
if (buffer[i+lecture] != '\n') return 0; // Fin de la ligne non trouvée.
|
|||
|
|||
// On efface l'ancien contenu :
|
|||
echantillon.valeurs.clear(); |
|||
echantillon.frequence = frequence; |
|||
echantillon.extra = ""; |
|||
|
|||
// Lecture du numéro :
|
|||
echantillon.numero = strtoul(local_buffer + local_lect, &fin, 10); |
|||
local_fin = fin - local_buffer; |
|||
// Le caractère suivant est forcément un ':', sinon le numéro n'est pas présent.
|
|||
if (local_buffer[local_fin] != ':') { |
|||
compteur += 1; |
|||
echantillon.numero = compteur; |
|||
} else { |
|||
local_lect = local_fin + 1; |
|||
} |
|||
|
|||
|
|||
// On scanne des doubles, autant qu'on en trouve :
|
|||
do { |
|||
ok = 0; |
|||
valeur = strtod(local_buffer + local_lect, &fin); |
|||
local_fin = fin - local_buffer; |
|||
if (valeur != 0.0) { |
|||
ok = 1; // Une valeur non nulle indique une conversion correcte.
|
|||
} else { |
|||
// Une valeur nulle peut indiquer une conversion incorrecte, ou le fait que le nombre soit nul.
|
|||
// Il faut vérifier cela. On doit trouver des chiffres dans l'espace qui a étré scanné.
|
|||
ok = 0; |
|||
for(int i = local_lect; i < local_fin; i++) { |
|||
if ((local_buffer[i] >= '0') && (local_buffer[i] <= '9')) ok = 1; // Il y a des chiffres.
|
|||
} |
|||
} |
|||
if (ok) { |
|||
local_lect = local_fin; |
|||
echantillon.valeurs.push_back(valeur); |
|||
} |
|||
} while (ok); |
|||
|
|||
|
|||
// On recherche s'il y a encore des caractères sur la ligne :
|
|||
while(local_buffer[local_lect] == ' ') local_lect ++; |
|||
echantillon.extra = local_buffer + local_lect; |
|||
|
|||
lecture += strlen(local_buffer) + 1; |
|||
return 1; // Ici la ligne a été complètement décodée.
|
|||
} |
|||
|
|||
|
|||
/*************************************************************************************************************/ |
|||
|
|||
int main(int argc, char **argv) |
|||
{ |
|||
int fd; |
|||
char buffer[2 * TAILLE_BUFFER + 1]; |
|||
int entree, lecture; |
|||
acquisition_biosemi::biosemi_result msg; |
|||
|
|||
|
|||
// Vérification des paramètres de la ligne de commande :
|
|||
|
|||
if (argc < 2) { |
|||
cerr << "Appel par : biosemi_simul <nom du fichier> [<fréquence>]." << std::endl; |
|||
cerr << " -- le fichier doit contienir l'enregistrement BCI." << std::endl; |
|||
cerr << " -- la fréquence par défaut, si non spécifié, est 256 ech/sec." << std::endl; |
|||
exit(1); |
|||
} |
|||
|
|||
|
|||
// Connexion au fichier :
|
|||
|
|||
entree = 0; |
|||
lecture = 0; |
|||
fd = open(argv[1], O_RDONLY); |
|||
if (fd == -1) { |
|||
cout << "Erreur : fichier introuvable : " << argv[1] << "." << endl; |
|||
exit(1); |
|||
} |
|||
if (argc > 2) frequence = atoi(argv[2]); |
|||
|
|||
|
|||
// Initialisation de ROS :
|
|||
|
|||
ros::init(argc, argv, "biosemi_simul"); |
|||
ros::NodeHandle n; |
|||
ros::Publisher biosemi_pub = n.advertise<acquisition_biosemi::biosemi_result>("biosemi_result", 3); |
|||
ros::Rate loop_rate(10); |
|||
|
|||
|
|||
msg.numero = 0; |
|||
msg.nombre = 0; |
|||
msg.frequence = 0; |
|||
msg.valeurs.clear(); |
|||
msg.extra = ""; |
|||
while (ros::ok()) |
|||
{ |
|||
acquisition_biosemi::biosemi_echantillon ech; |
|||
|
|||
lecture_fichier(fd, buffer, &entree); |
|||
|
|||
while(recupere_ligne(ech, buffer, lecture, entree)) { |
|||
if (lecture >= TAILLE_BUFFER) { |
|||
lecture -= TAILLE_BUFFER; |
|||
entree -= TAILLE_BUFFER; |
|||
memcpy(buffer, buffer+TAILLE_BUFFER, TAILLE_BUFFER + 1); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
if (msg.numero == 0) msg.numero = ech.numero; |
|||
msg.nombre += 1; |
|||
msg.frequence = ech.frequence; |
|||
if (ech.extra != "") msg.extra = ech.extra; |
|||
for(std::vector<double>::const_iterator i = ech.valeurs.begin(); i != ech.valeurs.end(); ++i) |
|||
msg.valeurs.push_back(*i); |
|||
|
|||
|
|||
std::cout.setf(std::ios::fixed, std::ios::floatfield); |
|||
std::cout.precision(12); |
|||
std::cout.width(12); std::cout.fill('0'); |
|||
std::cout << ech.numero; |
|||
std::cout.width(0); std::cout.fill(' '); |
|||
std::cout << "[" << ech.frequence << "]: "; |
|||
for(std::vector<double>::const_iterator i = ech.valeurs.begin(); i != ech.valeurs.end(); ++i) |
|||
std::cout << " " << *i; |
|||
std::cout << " " << ech.extra << " (" << msg.nombre << ")" << std::endl; |
|||
|
|||
|
|||
|
|||
|
|||
if (msg.nombre == frequence/10) { |
|||
biosemi_pub.publish(msg); |
|||
ros::spinOnce(); |
|||
msg.numero = 0; |
|||
msg.nombre = 0; |
|||
msg.frequence = 0; |
|||
msg.valeurs.clear(); |
|||
msg.extra = ""; |
|||
loop_rate.sleep(); |
|||
} |
|||
} |
|||
if (fin_de_donnees) { |
|||
biosemi_pub.publish(msg); |
|||
ros::spinOnce(); |
|||
msg.numero = 0; |
|||
msg.nombre = 0; |
|||
msg.frequence = 0; |
|||
msg.valeurs.clear(); |
|||
msg.extra = ""; |
|||
std::cerr << "FIN DE DONNEES" << std::endl; |
|||
usleep(300000); |
|||
ros::shutdown(); |
|||
} |
|||
} |
|||
|
|||
close(fd); |
|||
return 0; |
|||
} |
|||
@ -0,0 +1,257 @@ |
|||
/*
|
|||
* biosemi_talker.cpp |
|||
* |
|||
* |
|||
* Programme permettant de diffuser sous ROS les échantillons en provenance |
|||
* du système d'acquisition biosemi. |
|||
* Note : un message est diffusé par échantillon, un échantillon peut |
|||
* contenir plusieurs canaux. |
|||
* |
|||
* |
|||
* |
|||
* Ce programme transmet des messages qui contiennt : |
|||
* - le numéro d'ordre de l'échantillon |
|||
* - la fréquence d'échantillonnage |
|||
* - un tableau de valeurs réelles (double) dont la taille dépend |
|||
* des paramètres de lancement du serveur d'acquistion (nombre de canaux) |
|||
* - une chaîne de caractères extra (pour les codes d'erreurs). |
|||
* |
|||
*/ |
|||
|
|||
#include "ros/ros.h" |
|||
#include "acquisition_biosemi/biosemi_result.h" |
|||
#include "acquisition_biosemi/biosemi_echantillon.h" |
|||
#include <sys/types.h> |
|||
#include <sys/socket.h> |
|||
#include <netinet/in.h> |
|||
#include <netdb.h> |
|||
#include <unistd.h> |
|||
|
|||
|
|||
|
|||
#define TAILLE_BUFFER 20000 |
|||
#define FREQUENCE 2048 |
|||
|
|||
using namespace std; |
|||
|
|||
static int frequence = FREQUENCE; |
|||
static int fin_de_donnees = 0; |
|||
|
|||
|
|||
/*************************************************************************************************************/ |
|||
|
|||
int appelleServeur(int port, char * name); |
|||
|
|||
// Appelle un serveur par son nom et un numéro de port.
|
|||
// Renvoie un numéro de socket, ou -1 si erreur.
|
|||
|
|||
int appelleServeur(int port, char * name) { |
|||
struct hostent *hostinfo; |
|||
struct sockaddr_in server; |
|||
int Socket; |
|||
|
|||
hostinfo=gethostbyname(name); |
|||
if (hostinfo == NULL) return -1; |
|||
bzero((char*)&server, sizeof(server)); |
|||
memcpy(&server.sin_addr, hostinfo->h_addr, hostinfo->h_length); |
|||
server.sin_family=AF_INET; |
|||
server.sin_port=htons(port); |
|||
Socket=socket(AF_INET,SOCK_STREAM,0);static int fin_de_donnees = 0; |
|||
|
|||
if (connect(Socket, (struct sockaddr *)&server, sizeof(server))) |
|||
return -1; |
|||
else |
|||
return Socket; |
|||
} |
|||
|
|||
/*************************************************************************************************************/ |
|||
|
|||
void lecture_reseau(int socket, char * buffer, int * entree) { |
|||
ssize_t longueur; |
|||
|
|||
if (*entree == 2 * TAILLE_BUFFER) return; |
|||
longueur = recv(socket, buffer + (*entree), 2 * TAILLE_BUFFER - (*entree), 0); |
|||
if (longueur <= 0) { |
|||
fin_de_donnees = 1; |
|||
} else { |
|||
*entree += longueur; |
|||
buffer[*entree] = 0; |
|||
} |
|||
} |
|||
|
|||
/*************************************************************************************************************/ |
|||
|
|||
int recupere_ligne(acquisition_biosemi::biosemi_echantillon & echantillon, const char * buffer, int & lecture, int & entree) { |
|||
int local_lect = 0; |
|||
int local_fin; |
|||
char * fin;ros::spinOnce(); |
|||
double valeur; |
|||
int ok; |
|||
char local_buffer[TAILLE_BUFFER+1]; |
|||
int i; |
|||
|
|||
static int compteur = 0; |
|||
|
|||
|
|||
// Récupération d'une ligne au maximum dans un buffer local.
|
|||
for(i = 0; (i+lecture < entree) && (buffer[i+lecture] != '\n') && (buffer[i+lecture] != 0); i++) { |
|||
local_buffer[i] = buffer[i+lecture]; |
|||
local_buffer[i+1] = '\0'; |
|||
} |
|||
if (buffer[i+lecture] != '\n') return 0; // Fin de la ligne non trouvée.
|
|||
|
|||
// On efface l'ancien contenu :
|
|||
echantillon.valeurs.clear(); |
|||
echantillon.frequence = frequence; |
|||
echantillon.extra = ""; |
|||
|
|||
// Lecture du numéro :
|
|||
echantillon.numero = strtoul(local_buffer + local_lect, &fin, 10); |
|||
local_fin = fin - local_buffer; |
|||
// Le caractère suivant est forcément un ':', sinon le numéro n'est pas présent.
|
|||
if (local_buffer[local_fin] != ':') { |
|||
compteur += 1; |
|||
echantillon.numero = compteur; |
|||
} else { |
|||
local_lect = local_fin + 1; |
|||
} |
|||
|
|||
|
|||
// On scanne des doubles, autant qu'on en trouve :
|
|||
do { |
|||
ok = 0; |
|||
valeur = strtod(local_buffer + local_lect, &fin); |
|||
local_fin = fin - local_buffer; |
|||
if (valeur != 0.0) { |
|||
ok = 1; // Une valeur non nulle indique une conversion correcte.
|
|||
} else { |
|||
// Une valeur nulle peut indiquer une conversion incorrecte, ou le fait que le nombre soit nul.
|
|||
// Il faut vérifier cela. On doit trouver des chiffres dans l'espace qui a étré scanné.
|
|||
ok = 0; |
|||
for(int i = local_lect; i < local_fin; i++) { |
|||
if ((local_buffer[i] >= '0') && (local_buffer[i] <= '9')) ok = 1; // Il y a des chiffres.
|
|||
} |
|||
} |
|||
if (ok) { |
|||
local_lect = local_fin; |
|||
echantillon.valeurs.push_back(valeur); |
|||
} |
|||
} while (ok); |
|||
|
|||
|
|||
// On recherche s'il y a encore des caractères sur la ligne :
|
|||
while(local_buffer[local_lect] == ' ') local_lect ++; |
|||
echantillon.extra = local_buffer + local_lect; |
|||
|
|||
lecture += strlen(local_buffer) + 1; |
|||
return 1; // Ici la ligne a été complètement décodée.
|
|||
} |
|||
|
|||
|
|||
|
|||
/*************************************************************************************************************/ |
|||
|
|||
int main(int argc, char **argv) |
|||
{ |
|||
int Socket; |
|||
char buffer[2 * TAILLE_BUFFER + 1]; |
|||
int entree, lecture; |
|||
acquisition_biosemi::biosemi_result msg; |
|||
|
|||
|
|||
// Vérification des paramètres de la ligne de commande :
|
|||
|
|||
if (argc < 2) { |
|||
cerr << "Appel par : biosemi_talker <nom du serveur> [<numéro de port>]." << std::endl; |
|||
cerr << " -- le serveur est la machine sous Windows reliée au système d'acquisition." << std::endl; |
|||
cerr << " -- le numéro de port par défaut, si non spécifié, est 50000." << std::endl; |
|||
exit(1); |
|||
} |
|||
|
|||
|
|||
// Initialisation de ROS :
|
|||
|
|||
ros::init(argc, argv, "biosemi_talker"); |
|||
ros::NodeHandle n; |
|||
ros::Publisher biosemi_pub = n.advertise<acquisition_biosemi::biosemi_result>("biosemi_result", 3); |
|||
|
|||
|
|||
// Connexion au serveur réseau :
|
|||
|
|||
Socket = appelleServeur( argc >= 3 ? atoi(argv[2]) : 50000 , argv[1] ); |
|||
if (Socket < 0) { |
|||
cout << "Erreur de connexion au serveur : " << argv[1] << endl; |
|||
ros::shutdown(); |
|||
} |
|||
entree = 0; |
|||
lecture = 0; |
|||
|
|||
|
|||
msg.numero = 0; |
|||
msg.nombre = 0; |
|||
msg.frequence = 0; |
|||
msg.valeurs.clear(); |
|||
msg.extra = ""; |
|||
while (ros::ok()) |
|||
{ |
|||
acquisition_biosemi::biosemi_echantillon ech; |
|||
|
|||
lecture_reseau(Socket, buffer, &entree); |
|||
|
|||
while(recupere_ligne(ech, buffer, lecture, entree)) { |
|||
if (lecture >= TAILLE_BUFFER) {ros::spinOnce(); |
|||
lecture -= TAILLE_BUFFER; |
|||
entree -= TAILLE_BUFFER; |
|||
memcpy(buffer, buffer+TAILLE_BUFFER, TAILLE_BUFFER + 1); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
if (msg.numero == 0) msg.numero = ech.numero; |
|||
msg.nombre += 1; |
|||
msg.frequence = ech.frequence; |
|||
if (ech.extra != "") msg.extra = ech.extra; |
|||
for(std::vector<double>::const_iterator i = ech.valeurs.begin(); i != ech.valeurs.end(); ++i) |
|||
msg.valeurs.push_back(*i); |
|||
|
|||
|
|||
std::cout.setf(std::ios::fixed, std::ios::floatfield); |
|||
std::cout.precision(12); |
|||
std::cout.width(12); std::cout.fill('0'); |
|||
std::cout << ech.numero; |
|||
std::cout.width(0); std::cout.fill(' '); |
|||
std::cout << "[" << ech.frequence << "]: "; |
|||
for(std::vector<double>::const_iterator i = ech.valeurs.begin(); i != ech.valeurs.end(); ++i) |
|||
std::cout << " " << *i; |
|||
std::cout << " " << ech.extra << std::endl; |
|||
|
|||
|
|||
|
|||
|
|||
if (msg.nombre == frequence/10) { |
|||
biosemi_pub.publish(msg); |
|||
ros::spinOnce(); |
|||
msg.numero = 0; |
|||
msg.nombre = 0; |
|||
msg.frequence = 0; |
|||
msg.valeurs.clear(); |
|||
msg.extra = ""; |
|||
} |
|||
} |
|||
if (fin_de_donnees) { |
|||
biosemi_pub.publish(msg); |
|||
ros::spinOnce(); |
|||
msg.numero = 0; |
|||
msg.nombre = 0; |
|||
msg.frequence = 0; |
|||
msg.valeurs.clear(); |
|||
msg.extra = ""; |
|||
ros::shutdown(); |
|||
std::cerr << "Perte de la connexion réseau." << endl; |
|||
} |
|||
} |
|||
|
|||
close(Socket); |
|||
return 0; |
|||
} |
|||
Loading…
Reference in new issue