首页 > 其他分享 >力矩传感器数据通信——ROS话题通讯的方式

力矩传感器数据通信——ROS话题通讯的方式

时间:2024-12-17 11:32:21浏览次数:6  
标签:数据通信 INT void UINT static 力矩 ROS com rq

目录

1. 创建工作空间

2.设置tasks.json文件

3.创建功能包

4. 修改c_cpp_properties.json文件

5. 修改内部的CMakeLists.txt文件

6. 创建.launch .h  .c  .cpp文件

 6.1 创建launch文件

6.2 创建.h源文件

6.3.创建src源文件

7.Ctrl+Shift+B编译项目

8.连接力矩传感器

9. 启动roscore

10.发布话题消息

11.接收话题消息


点击此处下载项目文件:力矩传感器通信传输数据,直接下载运行可用

1. 创建工作空间

mkdir -p ./robotiq_ft/src
cd ./robotiq_ft/
catkin_make
code .

2.设置tasks.json文件

Ctrl+Shift+B,No build to run found -> Create tasks.jason file from template -> Others example to run an arbitrary externalcommand,把下面的代码复制进tasks.json文件中

{
	// 有关 tasks.json 格式的文档,请参见
		// https://go.microsoft.com/fwlink/?LinkId=733558
		"version": "2.0.0",
		"tasks": [
			{
				"label": "catkin_make:debug", //代表提示的描述性信息
				"type": "shell",  //可以选择shell或者process,如果是shell代码是在shell里面运行一个命令,如果是process代表作为一个进程来运行
				"command": "catkin_make",//这个是我们需要运行的命令
				"args": [],//如果需要在命令后面加一些后缀,可以写在这里,比如-DCATKIN_WHITELIST_PACKAGES=“pac1;pac2”
				"group": {"kind":"build","isDefault":true},
				"presentation": {
					"reveal": "always"//可选always或者silence,代表是否输出信息
				},
				"problemMatcher": "$msCompile"
			}
		]
	}

再次按 Ctrl+Shift+B编译,编译成功即可

3.创建功能包

在src处右键,创建功能包robotiq_ft,添加roscpp rospy std_msgs

4. 修改c_cpp_properties.json文件

注意,要在includePath中,将"/home/yjw/Desktop/my_robotiq_ft/src/robotiq_ft/include/**"改成自己的功能包include文件夹所在的路径,方法是在include处打开终端,输入pwd命令就会出现路径

{
  "configurations": [
    {
      "browse": {
        "databaseFilename": "${default}",
        "limitSymbolsToIncludedHeaders": false
      },
      "includePath": [
        "/opt/ros/melodic/include/**",
        "/usr/include/**",
        "/home/yjw/Desktop/my_robotiq_ft/src/robotiq_ft/include/**"
      ],
      "name": "ROS",
      "intelliSenseMode": "gcc-x64",
      "compilerPath": "/usr/bin/gcc",
      "cStandard": "gnu11",
      "cppStandard": "c++14"
    }
  ],
  "version": 4
}

5. 修改内部的CMakeLists.txt文件

cmake_minimum_required(VERSION 3.0.2)
project(robotiq_ft)


find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
)

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES robotiq_ft
#  CATKIN_DEPENDS roscpp rospy std_msgs
#  DEPENDS system_lib
)


include_directories(
   include
  ${catkin_INCLUDE_DIRS}
)

include_directories("/usr/include/eigen3") 


add_library(robotiq_lib              # 自己定义库的名字robotiq_lib 
  include/${PROJECT_NAME}/mutex.h     # 调用的自定义头文件,${PROJECT_NAME}表示功能包名
  include/${PROJECT_NAME}/rq_int.h 
  include/${PROJECT_NAME}/rq_sensor_com.h 
  include/${PROJECT_NAME}/rq_sensor_socket.h 
  include/${PROJECT_NAME}/rq_sensor_state.h 
  include/${PROJECT_NAME}/rq_thread.h 

  
  src/mutex.c                       # 调用的自定义源文件
  src/my_robotiq_ft.cpp
  src/rq_sensor_com.c 
  src/rq_sensor_socket.c 
  src/rq_sensor_state.c
  src/rq_thread.c
)




add_executable(my_robotiq_ft src/my_robotiq_ft.cpp)
add_executable(robotiq_sub
  src/robotiq_sub.cpp
)

# find_package(Franka 0.7.0 REQUIRED)

add_dependencies(robotiq_lib ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(my_robotiq_ft ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(robotiq_sub ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})

target_link_libraries(robotiq_lib
  # ${Franka_LIBRARIES} 
  ${catkin_LIBRARIES}
)
target_link_libraries(my_robotiq_ft
  robotiq_lib
  # ${Franka_LIBRARIES} 
  ${catkin_LIBRARIES}
)

target_link_libraries(robotiq_sub
  robotiq_lib
  # ${Franka_LIBRARIES} 
  ${catkin_LIBRARIES}
)

6. 创建.launch .h  .c  .cpp文件

所有文件如下所示

 6.1 创建launch文件

在生成的robotiq_ft功能包目录中右键,添加launch文件夹,然后在launch文件夹中添加my_robotiq_ft.launch文件

<launch>
    <node name="my_robotiq_ft" pkg="robotiq_ft" type="my_robotiq_ft" />
</launch>

6.2 创建.h源文件

在include目录下创建mutex.h,rq_int.h,rq_sensor_com.h,rq_sensor_socket.h,rq_sensor_state.h,rq_thread.h  具体代码如下(这里要检查一下include文件夹名是否显示为include/robotiq_ft,如果robotiq_ft没有跟在inlcude后面,则会报错)

mutex.h

/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file mutex.h
 *  \date July 2, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */


#ifndef MUTEX_H_
#define MUTEX_H_

#ifdef __unix__ //For Unix
	#include <pthread.h>
	#define MUTEX pthread_mutex_t
#elif defined(_WIN32)||defined(WIN32) //For Windows
	#include <windows.h>
	#include <process.h>
	#define MUTEX HANDLE
#endif

//Functions
int MUTEX_INIT(MUTEX *mutex);
int MUTEX_LOCK(MUTEX *mutex);
int MUTEX_UNLOCK(MUTEX *mutex);

#endif /* MUTEX_H_ */

rq_int.h

/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file rq_int.h
 *  \date June 30, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */

#ifndef RQ_INT_H_
#define RQ_INT_H_

typedef	char	INT_8;
typedef	short	INT_16;
typedef	int	INT_32;
typedef	long	INT_64;

typedef	unsigned char	UINT_8;
typedef	unsigned short	UINT_16;
typedef	unsigned int	UINT_32;
typedef	unsigned long	UINT_64;

#endif

rq_sensor_com.h

/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file rq_sensor_com.h
 *  \date June 19, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */

#ifndef RQ_SENSOR_COM_H
#define RQ_SENSOR_COM_H

#include "rq_int.h"
#include <stdio.h>
 #include <stdbool.h>

#define MP_BUFF_SIZE    1024

INT_8 rq_sensor_com(void);
void rq_sensor_com_read_info_high_lvl(void);
INT_8 rq_com_start_stream(void);
void rq_com_listen_stream(void);
bool rq_com_get_stream_detected(void);
bool rq_com_get_valid_stream(void);

//Accesseur
void rq_com_get_str_serial_number(INT_8 * serial_number);
void rq_com_get_str_firmware_version(INT_8 * firmware_version);
void rq_com_get_str_production_year(INT_8 * production_year);
float rq_com_get_received_data(UINT_8 i);
bool rq_com_got_new_message(void);
void rq_com_do_zero_force_flag(void);
void stop_connection(void);

#endif //RQ_SENSOR_COM_H

 rq_sensor_socket.h

/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file socket.h
 *  \date May 20, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */

#ifndef RQ_SENSOR_SOCKET_H_
#define RQ_SENSOR_SOCKET_H_

#include <stdint.h>

#ifdef WIN32

#include <winsock2.h>

#elif defined (linux)

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h> /* close */
#include <netdb.h> /* gethostbyname */
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define closesocket(s) close(s)
typedef int SOCKET;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
typedef struct in_addr IN_ADDR;

#else

#error not defined for this platform

#endif

int init_connection();
void end_connection(int sock);
void write_client(SOCKET sock, uint8_t *buffer);
#ifdef __unix__ //For Unix
	void *Read_socket(void *t);
#elif defined(_WIN32)||defined(WIN32) //For Windows
	void __cdecl Read_socket( void *t );
#endif
void set_socket_message_to_null(void);
void socket_message(uint8_t * chr_return);
int getNbClient(void);
SOCKET get_client_sock_accessor(void);
SOCKET get_client_sock_stream(void);
SOCKET get_socket_stream();

#endif /* RQ_SENSOR_SOCKET_H_l */

 rq_sensor_state.h

/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file rq_sensor_state.h
 *  \date June 19, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */

#ifndef RQ_SENSOR_STATE_H
#define RQ_SENSOR_STATE_H


#include "rq_int.h"
#include <stdbool.h>


enum rq_sensor_state_values 
{
	RQ_STATE_INIT,         ///< State that initialize the com. with the sensor
	RQ_STATE_READ_INFO,    ///< State that reads the firmware version,
	                       ///< serial number and production year
	RQ_STATE_START_STREAM, ///< State that start the sensor in streaming
	                       ///< mode
	RQ_STATE_RUN           ///< State that reads the streaming data from 
		                   ///< the sensor
};

INT_8 rq_sensor_state(void);
void rq_state_get_command(INT_8 const * const name, INT_8 * const  value);
void rq_set_zero(void);
enum rq_sensor_state_values rq_sensor_get_current_state(void);
bool rq_state_got_new_message(void);
float rq_state_get_received_data(UINT_8 i);

#endif //RQ_SENSOR_STATE_H

rq_thread.h

/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file rq_thread.h
 *  \date July 3, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */

#ifndef RQ_THREAD_H_
#define RQ_THREAD_H_

#ifdef __unix__ //For Unix
 int create_Thread(void *(*start_rtn)(void *));
#elif defined(_WIN32)||defined(WIN32) //For Windows
int create_Thread(void( __cdecl *start_address )( void * ));
#endif

int close_Thread(int iId);
void wait_thread(int iId);

 #endif /* RQ_THREAD_H_ */

6.3.创建src源文件

在生成的第二个src目录下创建mutex.c,my_robotiq_ft.cpp,robotiq_sub.cpp,rq_sensor_com.c,rq_sensor_socket.c,rq_sensor_state.c,rq_thread.c  具体代码如下

mutex.c

/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file mutex.c
 *  \date July 2, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */

#ifdef __unix__ //For Unix
	#include <pthread.h>
	#define MUTEX pthread_mutex_t
#elif defined(_WIN32)||defined(WIN32) //For Windows
	#include <windows.h>
	#include <process.h>
	#define MUTEX HANDLE
#endif

int MUTEX_INIT(MUTEX *mutex)
{
	#ifdef __unix__ //For Unix
        return pthread_mutex_init (mutex, NULL);;
	#elif defined(_WIN32)||defined(WIN32) //For Windows
        *mutex = CreateMutex(0, FALSE, 0);;
        return (*mutex==0);
	#endif
    return -1;
}

int MUTEX_LOCK(MUTEX *mutex)
{
	#ifdef __unix__ //For Unix
		return pthread_mutex_lock( mutex );
	#elif defined(_WIN32)||defined(WIN32) //For Windows
		return (WaitForSingleObject(*mutex, INFINITE)==WAIT_FAILED?1:0);
	#endif
    return -1;
}

int MUTEX_UNLOCK(MUTEX *mutex)
{
	#ifdef __unix__ //For Unix
        return pthread_mutex_unlock( mutex );
	#elif defined(_WIN32)||defined(WIN32) //For Windows
		return (ReleaseMutex(*mutex)==0);
	#endif
    return -1;
}

my_robotiq_ft.cpp

/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file main.c
 *  \date June 18, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */

// 包含了 ROS、STL 和 Robotiq 的相关头文件。
// ROS 头文件 主要用于与 ROS 系统交互,处理消息传递和坐标变换。
#include "ros/ros.h"
// 这个头文件定义了 ROS 消息类型 geometry_msgs::WrenchStamped,它表示带时间戳和框架ID的力矩传感器数据。Wrench 是一个三维力和三维力矩的组合,通常用于表示力传感器输出的数据。
// geometry_msgs::WrenchStamped 消息类型包含以下字段:
// header: 消息头,包含时间戳和坐标系(frame_id)。
// wrench: 力矩数据,包含力(force)和力矩(torque)。
#include "geometry_msgs/WrenchStamped.h"
// 这个头文件定义了与 tf 库相关的数据类型和函数,tf 库用于 ROS 中不同坐标系之间的变换。transform_datatypes.h 包含了坐标变换所需的矩阵、四元数等数据结构及操作函数。
#include "tf/transform_datatypes.h"
// 该头文件提供了 tf::TransformBroadcaster 类,用于在 ROS 中发布坐标系变换。它允许你广播坐标系之间的变换(例如,发布从传感器坐标系到机器人基坐标系的变换)。
#include "tf/transform_broadcaster.h"



// STL头文件 提供了标准库的功能,主要用于线程管理和输入输出
#include <thread>  // 这个头文件来自 C++ 标准库,用于线程管理。在这里,通常用于在 ROS 循环中进行阻塞式等待或者实现多线程操作。
#include <iostream>  //这是 C++ 标准输入输出流库,提供了 std::cout、std::cin 等功能,用于输出调试信息或读取输入。



// Robotiq's code
// rq 命名空间下包含了 Robotiq 的 C 语言接口,提供与传感器通信的功能。
namespace rq {
    extern "C" {
        //提供了与 Robotiq 传感器通信的功能,通常用于建立与传感器的连接、发送和接收数据。
        #include "robotiq_ft/rq_sensor_com.h"   
        // 定义了获取传感器状态的相关函数和数据结构,可以获取传感器的当前状态(如传感器是否工作正常、传感器的读取值等)。
        #include "robotiq_ft/rq_sensor_state.h"
        // 提供了与 Robotiq 接口的整数相关功能,通常用于处理与传感器接口通信时所需的整数数据类型和转换。
        #include "robotiq_ft/rq_int.h"
        // 提供了多线程相关功能,用于在进行传感器通信时确保线程的正确管理和同步。
        #include "robotiq_ft/rq_thread.h"
        //   #include "robotiq_ft/mutex.h"
    }
}  // namespace rq



// 该函数不断检查与传感器的连接状态,直到成功连接为止。
// rq::rq_sensor_state() 返回 0 表示连接成功。
namespace rq {
    void wait_for_other_connection() {
        using namespace std::chrono_literals;  //using namespace std::chrono_literals; 允许使用字面量(literal)来简化时间表示。在这里,它使得 1s 这个字面量表示 1 秒的时间,而不需要使用 std::chrono::seconds(1) 来表示。
        rq::INT_8 ret;  //定义了一个类型为 INT_8 的变量 ret。这个类型通常表示一个 8 位整数,用来存储与传感器状态相关的返回值。rq::rq_sensor_state() 函数将返回这个状态值。
        ROS_DEBUG_STREAM("waiting for connection\n");
        while (true) {
            std::this_thread::sleep_for(1s);  //std::this_thread::sleep_for(1s); 使得当前线程暂停(即“睡眠”)1秒
            ret = rq::rq_sensor_state();
            if (ret == 0) {
                break;
            }
        }
    }
}


// 该函数用于初始化传感器的连接,调用 rq::rq_sensor_state() 来检查传感器的连接状态。
// 如果传感器状态返回 -1,表示连接失败,会调用 wait_for_other_connection 等待重新连接。
void setup_robotiq() {
    //IF can't connect with the sensor wait for another connection
    rq::INT_8 ret = rq::rq_sensor_state();
    ROS_DEBUG_STREAM("first\n");
    
    if (ret == -1) {
        rq::wait_for_other_connection();
        //  fprintf(stderr, "NO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
    }

    //Read high-level informations
    ret = rq::rq_sensor_state();
    ROS_DEBUG_STREAM("second\n");
    if (ret == -1) {
        rq::wait_for_other_connection();
    }

    //Initialize connection with the client
    ret = rq::rq_sensor_state();
    ROS_DEBUG_STREAM("third\n");
    if (ret == -1) {
        rq::wait_for_other_connection();
         
    }
}



int main(int argc, char** argv) {
    const std::string pub_topic_param = "/ftsensor_node_name";
    const std::string sensor_frame_id_param = "/ftsensor_frame";

    setup_robotiq();
    
    // 初始化 ROS 节点
    ros::init(argc, argv, "my_robotiq_ft");
    ros::NodeHandle ros_node;

    // 这段代码的作用是从 ROS 参数服务器获取两个参数:
    // pub_topic_param 对应的 node_name,这是发布话题的名称。
    // sensor_frame_id_param 对应的 frame_id,这是传感器数据使用的坐标系框架 ID。
    std::string node_name;
    std::string frame_id;
    const int queue_size = 10; //消息队列长度,多余的抛弃

  // ???????????????????????????????????????????????????????
    // if (!ros_node.getParam(pub_topic_param, node_name)) {
    //     ROS_ERROR_STREAM(pub_topic_param << " not found in parameter server!\n");
    //     return -1;
    // }
    // if (!ros_node.getParam(sensor_frame_id_param, frame_id)) {
    //     ROS_ERROR_STREAM(sensor_frame_id_param << " not found in parameter server!\n");
    //     return -1;S
    // }

    // 创建一个发布者 sensor_pub,它将消息类型设为 geometry_msgs::WrenchStamped,并将数据发布到 node_name 主题,队列大小为 10   
    // ros::Publisher sensor_pub = ros_node.advertise<geometry_msgs::WrenchStamped>(node_name, queue_size);
   ros::Publisher sensor_pub = ros_node.advertise<geometry_msgs::WrenchStamped>("robotiq_ft", queue_size);

    ROS_DEBUG_STREAM("ready!\n");

    while (ros::ok()) {
        // 调用 rq_sensor_state() 获取传感器状态
        rq::INT_8 ret = rq::rq_sensor_state();
        // 如果获取传感器状态失败,等待其他连接
        if (ret == -1) {
            rq::wait_for_other_connection();  
        }
        
        // 如果传感器当前状态是 RUN 状态,继续执行
        if (rq::rq_sensor_get_current_state() == rq::RQ_STATE_RUN) {
           
            geometry_msgs::WrenchStamped msg;

            // 设置消息头部信息
            msg.header.frame_id = frame_id;   // 坐标系 ID
            msg.header.stamp = ros::Time(0);  // 时间戳,设置为 0 表示无特定时间

            // 填充力和力矩数据
            msg.wrench.force.x  = rq::rq_state_get_received_data(0);  // 力的 X 分量
            msg.wrench.force.y  = rq::rq_state_get_received_data(1);   // 力的 Y 分量
            msg.wrench.force.z  = rq::rq_state_get_received_data(2);   // 力的 Z 分量
            msg.wrench.torque.x = rq::rq_state_get_received_data(3);   // 力矩的 X 分量
            msg.wrench.torque.y = rq::rq_state_get_received_data(4);  // 力矩的 Y 分量
            msg.wrench.torque.z = rq::rq_state_get_received_data(5);  // 力矩的 Z 分量
              fprintf(stderr, "YES!\n");


             // 发布消息到话题
            sensor_pub.publish(msg);

            // 调用 ros::spinOnce() 进行一次事件处理,处理订阅的消息
            ros::spinOnce();
        }

        // ros::Duration(0.1).sleep();
    }
    return 0;
 }

robotiq_sub.cpp

#include "ros/ros.h"
#include "geometry_msgs/WrenchStamped.h"// 引入 WrenchStamped 消息类型

// 定义一个回调函数来处理接收到的 WrenchStamped 消息
void wrenchCallback(const geometry_msgs::WrenchStamped::ConstPtr& msg)
{
    // 打印消息中的力和力矩信息
    ROS_INFO("Received Wrench data:");
    ROS_INFO("Force: [%.3f, %.3f, %.3f]", msg->wrench.force.x, msg->wrench.force.y, msg->wrench.force.z);
    ROS_INFO("Torque: [%.3f, %.3f, %.3f]", msg->wrench.torque.x, msg->wrench.torque.y, msg->wrench.torque.z);
}

int main(int argc, char** argv)
{
    // 初始化 ROS 节点
    ros::init(argc, argv, "wrench_listener");
    ros::NodeHandle nh;

    // 订阅传感器数据话题 (假设话题名称为 /sensor_wrench)
    ros::Subscriber sub = nh.subscribe("robotiq_ft", 10, wrenchCallback);

    // 进入循环,等待回调函数
    ros::spin();

    return 0;
}

rq_sensor_com.c

// /* Software License Agreement (BSD License)
// *
// * Copyright (c) 2014, Robotiq, Inc.
// * All rights reserved.
// *
// * Redistribution and use in source and binary forms, with or without
// * modification, are permitted provided that the following conditions
// * are met:
// *
// * * Redistributions of source code must retain the above copyright
// * notice, this list of conditions and the following disclaimer.
// * * Redistributions in binary form must reproduce the above
// * copyright notice, this list of conditions and the following
// * disclaimer in the documentation and/or other materials provided
// * with the distribution.
// * * Neither the name of Robotiq, Inc. nor the names of its
// * contributors may be used to endorse or promote products derived
// * from this software without specific prior written permission.
// *
// * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// * POSSIBILITY OF SUCH DAMAGE.
// *
// * Copyright (c) 2014, Robotiq, Inc
// */

// /*
//  *  \file rq_sensor_com.c
//  *  \date June 18, 2014
//  *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
//  *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
//  */

// //
// //Includes

// //Platform specific
// #ifdef __unix__ /*For Unix*/
// #define _BSD_SOURCE
// #include <termios.h>
// #include <unistd.h>
// #include <dirent.h>
// #include <fcntl.h>
// #include <unistd.h>
// #include <time.h>
// #define Sleep(x) (usleep (x*1000))
// #elif defined(_WIN32)||defined(WIN32) /*For Windows*/
// #include <windows.h>
// #endif

// #include <string.h>
// #include <errno.h>

// //application specific
// #include "robotiq_ft/rq_sensor_com.h"

// // Definitions
// #define REGISTER_SELECT_OUTPUT 410
// #define REGISTER_SERIAL_NUMBER 510
// #define REGISTER_PRODUCTION_YEAR 514
// #define REGISTER_FIRMWARE_VERSION 500
// #define RQ_COM_MAX_STR_LENGTH 20
// #define RQ_COM_JAM_SIGNAL_CHAR      0xff
// #define RQ_COM_JAM_SIGNAL_LENGTH    50
// #define RQ_COM_TIMER_FOR_STREAM_DETECTION_MAX_VALUE 20 //20 * 4ms =  80ms sans bytes avant de dire qu'on n'a pas le stream
// #define RQ_COM_TIMER_FOR_VALID_STREAM_MAX_VALUE     40 //40 * 4ms = 160ms sans messages valide afin de dire que la communication fonctionne mal (16 mauvais messages)

// 
// // Private variables
// static float rq_com_received_data[6] = {0.0};
// static float rq_com_received_data_offset[6] = {0.0};

// static UINT_16 rq_com_computed_crc = 0;
// static UINT_16 rq_com_crc = 0;

// static INT_8 rq_com_str_sensor_serial_number[RQ_COM_MAX_STR_LENGTH];
// static INT_8 rq_com_str_sensor_production_year[RQ_COM_MAX_STR_LENGTH];
// static INT_8 rq_com_str_sensor_firmware_version[RQ_COM_MAX_STR_LENGTH];

// static UINT_32 rq_com_msg_received = 0;

// static UINT_8 rq_com_rcv_buff[MP_BUFF_SIZE];
// static UINT_8 rq_com_snd_buff[MP_BUFF_SIZE];
// static UINT_8 rq_com_rcv_buff2[MP_BUFF_SIZE];
// static INT_32 rq_com_rcv_len;
// static INT_32 rq_com_rcv_len2 = 0;

// static INT_32 rq_com_zero_force_flag = 0;
// static INT_32 rq_state_sensor_watchdog = 0;

// //variables related to the communication status
// static bool rq_com_stream_detected = false;
// static bool rq_com_valid_stream = false;
// static bool rq_com_new_message = false;
// static INT_32  rq_com_timer_for_stream_detection = 0;
// static INT_32  rq_com_timer_for_valid_stream = 0;

// ///
// //Private functions declaration
// static INT_8 rq_com_tentative_connexion(void);
// static void rq_com_send_jam_signal(void);
// static void rq_com_stop_stream_after_boot(void);

// static INT_32 rq_com_read_port(UINT_8 * const buf, UINT_32 buf_len);
// static INT_32 rq_com_write_port(UINT_8 const * const buf, UINT_32 buf_len);

// //Modbus functions
// static UINT_16 rq_com_compute_crc(UINT_8 const * adr, INT_32 length );
// static void rq_com_send_fc_03_request(UINT_16 base, UINT_16 n);
// static void rq_com_send_fc_16_request(INT_32 base, INT_32 n, UINT_8 const * const data);
// static INT_32 rq_com_wait_for_fc_03_echo(UINT_8 * const data);
// static INT_32 rq_com_wait_for_fc_16_echo(void);
// static INT_8 rq_com_send_fc_03(UINT_16 base, UINT_16 n, UINT_16 * const data);
// static INT_8 rq_com_send_fc_16(INT_32 base, INT_32 n, UINT_16 const * const data);

// #ifdef __unix__ //For Unix
// static UINT_8 rq_com_identify_device(INT_8 const * const d_name);
// #endif //For Unix

// #ifdef __unix__ //For Unix
// static INT_32 fd_connexion = -1;
// static INT_8 set_com_attribs (INT_32 fd, speed_t speed);
// #elif defined(_WIN32)||defined(WIN32) //For Windows
// HANDLE hSerial;
// #endif

// #include <stdio.h>

// //
// //Function definitions

// /**
//  * \fn void rq_sensor_com(void)
//  * \brief Discovers and initialize the communication with the sensor
//  * \details The functions loops  through all the serial com ports 
//  *          and polls them to discover the sensor
//  */
// INT_8 rq_sensor_com()
// {
// #ifdef __unix__ //For Unix
// 	UINT_8 device_found = 0;
// 	DIR *dir = NULL;
// 	struct dirent *entrydirectory = NULL;

// 	//Close a previously opened connection to a device
// 	close(fd_connexion);
// 	if ((dir = opendir("/sys/class/tty/")) == NULL)
// 	{
//                 fprintf(stderr, "/sys/class/tty can't be opened");
// 		return -1;
// 	}

// 	//Loops through the files in the /sys/class/tty/ directory
// 	while ((entrydirectory = readdir(dir)) != NULL && device_found == 0)
// 	{
// 		//Look for a serial device
// 		if (strstr(entrydirectory->d_name, "ttyS") || 
// 		    strstr(entrydirectory->d_name, "ttyUSB"))
// 		{
//                         fprintf(stderr, "found: %s\n", entrydirectory->d_name);
// 			device_found = rq_com_identify_device(entrydirectory->d_name);
// 		}
// 	}

// 	closedir(dir);

// 	if (device_found == 0)
// 	{
//                 fprintf(stderr, "no device found in /sys/class/tty\n");
// 		return -1;
// 	}
// #elif defined(_WIN32)||defined(WIN32) //For Windows
// 	DCB dcb;
// 	INT_32 i;
// 	INT_8 port[13];
// 	for(i = 0;i < 256; i++){
// 		sprintf(port,"\\\\.\\COM%d",i);
// 		hSerial = CreateFileA(port, GENERIC_READ | GENERIC_WRITE,
// 				0,NULL,OPEN_EXISTING,0,NULL);
// 		if(hSerial != INVALID_HANDLE_VALUE){
// 			dcb.DCBlength = sizeof(DCB);
// 			if (!GetCommState(hSerial, &dcb)){
// 				CloseHandle(hSerial);
// 				hSerial = INVALID_HANDLE_VALUE;
// 				continue;//Permet de recommencer la boucle
// 			}
// 			dcb.BaudRate = CBR_19200;
// 			dcb.ByteSize = 8;
// 			dcb.StopBits = ONESTOPBIT;
// 			dcb.Parity = NOPARITY;
// 			dcb.fParity = FALSE;

// 			/* No software handshaking */
// 			dcb.fTXContinueOnXoff = TRUE;
// 			dcb.fOutX = FALSE;
// 			dcb.fInX = FALSE;
// 			//dcb.fNull = FALSE;

// 			/* Binary mode (it's the only supported on Windows anyway) */
// 			dcb.fBinary = TRUE;

// 			/* Don't want errors to be blocking */
// 			dcb.fAbortOnError = FALSE;

// 			/* Setup port */
// 			if(!SetCommState(hSerial, &dcb)){
// 				CloseHandle(hSerial);
// 				continue;//Permet de recommencer la boucle
// 			}
// 			COMMTIMEOUTS timeouts={0};
// 			timeouts.ReadIntervalTimeout=0;
// 			timeouts.ReadTotalTimeoutConstant=1;
// 			timeouts.ReadTotalTimeoutMultiplier=0;
// 			timeouts.WriteTotalTimeoutConstant=1;
// 			timeouts.WriteTotalTimeoutMultiplier=0;
// 			if(!SetCommTimeouts(hSerial, &timeouts)){
// 				CloseHandle(hSerial);
// 				hSerial = INVALID_HANDLE_VALUE;
// 				continue;//Permet de recommencer la boucle
// 			}
// 			if (rq_com_tentative_connexion() == 1){
// 				return 0;
// 			}
// 			CloseHandle(hSerial);
// 		}
// 	}
// 	return -1;
// #else
// #endif
// 	return 0;
// }

// /**
//  * \fn static INT_8 rq_com_tentative_connexion()
//  * \brief Tries connecting to the sensor
//  * \returns 1 if the connection attempt succeeds, -1 otherwise
//  */
// static INT_8 rq_com_tentative_connexion()
// {
// 	INT_32 rc = 0;
// 	UINT_16 firmware_version [1];
// 	UINT_8 retries = 0;

// 	while(retries < 5 && rq_com_stream_detected == false)
// 	{
// 		rq_com_listen_stream();
// 		retries++;
// 	}

// 	rq_com_listen_stream();
// 	if(rq_com_stream_detected)
// 	{
// 		rq_com_stop_stream_after_boot();
// 	}

// 	//Give some time to the sensor to switch to modbus
// 	Sleep(100);

// 	//If the device returns an F as the first character of the fw version,
// 	//we consider its a sensor
// 	rc = rq_com_send_fc_03(REGISTER_FIRMWARE_VERSION, 2, firmware_version);
// 	if (rc != -1)
// 	{
// 		if (firmware_version[0] >> 8 == 'F')
// 		{
// 			return 1;
// 		}
// 	}

// 	return -1;
// }

// /**
//  * \fn static INT_8 set_com_attribs()
//  * \brief Sets the com port parameters to match those of the sensor
//  * \param fd, file descriptor that points to the serial port
//  * \param speed, baudrate
//  * \return 0 in case of a success, -1 otherwise
//  */
// #ifdef __unix__ //For Unix
// static INT_8 set_com_attribs (INT_32 fd, speed_t speed)
// {
// 	struct termios tty;
// 	memset (&tty, 0, sizeof (struct termios));

// 	if (tcgetattr (fd, &tty) != 0)
// 	{
// 		return -1;
// 	}

// 	cfsetospeed (&tty, speed);
// 	cfsetispeed (&tty, speed);

// 	tty.c_cflag |= (CLOCAL | CREAD);
// 	tty.c_cflag &= ~CSIZE;
// 	tty.c_cflag |= CS8;
// 	tty.c_cflag &= ~CSTOPB;
// 	tty.c_cflag &= ~PARENB;
// 	tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// 	tty.c_iflag &= ~INPCK;
// 	tty.c_iflag &= ~(IXON | IXOFF | IXANY);
// 	tty.c_cc[VMIN]  = 0;			// read doesn't block
// 	tty.c_cc[VTIME] = 1;

// 	if (tcsetattr (fd, TCSANOW, &tty) != 0)
// 	{
// 		printf("error %d from tcsetattr", errno);
// 		return -1;
// 	}

// 	return 0;
// }
// #endif

// /**
//  * \fn void rq_com_listen_stream()
//  * \brief Listens and decode a valid stream input
//  */
// void rq_com_listen_stream(void)
// {
// 	static INT_32 last_byte = 0;
// 	static INT_32 new_message = 0;
// 	INT_32 i = 0;
// 	INT_32 j = 0;    

// 	//Capture and store the current value of the sensor and use it to
// 	//zero subsequent sensor values
// 	if(rq_com_zero_force_flag == 1)
// 	{
// 		rq_com_zero_force_flag = 0;

// 		for(i = 0; i < 6; i++)
// 		{
// 			rq_com_received_data_offset[i] = rq_com_received_data[i];
// 		}

// 	}

// 	Sleep(10);

// 	//Increment communication state counters
// 	if(rq_com_timer_for_stream_detection++ > RQ_COM_TIMER_FOR_STREAM_DETECTION_MAX_VALUE)
// 	{
// 		rq_com_timer_for_stream_detection = RQ_COM_TIMER_FOR_STREAM_DETECTION_MAX_VALUE;
// 		rq_com_stream_detected = false;
// 	}

// 	if(rq_com_timer_for_valid_stream++ > RQ_COM_TIMER_FOR_VALID_STREAM_MAX_VALUE)
// 	{
// 		rq_com_timer_for_valid_stream = RQ_COM_TIMER_FOR_VALID_STREAM_MAX_VALUE;
// 		rq_com_valid_stream = false;
// 	}

// 	last_byte = 0;
// 	new_message = 0;

// 	//Data reception
// 	rq_com_rcv_len = rq_com_read_port(rq_com_rcv_buff, MP_BUFF_SIZE);

// 	//If at least a byte is received, we consider the sensor to stream
// 	if(rq_com_rcv_len > 0)
// 	{
// 		rq_com_stream_detected = true;
// 		rq_com_timer_for_stream_detection = 0;
// 	}

// 	//Copie les données au bout du buffer 2
// 	for(i = 0; i < rq_com_rcv_len; i++)
// 	{
// 		//If the buffer overflows, set the index to the beginning
// 		if(rq_com_rcv_len2 == MP_BUFF_SIZE)
// 		{
// 			//Next bytes will overwrite the begining of the buffer
// 			rq_com_rcv_len2 = 0;
// 			break;
// 		}

// 		rq_com_rcv_buff2[rq_com_rcv_len2++] = rq_com_rcv_buff[i];
// 	}

// 	//empty the buffers
// 	memset( rq_com_rcv_buff, 0, sizeof(rq_com_rcv_buff));
// 	memset( rq_com_snd_buff, 0, sizeof(rq_com_snd_buff));

// 	//If there is enough characters,...
// 	if(rq_com_rcv_len2 >= 16 && rq_com_rcv_len >= 1) 
// 	{        
// 		//Search for a valid stream message in the buffer
// 		for(i = rq_com_rcv_len2 - 16; i >= 0; i--)
// 		{
// 			//Header
// 			if(rq_com_rcv_buff2[i] == 0x20 && rq_com_rcv_buff2[i+1] == 0x4E && new_message == 0)
// 			{

// 				last_byte = i - 1;

// 				rq_com_computed_crc = rq_com_compute_crc(rq_com_rcv_buff2 + i * sizeof(*rq_com_rcv_buff2), 14);

// 				rq_com_crc 			= (rq_com_rcv_buff2[i+14] + rq_com_rcv_buff2[i+15] * 256);

// 				rq_com_msg_received++;


// 				//The crc is valid.. the message can be used
// 				if(rq_com_computed_crc == rq_com_crc)
// 				{
// 					last_byte = i + 15; //will erase the message

// 					//convert the efforts to floating point numbers
// 					for(j = 0; j < 3; j++)
// 					{
// 						rq_com_received_data[j] = ((float)((INT_16)((UINT_8)rq_com_rcv_buff2[i+2+2*j] + ((INT_16)(UINT_8)rq_com_rcv_buff2[i+3+2*j]) * 256))) / 100 ;
// 					}

// 					for(j = 3; j < 6; j++)
// 					{
// 						rq_com_received_data[j] = ((float)((INT_16)((UINT_8)rq_com_rcv_buff2[i+2+2*j] + ((INT_16)(UINT_8)rq_com_rcv_buff2[i+3+2*j]) * 256))) / 1000;
// 					}

// 					//Signal the stream as valid
// 					rq_com_valid_stream = true;
// 					rq_com_new_message = true;
// 					rq_com_timer_for_valid_stream = 0;

// 					new_message = 1;
// 					rq_state_sensor_watchdog = 1;

// 				}
// 				else
// 				{
// 					last_byte = i + 15;
// 					new_message = 1;
// 				}
// 			}
// 		}

// 		if(last_byte > 0)
// 		{
// 			//On shift le buffer 2 afin de ne garder que ce qui dépasse le dernier caractère du dernier message complet
// 			for(i = 0; i < (rq_com_rcv_len2 - last_byte - 1); i++)
// 			{
// 				rq_com_rcv_buff2[i] = rq_com_rcv_buff2[last_byte + 1 + i];
// 			}
// 			rq_com_rcv_len2 = rq_com_rcv_len2 - last_byte - 1;
// 		}
// 	}
// }

// /**
//  * \fn static void rq_com_send_jam_signal(void)
//  * \brief Send a signal that interrupts the streaming
//  */
// static void rq_com_send_jam_signal(void)
// {
// 	//Build the jam signal
// 	memset(rq_com_snd_buff, RQ_COM_JAM_SIGNAL_CHAR, RQ_COM_JAM_SIGNAL_LENGTH);

// 	//Send the jam signal
// 	rq_com_write_port(rq_com_snd_buff,RQ_COM_JAM_SIGNAL_LENGTH);
// }


// /**
//  * \fn static void rq_com_stop_stream_after_boot(void)
//  * \brief Send a jam signal to stop the sensor stream
//  *        and retry until the stream stops
//  */
// static void rq_com_stop_stream_after_boot(void)
// {
// 	static INT_32 counter = 0;
	
// 	while(rq_com_stream_detected)
// 	{
// 		counter++;

// 		if(counter == 1)
// 		{
// 			rq_com_send_jam_signal();
// 		}
// 		else
// 		{
// 			rq_com_listen_stream();

// 			if(rq_com_stream_detected)
// 			{
// 				counter = 0;
// 			}
// 			else
// 			{
// 				counter = 0;
// 			}
// 		}
// 	}
// }

// /**
//  * \fn INT_8 rq_com_start_stream(void)
//  * \brief Starts the sensor streaming mode
//  * \return 0 if the stream started, -1 otherwise
//  */
// INT_8 rq_com_start_stream(void)
// {
// 	UINT_16 data[1] = {0x0200}; //0x0200 selects the stream output
// 	UINT_8 retries = 0;
// 	INT_8 rc = rq_com_send_fc_16(REGISTER_SELECT_OUTPUT, 2, data);

// 	if (rc == -1)
// 	{
// 		while(retries < 5)
// 		{
// 			rq_com_listen_stream();

// 			if(rq_com_stream_detected)
// 			{
// 				return 0;
// 			}

// 			Sleep(50);
// 			retries = retries + 1;
// 		}

// 		return -1;
// 	}

// 	return 0;
// }

// /**
//  * \brief Sends a read request
//  * \param base Address of the first register to read
//  * \param n Number of bytes to read
//  * \param data table into which data will be written
//  */
// static INT_8 rq_com_send_fc_03(UINT_16 base, UINT_16 n, UINT_16 * const data)
// {
// 	UINT_8 bytes_read = 0;
// 	INT_32 i = 0;
// 	INT_32 cpt = 0;
// 	UINT_8 data_request[n]; 
// 	UINT_16 retries = 0;

// 	//precondition, null pointer
// 	if (data == NULL)
// 	{
// 		return -1;
// 	}

// 	//Send the read request
// 	rq_com_send_fc_03_request(base,n);

// 	//Read registers
// 	while (retries < 100 && bytes_read == 0)
// 	{
// 		Sleep(4);
// 		bytes_read = rq_com_wait_for_fc_03_echo(data_request);
// 		retries++;
// 	}

// 	if (bytes_read <= 0)
// 	{
// 		return -1;
// 	}

// 	if ((n%2) == 0){
// 		for (i = 0; i < n/2; i++ )
// 		{
// 			data[i] = (data_request[cpt++] * 256);
// 			data[i] = data[i] + data_request[cpt++];
// 		}
// 	}
// 	else{
// 		for (i = 0; i <= n/2; i++ )
// 		{
// 			data[i] = (data_request[cpt++] * 256);
// 			data[i] = data[i] + data_request[cpt++];
// 		}
// 	}

// 	return 0;
// }

// /**
//  * \fn static INT_8 rq_com_send_fc_16(INT_32 base, INT_32 n, UINT_16 * data)
//  * \brief Sends a write request to a number of registers
//  * \param base Address of the first register to write to
//  * \param n Number of registers to write
//  * \param data buffer that contains data to write
//  */
// static INT_8 rq_com_send_fc_16(INT_32 base, INT_32 n, UINT_16 const * const data)
// {
// 	INT_8 valid_answer = 0;
// 	UINT_8 data_request[n];
// 	UINT_16 retries = 0;
// 	UINT_32 i;

// 	//precondition, null pointer
// 	if (data == NULL)
// 	{
// 		return -1;
// 	}

// 	for (i = 0; i < n; i++ )
// 	{
// 		if(i % 2 == 0)
// 		{
// 			data_request[i] = (data[(i/2)] >> 8);
// 		}
// 		else
// 		{
// 			data_request[i] = (data[(i/2)] & 0xFF);
// 		}
// 	}

// 	rq_com_send_fc_16_request(base, n, data_request);

// 	while (retries < 100 && valid_answer == 0)
// 	{
// 		Sleep(10);
// 		valid_answer = rq_com_wait_for_fc_16_echo();
// 		retries++;
// 	}

// 	if(valid_answer == 1)
// 	{
// 		return 0;
// 	}

// 	return -1;
// }

// //
// //Public functions

// /**
//  * \fn void rq_sensor_com_read_info_high_lvl(void)
//  * \brief Reads and stores high level information from
//  *        the sensor. These include the firmware version,
//  *        the serial number and the production year.
//  */
// void rq_sensor_com_read_info_high_lvl(void)
// {
// 	UINT_16 registers[4] = {0};//table de registre
// 	UINT_64 serial_number = 0;
// 	INT_32 result = 0;

// 	//Firmware Version
// 	result = rq_com_send_fc_03(REGISTER_FIRMWARE_VERSION, 6, registers);
// 	if (result != -1)
// 	{
// 		sprintf(rq_com_str_sensor_firmware_version, "%c%c%c-%hhu.%hhu.%hhu",
// 				registers[0] >> 8, registers[0] & 0xFF, registers[1] >> 8,
// 				registers[1] & 0xFF, registers[2] >> 8, registers[2] & 0xFF);
// 	}

// 	//Production Year
// 	result = rq_com_send_fc_03(REGISTER_PRODUCTION_YEAR, 2, registers);
// 	if (result != -1)
// 	{
// 		sprintf(rq_com_str_sensor_production_year, "%u", registers[0]);
// 	}

// 	//Serial Number
// 	result = rq_com_send_fc_03(REGISTER_SERIAL_NUMBER, 8, registers);
// 	if (result != -1)
// 	{
// 		serial_number = (UINT_64) ((registers[3] >> 8) * 256 * 256 * 256
// 				+ (registers[3] & 0xFF) * 256 * 256 + (registers[2] >> 8) * 256
// 				+ (registers[2] & 0xFF));

// 		if (serial_number == 0)
// 		{
// 			sprintf(rq_com_str_sensor_serial_number, "UNKNOWN");
// 		}
// 		else
// 		{
// 			sprintf(rq_com_str_sensor_serial_number, "%c%c%c-%.4lu", registers[0] >> 8,
// 					registers[0] & 0xFF, registers[1] >> 8, serial_number);
// 		}
// 	}
// }

// /**
//  * \fn static INT_32 rq_com_read_port(UINT_8 * buf, UINT_32 buf_len)
//  * \brief Reads incomming data on the com port
//  * \param buf, contains the incomming data
//  * \param buf_len maximum number of data to read
//  * \return The number of character read
//  */
// static INT_32 rq_com_read_port(UINT_8 * const buf, UINT_32 buf_len)
// {
// #ifdef __unix__ //For Unix
// 	return read(fd_connexion, buf, buf_len);
// #elif defined(_WIN32)||defined(WIN32) //For Windows
// 	DWORD myBytesRead = 0;
// 	ReadFile(hSerial,buf,buf_len,&myBytesRead,NULL);
// 	return myBytesRead;
// #endif
// }

// /**
//  * \fn static INT_32 rq_com_write_port(UINT_8 * buf, UINT_32 buf_len)
//  * \brief Writes on the com port
//  * \param buf data to write
//  * \param buf_len numer of bytes to write
//  * \return The number of characters written or -1 in case of an error
//  */
// static INT_32 rq_com_write_port(UINT_8 const * const buf, UINT_32 buf_len)
// {
// 	//precondition
// 	if (buf == NULL)
// 	{
// 		return -1;
// 	}

// #ifdef __unix__ //For Unix
//     return write(fd_connexion, buf, buf_len);
// #elif defined(_WIN32)||defined(WIN32) //For Windows
//     DWORD n_bytes = 0;
//     return (WriteFile(hSerial, buf, buf_len, &n_bytes, NULL)) ? n_bytes: -1;
// #endif
// }

// /**
//  * \fn static UINT_16 rq_com_compute_crc(UINT_8 * adr, INT_32 length )
//  * \param adr, Address of the first byte 
//  * \param length Length of the buffer on which the crc is computed
//  * \return Value of the crc
//  */
// static UINT_16 rq_com_compute_crc(UINT_8 const * adr, INT_32 length )
// {
//         UINT_16 CRC_calc = 0xFFFF;
//         INT_32 j=0;
//         INT_32 k=0;

// 	//precondition, null pointer
// 	if (adr == NULL)
// 	{
// 		return 0;
// 	}

// 	//Tant qu'il reste des bytes dans le message
// 	while (j < length)
// 	{
// 		//Si c'est le premier byte
// 		if (j==0)
// 		{
// 			CRC_calc ^= *adr & 0xFF;
// 		}
// 		//Sinon on utilisera un XOR sur le word
// 		else
// 		{
// 			CRC_calc ^= *adr;
// 		}

// 		k=0;
		
// 		//Tant que le byte n'est pas complété
// 		while (k < 8)
// 		{
// 			//Si le dernier bit est un 1
// 			if (CRC_calc & 0x0001)
// 			{
// 				CRC_calc =  (CRC_calc >> 1)^ 0xA001;	//Shift de 1 bit vers la droite et XOR avec le facteur polynomial
// 			}
// 	    	else
// 			{
// 				CRC_calc >>= 1;			//Shift de 1 bit vers la droite
// 			}
	
//     		k++;
// 	    }
	
// 		//Incrémente l'adresse et le compteur d'adresse
// 		adr++;
// 		j++;
// 	}
	
// 	return CRC_calc;
// }

// /**
//  * \fn static void rq_com_send_fc_03_request(UINT_16 base, UINT_16 n)
//  * \brief Compute and send the fc03 request on the com port
//  * \param base Address of the first register to read
//  * \param n Number of bytes to read
//  */
// static void rq_com_send_fc_03_request(UINT_16 base, UINT_16 n)
// {
// 	static UINT_8 buf[MP_BUFF_SIZE];
// 	INT_32 length = 0;
// 	UINT_8 reg[2];
// 	UINT_8 words[2];
// 	UINT_16 CRC;
	
// 	//Si le nombre de registre est impair
// 	if(n % 2 != 0)
// 	{
// 		n += 1;
// 	}
	
// 	//Scinder en LSB et MSB
// 	reg[0]   = (UINT_8)(base >> 8); //MSB to the left
// 	reg[1]   = (UINT_8)(base & 0x00FF); //LSB to the right
// 	words[0] = (UINT_8)((n/2) >> 8); //MSB to the left
// 	words[1] = (UINT_8)((n/2) & 0x00FF); //LSB to the right
	
// 	//Build the request
// 	buf[length++] = 9; //slave address
// 	buf[length++] = 3;
// 	buf[length++] = reg[0];
// 	buf[length++] = reg[1];
// 	buf[length++] = words[0];
// 	buf[length++] = words[1];
	
// 	//CRC computation
// 	CRC = rq_com_compute_crc(buf, length);
	
// 	//Append the crc
// 	buf[length++] = (UINT_8)(CRC & 0x00FF);
// 	buf[length++] = (UINT_8)(CRC >> 8);
	
// 	//Send the request
// 	rq_com_write_port(buf, length);
// }

// /**
//  * \fn static INT_32 rq_com_wait_for_fc_03_echo(UINT_8 data[])
//  * \brief Reads the reply to a fc03 request
//  * \param base Address of the buffer that will store the reply
//  * \return The number of character read
//  */
// static INT_32 rq_com_wait_for_fc_03_echo(UINT_8 * const data)
// {
// 	static UINT_8 buf[MP_BUFF_SIZE];
// 	static INT_32 length = 0;
// 	static INT_32 old_length = 0;
// 	static INT_32 counter_no_new_data = 0;
// 	UINT_8 n = 0;
// 	UINT_16 CRC = 0;
// 	INT_32 j = 0;
// 	INT_32 ret = rq_com_read_port(&buf[length], MP_BUFF_SIZE - length);
	
// 	if(ret != -1)
// 	{
// 		length = length + ret;
// 	}

// 	//If there is no new data, the buffer is cleared
// 	if(length == old_length)
// 	{
// 		if(counter_no_new_data < 5)
// 		{
// 			counter_no_new_data++;
// 		}
// 		else
// 		{
// 			length = 0;
// 		}
// 	}
// 	else
// 	{
// 		counter_no_new_data = 0;
// 	}
	
// 	old_length = length;
	
// 	if(length > 0)
// 	{
// 		//If there is not enough data, return
// 		if(length <= 5)
// 		{
// 			return 0;
// 		}
// 		else
// 		{
// 			if(buf[1] == 3) //3 indicates the response to a fc03 query
// 			{
// 				n = buf[2];
// 				if(length < 5 + n)
// 				{
// 					return 0;
// 				}
// 			}
// 			else //unknown fc code
// 			{
// 				length = 0;
// 				return 0;
// 			}
// 		}
// 		CRC = rq_com_compute_crc(buf, length - 2);
		
// 		//Verifies the crc and the slave ID
// 		if(CRC != (UINT_16)((buf[length - 1] * 256) + (buf[length - 2])))
// 		{
// 			//On clear le buffer
// 			buf[0] = 0;
// 			length = 0;
// 			return 0;
// 		}
// 		else
// 		{
// 			n = buf[2];
			
// 			//Writes the bytes to the return buffer
// 			for(j = 0; j < n; j++)
// 			{
// 				data[j] = buf[j + 3];
// 			}
			
// 			//Clears the buffer
// 			buf[0] = 0;
// 			length = 0;
// 			return n;
// 		}
// 	}
	
// 	return 0;
// }


// /**
//  * \fn void modbus_send_fc_16_request(INT_32 base, INT_32 n, UINT_8 * data)
//  * \brief Sends a fc16 write request
//  * \param base Address of the first register to write to
//  * \param n Number of bytes to write
//  */
// static void rq_com_send_fc_16_request(INT_32 base, INT_32 n, UINT_8 const * const data)
// {
// 	static UINT_8 buf[MP_BUFF_SIZE];
// 	INT_32 length = 0;

// 	//Byte of the query
// 	UINT_8 reg[2];
// 	UINT_8 words[2];
// 	UINT_16 CRC;
// 	INT_32 n2 = 0;
// 	INT_32 i = 0;

// 	if (data == NULL)
// 	{
// 		return;
// 	}
	
// 	//Manage if the number of bytes to write is odd or even
// 	if(n %2 != 0)
// 	{
// 		n2 = n+1;
// 	}
// 	else
// 	{
// 		n2 = n;
// 	}
	
// 	//Split the address and the number of bytes between MSB ans LSB
// 	reg[0]   = (UINT_8)(base >> 8);       //MSB to the left
// 	reg[1]   = (UINT_8)(base & 0x00FF);   //LSB to the right
// 	words[0] = (UINT_8)((n2/2) >> 8);     //MSB to the left
// 	words[1] = (UINT_8)((n2/2) & 0x00FF); //LSB to the right
	
	
// 	//Build the query
// 	buf[length++] = 9; //slave address
// 	buf[length++] = 16;
// 	buf[length++] = reg[0];
// 	buf[length++] = reg[1];
// 	buf[length++] = words[0];
// 	buf[length++] = words[1];
// 	buf[length++] = n2;
	
// 	//Copy data to the send buffer
// 	for(i = 0; i < n; i++)
// 	{
// 		buf[length++] = data[i];
// 	}
	
// 	if(n != n2)
// 	{
// 		buf[length++] = 0;
// 	}
	
// 	CRC = rq_com_compute_crc(buf, length);
	
// 	//Append the crc to the query
// 	buf[length++] = (UINT_8)(CRC & 0x00FF);
// 	buf[length++] = (UINT_8)(CRC >> 8);
	
// 	//Send the query
// 	rq_com_write_port(buf, length);
// }

// /**
//  * \fn static INT_32 rq_com_wait_for_fc_16_echo(void)
//  * \brief Reads the response to a fc16 write query
//  * \return 0 for an invalid response, 1 otherwise
//  */
// static INT_32 rq_com_wait_for_fc_16_echo(void)
// {
// 	static UINT_8 buf[MP_BUFF_SIZE];
// 	static INT_32 length = 0;
// 	static INT_32 old_length = 0;
// 	static INT_32 counter_no_new_data = 0;
// 	UINT_16 CRC = 0;

// 	length = length + rq_com_read_port(&buf[length], MP_BUFF_SIZE - length);

// 	//Clear the buffer if no new data
// 	if(length == old_length)
// 	{
// 		if(counter_no_new_data < 5)
// 		{
// 			counter_no_new_data++;
// 		}
// 		else
// 		{
// 			length = 0;
// 		}
// 	}
// 	else
// 	{
// 		counter_no_new_data = 0;
// 	}

// 	old_length = length;

// 	if(length > 0)
// 	{
// 		//If not enough data, return
// 		if(length < 8)
// 		{
// 			return 0;
// 		}
// 		else
// 		{
// 			//if it's a reply to a fc16 query then proceed
// 			if(buf[1] == 16)
// 			{
// 					length = 8;

// 					CRC = rq_com_compute_crc(buf, length - 2);

// 					//Check the crc an the slave ID
// 					if(CRC != (UINT_16)((buf[length - 1] * 256) + (buf[length - 2])))
// 					{
// 						//Clear the buffer
// 						length = 0;

// 						return 0;
// 					}
// 					else
// 					{
// 						//Clear the buffer
// 						length = 0;

// 						return 1;
// 					}

// 			}
// 			else //Clear the buffer
// 			{
// 					length = 0;
// 					return 0;
// 			}
// 		}

// 	}

// 	return 0;
// }


// /**
//  * \brief Retrieves the sensor serial number
//  * \param serial_number address of the return buffer
//  */
// void rq_com_get_str_serial_number(INT_8 * serial_number)
// {
// 	strcpy(serial_number, rq_com_str_sensor_serial_number);
// }

// /**
//  * \brief Retrieves the sensor firmware version
//  * \param firmware_version Address of the return buffer
//  */
// void rq_com_get_str_firmware_version(INT_8 * firmware_version)
// {
// 	strcpy(firmware_version, rq_com_str_sensor_firmware_version);
// }

// /**
//  * \brief Retrieves the sensor firmware version
//  * \param production_year Address of the return buffer
//  */
// void rq_com_get_str_production_year(INT_8 * production_year)
// {
// 	strcpy(production_year,rq_com_str_sensor_production_year);
// }

// /**
//  * \brief retrieves the sensor firmware version
//  * \param production_year Address of the return buffer
//  */
// bool rq_com_get_stream_detected()
// {
// 	return rq_com_stream_detected;
// }

// /**
//  * \brief returns if the stream message is valid
//  */
// bool rq_com_get_valid_stream()
// {
// 	return rq_com_valid_stream;
// }

// /**
//  * \brief Return an effort component
//  * \param i Index of the component. 0 to 2 for Fx, Fy and Fz.
//  *          3 to 5 for Mx, My and Mz.
//  */
// float rq_com_get_received_data(UINT_8 i)
// {
// 	if(i >= 0 && i <= 5)
// 	{
// 		return rq_com_received_data[i] - rq_com_received_data_offset[i];
// 	}

// 	return 0.0;
// }

// /**
//  * \brief Returns true if a new valid stream message has been decoded and
//  *        is available.
//  * \details When this function is called, the variable that indicates if a 
//             new message is available is set to false even if the message
//             hasn't beed read.
//  */
// bool rq_com_got_new_message()
// {
// 	bool tmp = rq_com_new_message;
// 	rq_com_new_message = false;
// 	return tmp;
// }

// /**
//  * \brief Set the "zero sensor" flag to 1. When the next stream message will
//           be decoded, the effort values will be stored as offsets a
//           substracted from the next values
//  */
// void rq_com_do_zero_force_flag()
// {
// 	rq_com_zero_force_flag = 1;
// }

// /**
//  * \brief close the serial port. 
//  * \warning Only valid under Windows.
//  */
// void stop_connection()
// {
// #if defined(_WIN32)||defined(WIN32) //For Windows
// 	CloseHandle(hSerial);
// 	hSerial = INVALID_HANDLE_VALUE;
// #endif
// }


// /**
//  * \author Pierre-Olivier Proulx
//  * \brief try to discover a com port by polling each serial port
//  * \return 1 if a device is found, 0 otherwise
//  * \details For linux, we user the command fuser to determine if the
//  *          tty is used by another process. If so, we do not scan it.
//  */
// #ifdef __unix__ //For Unix
// static UINT_8 rq_com_identify_device(INT_8 const * const d_name)
// {
// 	FILE * fuser_output;
// 	INT_8 fuser_cmd[40] = {0};
// 	INT_8 fuser_ret[30] = {0};
// 	INT_8 dirParent[20] = {0};
// 	INT_8 port_com[15] = {0};

// 	strcpy(dirParent, "/dev/");
// 	strcat(dirParent, d_name);
// 	strcpy(port_com, dirParent);

// 	/* si un process utilise le tty, on le le scan pas. */
// 	snprintf (fuser_cmd, 40, "fuser %s 2> /dev/null", port_com); 
// 	fuser_output = popen (fuser_cmd, "r");

// 	if (fuser_output != NULL)
// 	{
// 		fgets (fuser_ret, 30, fuser_output);
// 		fclose(fuser_output);
// 	}

// 	if (strlen (fuser_ret) != 0)
// 	{
// 		return 0;
// 	}

//         fprintf(stderr, "fuser ok\n");

//         fprintf(stderr, "attempting to open %s\n", port_com);
// 	fd_connexion = open(port_com, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);

// 	//The serial port is open
// 	if(fd_connexion != -1)
// 	{
//                 fprintf(stderr, "fd_connexion != 1\n");
// 		if(set_com_attribs(fd_connexion,B19200) != -1)
// 		{
// 			//Try connecting to the sensor
// 			if (rq_com_tentative_connexion() == 1)
// 			{
// 				return 1;
// 			}
// 		}
		
// 		//The device is identified, close the connection
// 		close(fd_connexion);
//                 fprintf(stderr, "close connection\n");
// 	} else {
//                 perror("uhhhhhh");
//                 fprintf(stderr, "fd_connexion == 1\n");
//         }
// 	return 0;
// }
// #endif


















/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file rq_sensor_com.c
 *  \date June 18, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */

//
//Includes

//Platform specific
#ifdef __unix__ /*For Unix*/
#define _BSD_SOURCE
#include <termios.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#define Sleep(x) (usleep (x*1000))
#elif defined(_WIN32)||defined(WIN32) /*For Windows*/
#include <windows.h>
#endif

#include <string.h>
#include <errno.h>

//application specific
#include "robotiq_ft/rq_sensor_com.h"

// Definitions
#define REGISTER_SELECT_OUTPUT 410
#define REGISTER_SERIAL_NUMBER 510
#define REGISTER_PRODUCTION_YEAR 514
#define REGISTER_FIRMWARE_VERSION 500
#define RQ_COM_MAX_STR_LENGTH 20
#define RQ_COM_JAM_SIGNAL_CHAR      0xff
#define RQ_COM_JAM_SIGNAL_LENGTH    50
#define RQ_COM_TIMER_FOR_STREAM_DETECTION_MAX_VALUE 20 //20 * 4ms =  80ms sans bytes avant de dire qu'on n'a pas le stream
#define RQ_COM_TIMER_FOR_VALID_STREAM_MAX_VALUE     40 //40 * 4ms = 160ms sans messages valide afin de dire que la communication fonctionne mal (16 mauvais messages)


// Private variables
static float rq_com_received_data[6] = {0.0};
static float rq_com_received_data_offset[6] = {0.0};

static UINT_16 rq_com_computed_crc = 0;
static UINT_16 rq_com_crc = 0;

static INT_8 rq_com_str_sensor_serial_number[RQ_COM_MAX_STR_LENGTH];
static INT_8 rq_com_str_sensor_production_year[RQ_COM_MAX_STR_LENGTH];
static INT_8 rq_com_str_sensor_firmware_version[RQ_COM_MAX_STR_LENGTH];

static UINT_32 rq_com_msg_received = 0;

static UINT_8 rq_com_rcv_buff[MP_BUFF_SIZE];
static UINT_8 rq_com_snd_buff[MP_BUFF_SIZE];
static UINT_8 rq_com_rcv_buff2[MP_BUFF_SIZE];
static INT_32 rq_com_rcv_len;
static INT_32 rq_com_rcv_len2 = 0;

static INT_32 rq_com_zero_force_flag = 0;
static INT_32 rq_state_sensor_watchdog = 0;

//variables related to the communication status
static bool rq_com_stream_detected = false;
static bool rq_com_valid_stream = false;
static bool rq_com_new_message = false;
static INT_32  rq_com_timer_for_stream_detection = 0;
static INT_32  rq_com_timer_for_valid_stream = 0;

///
//Private functions declaration
static INT_8 rq_com_tentative_connexion(void);
static void rq_com_send_jam_signal(void);
static void rq_com_stop_stream_after_boot(void);

static INT_32 rq_com_read_port(UINT_8 * const buf, UINT_32 buf_len);
static INT_32 rq_com_write_port(UINT_8 const * const buf, UINT_32 buf_len);

//Modbus functions
static UINT_16 rq_com_compute_crc(UINT_8 const * adr, INT_32 length );
static void rq_com_send_fc_03_request(UINT_16 base, UINT_16 n);
static void rq_com_send_fc_16_request(INT_32 base, INT_32 n, UINT_8 const * const data);
static INT_32 rq_com_wait_for_fc_03_echo(UINT_8 * const data);
static INT_32 rq_com_wait_for_fc_16_echo(void);
static INT_8 rq_com_send_fc_03(UINT_16 base, UINT_16 n, UINT_16 * const data);
static INT_8 rq_com_send_fc_16(INT_32 base, INT_32 n, UINT_16 const * const data);

#ifdef __unix__ //For Unix
static UINT_8 rq_com_identify_device(INT_8 const * const d_name);
#endif //For Unix

#ifdef __unix__ //For Unix
static INT_32 fd_connexion = -1;
static INT_8 set_com_attribs (INT_32 fd, speed_t speed);
#elif defined(_WIN32)||defined(WIN32) //For Windows
HANDLE hSerial;
#endif

//
//Function definitions

/**
 * \fn void rq_sensor_com(void)
 * \brief Discovers and initialize the communication with the sensor
 * \details The functions loops  through all the serial com ports 
 *          and polls them to discover the sensor
 */
INT_8 rq_sensor_com()
{
#ifdef __unix__ //For Unix
	UINT_8 device_found = 0;
	DIR *dir = NULL;
	struct dirent *entrydirectory = NULL;

	//Close a previously opened connection to a device
	close(fd_connexion);
	if ((dir = opendir("/sys/class/tty/")) == NULL)
	{
		return -1;
	}

	//Loops through the files in the /sys/class/tty/ directory
	while ((entrydirectory = readdir(dir)) != NULL && device_found == 0)
	{
		//Look for a serial device
		if (strstr(entrydirectory->d_name, "ttyS") || 
		    strstr(entrydirectory->d_name, "ttyUSB"))
		{
			device_found = rq_com_identify_device(entrydirectory->d_name);
		}
	}

	closedir(dir);

	if (device_found == 0)
	{
		return -1;
	}
#elif defined(_WIN32)||defined(WIN32) //For Windows
	DCB dcb;
	INT_32 i;
	INT_8 port[13];
	for(i = 0;i < 256; i++){
		sprintf(port,"\\\\.\\COM%d",i);
		hSerial = CreateFileA(port, GENERIC_READ | GENERIC_WRITE,
				0,NULL,OPEN_EXISTING,0,NULL);
		if(hSerial != INVALID_HANDLE_VALUE){
			dcb.DCBlength = sizeof(DCB);
			if (!GetCommState(hSerial, &dcb)){
				CloseHandle(hSerial);
				hSerial = INVALID_HANDLE_VALUE;
				continue;//Permet de recommencer la boucle
			}
			dcb.BaudRate = CBR_19200;
			dcb.ByteSize = 8;
			dcb.StopBits = ONESTOPBIT;
			dcb.Parity = NOPARITY;
			dcb.fParity = FALSE;

			/* No software handshaking */
			dcb.fTXContinueOnXoff = TRUE;
			dcb.fOutX = FALSE;
			dcb.fInX = FALSE;
			//dcb.fNull = FALSE;

			/* Binary mode (it's the only supported on Windows anyway) */
			dcb.fBinary = TRUE;

			/* Don't want errors to be blocking */
			dcb.fAbortOnError = FALSE;

			/* Setup port */
			if(!SetCommState(hSerial, &dcb)){
				CloseHandle(hSerial);
				continue;//Permet de recommencer la boucle
			}
			COMMTIMEOUTS timeouts={0};
			timeouts.ReadIntervalTimeout=0;
			timeouts.ReadTotalTimeoutConstant=1;
			timeouts.ReadTotalTimeoutMultiplier=0;
			timeouts.WriteTotalTimeoutConstant=1;
			timeouts.WriteTotalTimeoutMultiplier=0;
			if(!SetCommTimeouts(hSerial, &timeouts)){
				CloseHandle(hSerial);
				hSerial = INVALID_HANDLE_VALUE;
				continue;//Permet de recommencer la boucle
			}
			if (rq_com_tentative_connexion() == 1){
				return 0;
			}
			CloseHandle(hSerial);
		}
	}
	return -1;
#else
#endif
	return 0;
}

/**
 * \fn static INT_8 rq_com_tentative_connexion()
 * \brief Tries connecting to the sensor
 * \returns 1 if the connection attempt succeeds, -1 otherwise
 */
static INT_8 rq_com_tentative_connexion()
{
	INT_32 rc = 0;
	UINT_16 firmware_version [1];
	UINT_8 retries = 0;

	while(retries < 5 && rq_com_stream_detected == false)
	{
		rq_com_listen_stream();
		retries++;
	}

	rq_com_listen_stream();
	if(rq_com_stream_detected)
	{
		rq_com_stop_stream_after_boot();
	}

	//Give some time to the sensor to switch to modbus
	Sleep(100);

	//If the device returns an F as the first character of the fw version,
	//we consider its a sensor
	rc = rq_com_send_fc_03(REGISTER_FIRMWARE_VERSION, 2, firmware_version);
	if (rc != -1)
	{
		if (firmware_version[0] >> 8 == 'F')
		{
			return 1;
		}
	}

	return -1;
}

/**
 * \fn static INT_8 set_com_attribs()
 * \brief Sets the com port parameters to match those of the sensor
 * \param fd, file descriptor that points to the serial port
 * \param speed, baudrate
 * \return 0 in case of a success, -1 otherwise
 */
#ifdef __unix__ //For Unix
static INT_8 set_com_attribs (INT_32 fd, speed_t speed)
{
	struct termios tty;
	memset (&tty, 0, sizeof (struct termios));

	if (tcgetattr (fd, &tty) != 0)
	{
		return -1;
	}

	cfsetospeed (&tty, speed);
	cfsetispeed (&tty, speed);

	tty.c_cflag |= (CLOCAL | CREAD);
	tty.c_cflag &= ~CSIZE;
	tty.c_cflag |= CS8;
	tty.c_cflag &= ~CSTOPB;
	tty.c_cflag &= ~PARENB;
	tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
	tty.c_iflag &= ~INPCK;
	tty.c_iflag &= ~(IXON | IXOFF | IXANY);
	tty.c_cc[VMIN]  = 0;			// read doesn't block
	tty.c_cc[VTIME] = 1;

	if (tcsetattr (fd, TCSANOW, &tty) != 0)
	{
		printf("error %d from tcsetattr", errno);
		return -1;
	}

	return 0;
}
#endif

/**
 * \fn void rq_com_listen_stream()
 * \brief Listens and decode a valid stream input
 */
void rq_com_listen_stream(void)
{
	static INT_32 last_byte = 0;
	static INT_32 new_message = 0;
	INT_32 i = 0;
	INT_32 j = 0;    

	//Capture and store the current value of the sensor and use it to
	//zero subsequent sensor values
	if(rq_com_zero_force_flag == 1)
	{
		rq_com_zero_force_flag = 0;

		for(i = 0; i < 6; i++)
		{
			rq_com_received_data_offset[i] = rq_com_received_data[i];
		}

	}

	Sleep(10);

	//Increment communication state counters
	if(rq_com_timer_for_stream_detection++ > RQ_COM_TIMER_FOR_STREAM_DETECTION_MAX_VALUE)
	{
		rq_com_timer_for_stream_detection = RQ_COM_TIMER_FOR_STREAM_DETECTION_MAX_VALUE;
		rq_com_stream_detected = false;
	}

	if(rq_com_timer_for_valid_stream++ > RQ_COM_TIMER_FOR_VALID_STREAM_MAX_VALUE)
	{
		rq_com_timer_for_valid_stream = RQ_COM_TIMER_FOR_VALID_STREAM_MAX_VALUE;
		rq_com_valid_stream = false;
	}

	last_byte = 0;
	new_message = 0;

	//Data reception
	rq_com_rcv_len = rq_com_read_port(rq_com_rcv_buff, MP_BUFF_SIZE);

	//If at least a byte is received, we consider the sensor to stream
	if(rq_com_rcv_len > 0)
	{
		rq_com_stream_detected = true;
		rq_com_timer_for_stream_detection = 0;
	}

	//Copie les données au bout du buffer 2
	for(i = 0; i < rq_com_rcv_len; i++)
	{
		//If the buffer overflows, set the index to the beginning
		if(rq_com_rcv_len2 == MP_BUFF_SIZE)
		{
			//Next bytes will overwrite the begining of the buffer
			rq_com_rcv_len2 = 0;
			break;
		}

		rq_com_rcv_buff2[rq_com_rcv_len2++] = rq_com_rcv_buff[i];
	}

	//empty the buffers
	memset( rq_com_rcv_buff, 0, sizeof(rq_com_rcv_buff));
	memset( rq_com_snd_buff, 0, sizeof(rq_com_snd_buff));

	//If there is enough characters,...
	if(rq_com_rcv_len2 >= 16 && rq_com_rcv_len >= 1) 
	{        
		//Search for a valid stream message in the buffer
		for(i = rq_com_rcv_len2 - 16; i >= 0; i--)
		{
			//Header
			if(rq_com_rcv_buff2[i] == 0x20 && rq_com_rcv_buff2[i+1] == 0x4E && new_message == 0)
			{

				last_byte = i - 1;

				rq_com_computed_crc = rq_com_compute_crc(rq_com_rcv_buff2 + i * sizeof(*rq_com_rcv_buff2), 14);

				rq_com_crc 			= (rq_com_rcv_buff2[i+14] + rq_com_rcv_buff2[i+15] * 256);

				rq_com_msg_received++;


				//The crc is valid.. the message can be used
				if(rq_com_computed_crc == rq_com_crc)
				{
					last_byte = i + 15; //will erase the message

					//convert the efforts to floating point numbers
					for(j = 0; j < 3; j++)
					{
						rq_com_received_data[j] = ((float)((INT_16)((UINT_8)rq_com_rcv_buff2[i+2+2*j] + ((INT_16)(UINT_8)rq_com_rcv_buff2[i+3+2*j]) * 256))) / 100 ;
					}

					for(j = 3; j < 6; j++)
					{
						rq_com_received_data[j] = ((float)((INT_16)((UINT_8)rq_com_rcv_buff2[i+2+2*j] + ((INT_16)(UINT_8)rq_com_rcv_buff2[i+3+2*j]) * 256))) / 1000;
					}

					//Signal the stream as valid
					rq_com_valid_stream = true;
					rq_com_new_message = true;
					rq_com_timer_for_valid_stream = 0;

					new_message = 1;
					rq_state_sensor_watchdog = 1;

				}
				else
				{
					last_byte = i + 15;
					new_message = 1;
				}
			}
		}

		if(last_byte > 0)
		{
			//On shift le buffer 2 afin de ne garder que ce qui dépasse le dernier caractère du dernier message complet
			for(i = 0; i < (rq_com_rcv_len2 - last_byte - 1); i++)
			{
				rq_com_rcv_buff2[i] = rq_com_rcv_buff2[last_byte + 1 + i];
			}
			rq_com_rcv_len2 = rq_com_rcv_len2 - last_byte - 1;
		}
	}
}

/**
 * \fn static void rq_com_send_jam_signal(void)
 * \brief Send a signal that interrupts the streaming
 */
static void rq_com_send_jam_signal(void)
{
	//Build the jam signal
	memset(rq_com_snd_buff, RQ_COM_JAM_SIGNAL_CHAR, RQ_COM_JAM_SIGNAL_LENGTH);

	//Send the jam signal
	rq_com_write_port(rq_com_snd_buff,RQ_COM_JAM_SIGNAL_LENGTH);
}


/**
 * \fn static void rq_com_stop_stream_after_boot(void)
 * \brief Send a jam signal to stop the sensor stream
 *        and retry until the stream stops
 */
static void rq_com_stop_stream_after_boot(void)
{
	static INT_32 counter = 0;
	
	while(rq_com_stream_detected)
	{
		counter++;

		if(counter == 1)
		{
			rq_com_send_jam_signal();
		}
		else
		{
			rq_com_listen_stream();

			if(rq_com_stream_detected)
			{
				counter = 0;
			}
			else
			{
				counter = 0;
			}
		}
	}
}

/**
 * \fn INT_8 rq_com_start_stream(void)
 * \brief Starts the sensor streaming mode
 * \return 0 if the stream started, -1 otherwise
 */
INT_8 rq_com_start_stream(void)
{
	UINT_16 data[1] = {0x0200}; //0x0200 selects the stream output
	UINT_8 retries = 0;
	INT_8 rc = rq_com_send_fc_16(REGISTER_SELECT_OUTPUT, 2, data);

	if (rc == -1)
	{
		while(retries < 5)
		{
			rq_com_listen_stream();

			if(rq_com_stream_detected)
			{
				return 0;
			}

			Sleep(50);
			retries = retries + 1;
		}

		return -1;
	}

	return 0;
}

/**
 * \brief Sends a read request
 * \param base Address of the first register to read
 * \param n Number of bytes to read
 * \param data table into which data will be written
 */
static INT_8 rq_com_send_fc_03(UINT_16 base, UINT_16 n, UINT_16 * const data)
{
	UINT_8 bytes_read = 0;
	INT_32 i = 0;
	INT_32 cpt = 0;
	UINT_8 data_request[n]; 
	UINT_16 retries = 0;

	//precondition, null pointer
	if (data == NULL)
	{
		return -1;
	}

	//Send the read request
	rq_com_send_fc_03_request(base,n);

	//Read registers
	while (retries < 100 && bytes_read == 0)
	{
		Sleep(4);
		bytes_read = rq_com_wait_for_fc_03_echo(data_request);
		retries++;
	}

	if (bytes_read <= 0)
	{
		return -1;
	}

	if ((n%2) == 0){
		for (i = 0; i < n/2; i++ )
		{
			data[i] = (data_request[cpt++] * 256);
			data[i] = data[i] + data_request[cpt++];
		}
	}
	else{
		for (i = 0; i <= n/2; i++ )
		{
			data[i] = (data_request[cpt++] * 256);
			data[i] = data[i] + data_request[cpt++];
		}
	}

	return 0;
}

/**
 * \fn static INT_8 rq_com_send_fc_16(INT_32 base, INT_32 n, UINT_16 * data)
 * \brief Sends a write request to a number of registers
 * \param base Address of the first register to write to
 * \param n Number of registers to write
 * \param data buffer that contains data to write
 */
static INT_8 rq_com_send_fc_16(INT_32 base, INT_32 n, UINT_16 const * const data)
{
	INT_8 valid_answer = 0;
	UINT_8 data_request[n];
	UINT_16 retries = 0;
	UINT_32 i;

	//precondition, null pointer
	if (data == NULL)
	{
		return -1;
	}

	for (i = 0; i < n; i++ )
	{
		if(i % 2 == 0)
		{
			data_request[i] = (data[(i/2)] >> 8);
		}
		else
		{
			data_request[i] = (data[(i/2)] & 0xFF);
		}
	}

	rq_com_send_fc_16_request(base, n, data_request);

	while (retries < 100 && valid_answer == 0)
	{
		Sleep(10);
		valid_answer = rq_com_wait_for_fc_16_echo();
		retries++;
	}

	if(valid_answer == 1)
	{
		return 0;
	}

	return -1;
}

//
//Public functions

/**
 * \fn void rq_sensor_com_read_info_high_lvl(void)
 * \brief Reads and stores high level information from
 *        the sensor. These include the firmware version,
 *        the serial number and the production year.
 */
void rq_sensor_com_read_info_high_lvl(void)
{
	UINT_16 registers[4] = {0};//table de registre
	UINT_64 serial_number = 0;
	INT_32 result = 0;

	//Firmware Version
	result = rq_com_send_fc_03(REGISTER_FIRMWARE_VERSION, 6, registers);
	if (result != -1)
	{
		sprintf(rq_com_str_sensor_firmware_version, "%c%c%c-%hhu.%hhu.%hhu",
				registers[0] >> 8, registers[0] & 0xFF, registers[1] >> 8,
				registers[1] & 0xFF, registers[2] >> 8, registers[2] & 0xFF);
	}

	//Production Year
	result = rq_com_send_fc_03(REGISTER_PRODUCTION_YEAR, 2, registers);
	if (result != -1)
	{
		sprintf(rq_com_str_sensor_production_year, "%u", registers[0]);
	}

	//Serial Number
	result = rq_com_send_fc_03(REGISTER_SERIAL_NUMBER, 8, registers);
	if (result != -1)
	{
		serial_number = (UINT_64) ((registers[3] >> 8) * 256 * 256 * 256
				+ (registers[3] & 0xFF) * 256 * 256 + (registers[2] >> 8) * 256
				+ (registers[2] & 0xFF));

		if (serial_number == 0)
		{
			sprintf(rq_com_str_sensor_serial_number, "UNKNOWN");
		}
		else
		{
			sprintf(rq_com_str_sensor_serial_number, "%c%c%c-%.4lu", registers[0] >> 8,
					registers[0] & 0xFF, registers[1] >> 8, serial_number);
		}
	}
}

/**
 * \fn static INT_32 rq_com_read_port(UINT_8 * buf, UINT_32 buf_len)
 * \brief Reads incomming data on the com port
 * \param buf, contains the incomming data
 * \param buf_len maximum number of data to read
 * \return The number of character read
 */
static INT_32 rq_com_read_port(UINT_8 * const buf, UINT_32 buf_len)
{
#ifdef __unix__ //For Unix
	return read(fd_connexion, buf, buf_len);
#elif defined(_WIN32)||defined(WIN32) //For Windows
	DWORD myBytesRead = 0;
	ReadFile(hSerial,buf,buf_len,&myBytesRead,NULL);
	return myBytesRead;
#endif
}

/**
 * \fn static INT_32 rq_com_write_port(UINT_8 * buf, UINT_32 buf_len)
 * \brief Writes on the com port
 * \param buf data to write
 * \param buf_len numer of bytes to write
 * \return The number of characters written or -1 in case of an error
 */
static INT_32 rq_com_write_port(UINT_8 const * const buf, UINT_32 buf_len)
{
	//precondition
	if (buf == NULL)
	{
		return -1;
	}

#ifdef __unix__ //For Unix
    return write(fd_connexion, buf, buf_len);
#elif defined(_WIN32)||defined(WIN32) //For Windows
    DWORD n_bytes = 0;
    return (WriteFile(hSerial, buf, buf_len, &n_bytes, NULL)) ? n_bytes: -1;
#endif
}

/**
 * \fn static UINT_16 rq_com_compute_crc(UINT_8 * adr, INT_32 length )
 * \param adr, Address of the first byte 
 * \param length Length of the buffer on which the crc is computed
 * \return Value of the crc
 */
static UINT_16 rq_com_compute_crc(UINT_8 const * adr, INT_32 length )
{
        UINT_16 CRC_calc = 0xFFFF;
        INT_32 j=0;
        INT_32 k=0;

	//precondition, null pointer
	if (adr == NULL)
	{
		return 0;
	}

	//Tant qu'il reste des bytes dans le message
	while (j < length)
	{
		//Si c'est le premier byte
		if (j==0)
		{
			CRC_calc ^= *adr & 0xFF;
		}
		//Sinon on utilisera un XOR sur le word
		else
		{
			CRC_calc ^= *adr;
		}

		k=0;
		
		//Tant que le byte n'est pas complété
		while (k < 8)
		{
			//Si le dernier bit est un 1
			if (CRC_calc & 0x0001)
			{
				CRC_calc =  (CRC_calc >> 1)^ 0xA001;	//Shift de 1 bit vers la droite et XOR avec le facteur polynomial
			}
	    	else
			{
				CRC_calc >>= 1;			//Shift de 1 bit vers la droite
			}
	
    		k++;
	    }
	
		//Incrémente l'adresse et le compteur d'adresse
		adr++;
		j++;
	}
	
	return CRC_calc;
}

/**
 * \fn static void rq_com_send_fc_03_request(UINT_16 base, UINT_16 n)
 * \brief Compute and send the fc03 request on the com port
 * \param base Address of the first register to read
 * \param n Number of bytes to read
 */
static void rq_com_send_fc_03_request(UINT_16 base, UINT_16 n)
{
	static UINT_8 buf[MP_BUFF_SIZE];
	INT_32 length = 0;
	UINT_8 reg[2];
	UINT_8 words[2];
	UINT_16 CRC;
	
	//Si le nombre de registre est impair
	if(n % 2 != 0)
	{
		n += 1;
	}
	
	//Scinder en LSB et MSB
	reg[0]   = (UINT_8)(base >> 8); //MSB to the left
	reg[1]   = (UINT_8)(base & 0x00FF); //LSB to the right
	words[0] = (UINT_8)((n/2) >> 8); //MSB to the left
	words[1] = (UINT_8)((n/2) & 0x00FF); //LSB to the right
	
	//Build the request
	buf[length++] = 9; //slave address
	buf[length++] = 3;
	buf[length++] = reg[0];
	buf[length++] = reg[1];
	buf[length++] = words[0];
	buf[length++] = words[1];
	
	//CRC computation
	CRC = rq_com_compute_crc(buf, length);
	
	//Append the crc
	buf[length++] = (UINT_8)(CRC & 0x00FF);
	buf[length++] = (UINT_8)(CRC >> 8);
	
	//Send the request
	rq_com_write_port(buf, length);
}

/**
 * \fn static INT_32 rq_com_wait_for_fc_03_echo(UINT_8 data[])
 * \brief Reads the reply to a fc03 request
 * \param base Address of the buffer that will store the reply
 * \return The number of character read
 */
static INT_32 rq_com_wait_for_fc_03_echo(UINT_8 * const data)
{
	static UINT_8 buf[MP_BUFF_SIZE];
	static INT_32 length = 0;
	static INT_32 old_length = 0;
	static INT_32 counter_no_new_data = 0;
	UINT_8 n = 0;
	UINT_16 CRC = 0;
	INT_32 j = 0;
	INT_32 ret = rq_com_read_port(&buf[length], MP_BUFF_SIZE - length);
	
	if(ret != -1)
	{
		length = length + ret;
	}

	//If there is no new data, the buffer is cleared
	if(length == old_length)
	{
		if(counter_no_new_data < 5)
		{
			counter_no_new_data++;
		}
		else
		{
			length = 0;
		}
	}
	else
	{
		counter_no_new_data = 0;
	}
	
	old_length = length;
	
	if(length > 0)
	{
		//If there is not enough data, return
		if(length <= 5)
		{
			return 0;
		}
		else
		{
			if(buf[1] == 3) //3 indicates the response to a fc03 query
			{
				n = buf[2];
				if(length < 5 + n)
				{
					return 0;
				}
			}
			else //unknown fc code
			{
				length = 0;
				return 0;
			}
		}
		CRC = rq_com_compute_crc(buf, length - 2);
		
		//Verifies the crc and the slave ID
		if(CRC != (UINT_16)((buf[length - 1] * 256) + (buf[length - 2])))
		{
			//On clear le buffer
			buf[0] = 0;
			length = 0;
			return 0;
		}
		else
		{
			n = buf[2];
			
			//Writes the bytes to the return buffer
			for(j = 0; j < n; j++)
			{
				data[j] = buf[j + 3];
			}
			
			//Clears the buffer
			buf[0] = 0;
			length = 0;
			return n;
		}
	}
	
	return 0;
}


/**
 * \fn void modbus_send_fc_16_request(INT_32 base, INT_32 n, UINT_8 * data)
 * \brief Sends a fc16 write request
 * \param base Address of the first register to write to
 * \param n Number of bytes to write
 */
static void rq_com_send_fc_16_request(INT_32 base, INT_32 n, UINT_8 const * const data)
{
	static UINT_8 buf[MP_BUFF_SIZE];
	INT_32 length = 0;

	//Byte of the query
	UINT_8 reg[2];
	UINT_8 words[2];
	UINT_16 CRC;
	INT_32 n2 = 0;
	INT_32 i = 0;

	if (data == NULL)
	{
		return;
	}
	
	//Manage if the number of bytes to write is odd or even
	if(n %2 != 0)
	{
		n2 = n+1;
	}
	else
	{
		n2 = n;
	}
	
	//Split the address and the number of bytes between MSB ans LSB
	reg[0]   = (UINT_8)(base >> 8);       //MSB to the left
	reg[1]   = (UINT_8)(base & 0x00FF);   //LSB to the right
	words[0] = (UINT_8)((n2/2) >> 8);     //MSB to the left
	words[1] = (UINT_8)((n2/2) & 0x00FF); //LSB to the right
	
	
	//Build the query
	buf[length++] = 9; //slave address
	buf[length++] = 16;
	buf[length++] = reg[0];
	buf[length++] = reg[1];
	buf[length++] = words[0];
	buf[length++] = words[1];
	buf[length++] = n2;
	
	//Copy data to the send buffer
	for(i = 0; i < n; i++)
	{
		buf[length++] = data[i];
	}
	
	if(n != n2)
	{
		buf[length++] = 0;
	}
	
	CRC = rq_com_compute_crc(buf, length);
	
	//Append the crc to the query
	buf[length++] = (UINT_8)(CRC & 0x00FF);
	buf[length++] = (UINT_8)(CRC >> 8);
	
	//Send the query
	rq_com_write_port(buf, length);
}

/**
 * \fn static INT_32 rq_com_wait_for_fc_16_echo(void)
 * \brief Reads the response to a fc16 write query
 * \return 0 for an invalid response, 1 otherwise
 */
static INT_32 rq_com_wait_for_fc_16_echo(void)
{
	static UINT_8 buf[MP_BUFF_SIZE];
	static INT_32 length = 0;
	static INT_32 old_length = 0;
	static INT_32 counter_no_new_data = 0;
	UINT_16 CRC = 0;

	length = length + rq_com_read_port(&buf[length], MP_BUFF_SIZE - length);

	//Clear the buffer if no new data
	if(length == old_length)
	{
		if(counter_no_new_data < 5)
		{
			counter_no_new_data++;
		}
		else
		{
			length = 0;
		}
	}
	else
	{
		counter_no_new_data = 0;
	}

	old_length = length;

	if(length > 0)
	{
		//If not enough data, return
		if(length < 8)
		{
			return 0;
		}
		else
		{
			//if it's a reply to a fc16 query then proceed
			if(buf[1] == 16)
			{
					length = 8;

					CRC = rq_com_compute_crc(buf, length - 2);

					//Check the crc an the slave ID
					if(CRC != (UINT_16)((buf[length - 1] * 256) + (buf[length - 2])))
					{
						//Clear the buffer
						length = 0;

						return 0;
					}
					else
					{
						//Clear the buffer
						length = 0;

						return 1;
					}

			}
			else //Clear the buffer
			{
					length = 0;
					return 0;
			}
		}

	}

	return 0;
}


/**
 * \brief Retrieves the sensor serial number
 * \param serial_number address of the return buffer
 */
void rq_com_get_str_serial_number(INT_8 * serial_number)
{
	strcpy(serial_number, rq_com_str_sensor_serial_number);
}

/**
 * \brief Retrieves the sensor firmware version
 * \param firmware_version Address of the return buffer
 */
void rq_com_get_str_firmware_version(INT_8 * firmware_version)
{
	strcpy(firmware_version, rq_com_str_sensor_firmware_version);
}

/**
 * \brief Retrieves the sensor firmware version
 * \param production_year Address of the return buffer
 */
void rq_com_get_str_production_year(INT_8 * production_year)
{
	strcpy(production_year,rq_com_str_sensor_production_year);
}

/**
 * \brief retrieves the sensor firmware version
 * \param production_year Address of the return buffer
 */
bool rq_com_get_stream_detected()
{
	return rq_com_stream_detected;
}

/**
 * \brief returns if the stream message is valid
 */
bool rq_com_get_valid_stream()
{
	return rq_com_valid_stream;
}

/**
 * \brief Return an effort component
 * \param i Index of the component. 0 to 2 for Fx, Fy and Fz.
 *          3 to 5 for Mx, My and Mz.
 */
float rq_com_get_received_data(UINT_8 i)
{
	if(i >= 0 && i <= 5)
	{
		return rq_com_received_data[i] - rq_com_received_data_offset[i];
	}

	return 0.0;
}

/**
 * \brief Returns true if a new valid stream message has been decoded and
 *        is available.
 * \details When this function is called, the variable that indicates if a 
            new message is available is set to false even if the message
            hasn't beed read.
 */
bool rq_com_got_new_message()
{
	bool tmp = rq_com_new_message;
	rq_com_new_message = false;
	return tmp;
}

/**
 * \brief Set the "zero sensor" flag to 1. When the next stream message will
          be decoded, the effort values will be stored as offsets a
          substracted from the next values
 */
void rq_com_do_zero_force_flag()
{
	rq_com_zero_force_flag = 1;
}

/**
 * \brief close the serial port. 
 * \warning Only valid under Windows.
 */
void stop_connection()
{
#if defined(_WIN32)||defined(WIN32) //For Windows
	CloseHandle(hSerial);
	hSerial = INVALID_HANDLE_VALUE;
#endif
}


/**
 * \author Pierre-Olivier Proulx
 * \brief try to discover a com port by polling each serial port
 * \return 1 if a device is found, 0 otherwise
 * \details For linux, we user the command fuser to determine if the
 *          tty is used by another process. If so, we do not scan it.
 */
#ifdef __unix__ //For Unix
static UINT_8 rq_com_identify_device(INT_8 const * const d_name)
{
	FILE * fuser_output;
	INT_8 fuser_cmd[40] = {0};
	INT_8 fuser_ret[30] = {0};
	INT_8 dirParent[20] = {0};
	INT_8 port_com[15] = {0};

	strcpy(dirParent, "/dev/");
	strcat(dirParent, d_name);
	strcpy(port_com, dirParent);

	/* si un process utilise le tty, on le le scan pas. */
	snprintf (fuser_cmd, 40, "fuser %s 2> /dev/null", port_com); 
	fuser_output = popen (fuser_cmd, "r");

	if (fuser_output != NULL)
	{
		fgets (fuser_ret, 30, fuser_output);
		fclose(fuser_output);
	}

	if (strlen (fuser_ret) != 0)
	{
		return 0;
	}

	fd_connexion = open(port_com, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);

	//The serial port is open
	if(fd_connexion != -1)
	{
		if(set_com_attribs(fd_connexion,B19200) != -1)
		{
			//Try connecting to the sensor
			if (rq_com_tentative_connexion() == 1)
			{
				return 1;
			}
		}
		
		//The device is identified, close the connection
		close(fd_connexion);
	}
	return 0;
}
#endif

rq_sensor_socket.c

/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file socket.c
 *  \date May 20, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */

#include "robotiq_ft/rq_sensor_socket.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "robotiq_ft/mutex.h"

//pour les mutex
#ifdef __unix__ //For Unix
	#include <pthread.h>
	#define MUTEX pthread_mutex_t
#elif defined(_WIN32)||defined(WIN32) //For Windows
	#include <windows.h>
	#include <process.h>
	#define MUTEX HANDLE
#endif

#define CRLF	 "\r\n"
#define PORT	 63350
#define PORT_STREAM 63351
#define MAX_CLIENTS 1
#define BUF_SIZE 512

#define CAPTEUR_STREAM 0
#define CAPTEUR_ACCESSEUR 1

static uint8_t message[BUF_SIZE];//message recu par TCP
static SOCKET s_socket = 0;//Socket du serveur
static SOCKET s_socket_stream = 0;//Socket du serveurStream
static SOCKET c_socket_acc;//Socket du client accesseur
static SOCKET c_socket_capt = 0;//Socket du client capteur
static MUTEX mtx;// Mutex
static MUTEX mtxWrite; // Mutex pour la fonction write

static int read_client(SOCKET sock, uint8_t *buffer);
static void start_socket(int iSock);

/**
 * \fn void init_connection(void)
 * \brief Fonction qui ouvre le socket serveur et du stream et attend un client stream.
 */
int init_connection() {
	while(s_socket_stream == 0){
		usleep(500000);
		start_socket(CAPTEUR_STREAM);
	}
	while(s_socket == 0){
		usleep(500000);
		start_socket(CAPTEUR_ACCESSEUR);
	}

	//Attente de connection au serveur
	SOCKADDR_IN csin;
	int sinsize = sizeof(csin);
	c_socket_capt = accept(s_socket_stream, (SOCKADDR *)&csin, &sinsize);//accept attend la connexion d'un client

	return s_socket;
}

/**
 * \fn void end_connection(int sock)
 * \brief Fonction qui ferme le socket passer en parametre.
 * \param sock, integer du socket a fermer.
 */
void end_connection(int sock) {
	closesocket(sock);
}

/**
 * \fn static int read_client(SOCKET sock, char *buffer)
 * \brief Fonction qui lis ce que le client a envoyer.
 * \param sock, SOCKET client
 * \param *buffer, adresse memoire d'un buffer de char pour le message
 * \return n, nombre de caractere dans le buffer
 */
static int read_client(SOCKET sock, uint8_t *buffer) {
	int n = 0;
	if ((n = recv(sock, buffer, BUF_SIZE - 1, 0)) < 0) {
		return 0;//signifie une erreur
	}
	else{
		MUTEX_LOCK(&mtx);
		strcpy(message,buffer);
		message[n] = 0;
		MUTEX_UNLOCK(&mtx);
		buffer[n] = 0;

		return n;
	}
}

/**
 * \fn void write_client(SOCKET sock, const char *buffer)
 * \brief Fonction qui envoie un message au client.
 * \param sock, SOCKET client
 * \param *buffer, adresse memoire d'un buffer de char pour le message a envoyer
 */
void write_client(SOCKET sock, uint8_t *buffer) {
	MUTEX_LOCK(&mtxWrite);
	int ret = send(sock, buffer, strlen(buffer), MSG_DONTWAIT);
	if(ret == -1 && errno == EAGAIN){
		ret = send(sock, buffer, strlen(buffer), MSG_DONTWAIT);
	}
	else if (ret == -1 && errno == ECONNRESET){
		SOCKADDR_IN csin;
		int sinsize = sizeof(csin);
		if(sock == c_socket_capt){
			close(c_socket_capt);
			close(s_socket_stream);
			start_socket(CAPTEUR_STREAM);
			c_socket_capt = 0;
			while(c_socket_capt == 0){
				c_socket_capt = accept(s_socket_stream, (SOCKADDR *)&csin, &sinsize);//accept attend la connexion d'un client
			}
		}
		else if(sock == c_socket_acc){
			close(c_socket_acc);
			close(s_socket);
			start_socket(CAPTEUR_ACCESSEUR);
			c_socket_acc = 0;
			while(c_socket_acc == 0){
				c_socket_acc = accept(s_socket, (SOCKADDR *)&csin, &sinsize);//accept attend la connexion d'un client
			}
		}
	}
	MUTEX_UNLOCK(&mtxWrite);
}

/**
 * \fn void *Read_socket(void *t)
 * \brief Fonction utiliser par le thread pour faire une boucle
 *     infini de lecture de message recu par le client et si client en erreur,
 *     on attend le prochain client qui se connecte et continu la boucle.
 * \param *t, paramettre bidon pour que le thread fonctionne.
 */
#ifdef __unix__ //For Unix
void *Read_socket(void *t)
#elif defined(_WIN32)||defined(WIN32) //For Windows
void __cdecl Read_socket( void *t )
#endif
{
	SOCKADDR_IN csin;
	int sinsize = sizeof(csin);
	char testConnexion[BUF_SIZE];
	c_socket_acc = accept(s_socket, (SOCKADDR *)&csin, &sinsize);
	while(1){
		if(read_client(c_socket_acc, testConnexion)  == 0){
			close(c_socket_acc);
			close(s_socket);
			start_socket(CAPTEUR_ACCESSEUR);
			//Si on perd la connexion on attend la prochaine.
			c_socket_acc = accept(s_socket, (SOCKADDR *)&csin, &sinsize);
		}
	}
}

/**
 * \fn void set_socket_message_to_null(char * chr_return)
 * \brief Fonction qui vide la variable globale message.
 */
void set_socket_message_to_null(void){
	MUTEX_LOCK(&mtx);
	message[0] = 0;
	MUTEX_UNLOCK(&mtx);
}

/**
 * \fn void socket_message(char * chr_return)
 * \brief Fonction qui retourne le message via le paramettre.
 * \param * chr_return, adresse memoire pour evoie du message via le parammetre
 * \param *buffer, adresse memoire d'un buffer de char pour le message a envoyer
 */
void socket_message(uint8_t * chr_return){
	MUTEX_LOCK(&mtx);
	strcpy(chr_return,message);
	MUTEX_UNLOCK(&mtx);
}

/**
 * \fn SOCKET get_client_sock_accessor(void)
 * \brief Fonction qui retourne socket du client presentement connecter.
 */
SOCKET get_client_sock_accessor(void){
	return c_socket_acc;
}

/**
 * \fn SOCKET get_client_sock_stream(void)
 * \brief Fonction qui retourne socket du capteur presentement connecter.
 */
SOCKET get_client_sock_stream(void){
	return c_socket_capt;
}

/**
 * \fn SOCKET get_socket_stream(void)
 * \brief Fonction qui retourne socket serveur pour le stream.
 */
SOCKET get_socket_stream(){
	return s_socket_stream;
}


static void start_socket(int iSock) {
	SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
	SOCKADDR_IN sin = { 0 };

	if (sock == INVALID_SOCKET) {
		return;
	}

	//Pour le socket des accesseur
	sin.sin_addr.s_addr = htonl(INADDR_ANY);
	if(iSock == CAPTEUR_ACCESSEUR) sin.sin_port = htons(PORT);
	if(iSock == CAPTEUR_STREAM) sin.sin_port = htons(PORT_STREAM);
	sin.sin_family = AF_INET;


	//Permet d'ouvrir les sockets sur les bons ports
	if(bind(sock,(SOCKADDR *) &sin, sizeof sin) == SOCKET_ERROR){
		return;
	}

	//Permet l'ecoute des client
	if(listen(sock, MAX_CLIENTS) == SOCKET_ERROR){
		return;
	}


	if(iSock == CAPTEUR_ACCESSEUR) s_socket = sock;
	if(iSock == CAPTEUR_STREAM) s_socket_stream = sock;
}

rq_sensor_state.c

/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file rq_sensor_state.c
 *  \date June 19, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */

//
//Includes
#include <string.h>
#include "robotiq_ft/rq_sensor_state.h"
#include "robotiq_ft/rq_sensor_com.h"

///
//Private variables
static enum rq_sensor_state_values current_state = RQ_STATE_INIT;

///
//Private functions
static INT_8 rq_state_init_com();
static void rq_state_read_info_high_lvl();
static void rq_state_start_stream();
static void rq_state_run();

//
//Function definitions

/**
 * \fn void rq_sensor_state(void)
 * \brief Manages the states of the sensor driver
 * \returns -1 if an error occurs, 0 otherwise
 */
INT_8 rq_sensor_state(void)
{
	INT_8 ret;

	switch (current_state)
	{
	case RQ_STATE_INIT:
		ret = rq_state_init_com();
		if(ret == -1)
		{
			return -1;
		}
		break;

	case RQ_STATE_READ_INFO:
		rq_state_read_info_high_lvl();
		break;

	case RQ_STATE_START_STREAM:
		rq_state_start_stream();
		break;

	case RQ_STATE_RUN:
		rq_state_run();
		break;

	default:
		printf("rq_state(): Unknown error\r\n");
		return -1;
		break;

	}
	return 0;
 }

/**
 * \fn void rq_state_init_com(void)
 * \brief Initialize communication with the sensor and set the
 *        next state to \ref RQ_STATE_READ_INFO
 */
static INT_8 rq_state_init_com()
{
	if(rq_sensor_com() == -1)
	{
		return -1;
	}

	current_state = RQ_STATE_READ_INFO;
	return 0;
}

/**
 * \fn void rq_state_read_info_high_lvl(void)
 * \brief Reads the high level information from the
 *        sensor and set the next state to 
 *        \ref RQ_STATE_START_STREAM
 */
static void rq_state_read_info_high_lvl()
{
	rq_sensor_com_read_info_high_lvl();
	current_state = RQ_STATE_START_STREAM;
}

/**
 * \fn void rq_state_start_stream(void)
 * \brief Send the command to start the streaming mode
 *        If the stream doesn't start, return to state init.
 *        Set the next state to \ref RQ_STATE_RUN
 */
static void rq_state_start_stream()
{
	if(rq_com_start_stream() == -1)
	{
#if defined(_WIN32)||defined(WIN32) //For Windows
		stop_connection();
#endif
		current_state = RQ_STATE_INIT;
	}
	current_state = RQ_STATE_RUN;
}

/**
 * \fn void rq_state_run()
 * \brief Capture and read the stream from the sensor.
 *        If the stream is not valid, return to state
 *        \ref RQ_STATE_INIT
 */
static void rq_state_run()
{
	rq_com_listen_stream();

	if(rq_com_get_valid_stream() == false)
	{
#if defined(_WIN32)||defined(WIN32) //For Windows
		stop_connection();
#endif
		current_state = RQ_STATE_INIT;
	}
}

/**
 * \fn float rq_state_get_received_data()
 * \brief Returns the force/torque component
 * \param i, index of the component
 * \pre i has a value between 0 and 5
 */
float rq_state_get_received_data(UINT_8 i)
{
	if(i >= 0 && i <= 5)
	{
		return rq_com_get_received_data(i);
	}
	else
	{
		return 0.0;
	}
}

/**
 * \fn int rq_state_get_command(char* name, char *value)
 * \brief Gets the value of high level information from the sensor
 * \param name the name of the information field. The value can be 
 *                either "SNU", "FMW" or "PYE"
 * \param value A string
 * \return 0 in case of succes, -1 otherwise
 */
void rq_state_get_command(INT_8 const * const name, INT_8 * const  value)
{
	//precondition, null pointer
	if( value == NULL || name == NULL)
	{
		return;
	}

	if(strstr(name, "SNU"))
	{
		rq_com_get_str_serial_number( value);
	}
	else if(strstr(name, "FWV"))
	{
		rq_com_get_str_firmware_version( value);
	}
	else if(strstr(name, "PYE"))
	{
		rq_com_get_str_production_year( value);
	}
}

/**
 * \fn enum rq_sensor_state_values rq_sensor_get_current_state()
 * \brief Returns this module's state machine current state
 */
enum rq_sensor_state_values rq_sensor_get_current_state()
{
	return current_state;
}

/**
 * \brief Returns true if a stream message is available
 */
bool rq_state_got_new_message()
{
	return rq_com_got_new_message();
}

/**
 * \brief Command a zero on the sensor
 */
void rq_set_zero()
{
	rq_com_do_zero_force_flag();
}

rq_thread.c 

/* Software License Agreement (BSD License)
*
* Copyright (c) 2014, Robotiq, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Robotiq, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2014, Robotiq, Inc
*/

/*
 *  \file rq_thread.c
 *  \date July 3, 2014
 *  \author Jonathan Savoie <jonathan.savoie@robotic.com>
 *  \maintener Nicolas Lauzier <nicolas@robotiq.com>
 */

#include "robotiq_ft/rq_thread.h"

#ifdef __unix__ //For Unix

#include <pthread.h>
#include <signal.h>

static pthread_t threads[5];
static int libre[5] = {0,0,0,0,0};

int create_Thread(void *(*start_rtn)(void *))
{
	int i = 0;
	long t = 0;

	for(i = 0;i < 5; i++){
		if (libre[i] == 0){
			libre[i] = 1;
			break;
		}
	}
	int rc = pthread_create(&threads[i], NULL, start_rtn, (void *)t);
	if (rc != 0){
		//printf("ERROR; return code from pthread_create() is %d\n", rc);
		return -1;
	}
	return i;
}

int close_Thread(int iId){
	if(iId >= 0 || iId < 5){
		pthread_kill(threads[iId], SIGKILL);
		libre[iId] = 0;
		threads[iId] = 0;
		return 0;
	}
	else{
		return 1;
	}
}

void wait_thread(int iId){
	if(iId >= 0 || iId < 5){
		pthread_join(threads[iId], NULL);
		libre[iId] = 0;
		threads[iId] = 0;
	}
}

#elif defined(_WIN32)||defined(WIN32) //For Windows

#include <process.h>
#include <windows.h>

HANDLE pID[5];
int libre[5] = {0,0,0,0,0};

//int create_Thread(int iId,unsigned (__stdcall *start_address)( void * ))
int create_Thread(void( __cdecl *start_address )( void * ))
{
	int i;
	for(i = 0;i < 5; i++){
		if (libre[i] == 0){
			libre[i] = 1;
			break;
		}
	}
	pID[i] = (HANDLE)_beginthread(start_address,0,NULL);
	if(pID[i] == NULL){
		return -1;
	}
	return i;
}

int close_Thread(int iId){
	if(iId >= 0 || iId < 5){
		CloseHandle(pID[iId]);
		libre[iId] == 0;
		pID[iId] = NULL;
	}
}


void wait_thread(int iID){
	if(iID >= 0 || iID < 5){
		WaitForSingleObject(pID[iID], INFINITE);
	}
}

#endif

7.Ctrl+Shift+B编译项目

8.连接力矩传感器

将力矩传感器USB连接电脑,给力矩传感器供电。可参考教程Robotiq F/T 300S力矩传感器教程

9. 启动roscore

roscore

10.发布话题消息

重新打开一个终端,启动launch文件,发布话题消息,会发布力矩传感器采集的六维力和力矩信息。ROS通信可参考视频教程ROS通信bilibili和官方文档教程ROS课程文档

source ./devel/setup.bash
roslaunch robotiq_ft my_robotiq_ft.launch

11.接收话题消息

重新打开一个终端,启动robotiq_sub文件,接收话题消息

source ./devel/setup.bash
rosrun robotiq_ft robotiq_sub

如果通信不成功,先用官方的给的Linux文件先试一遍力矩传感器传输数据是否可行

标签:数据通信,INT,void,UINT,static,力矩,ROS,com,rq
From: https://blog.csdn.net/bulletstart/article/details/144527685

相关文章

  • 电脑开机或打开程序提示缺少Microsoft.Windows.Storage.Core.dll文件问题
    在大部分情况下出现我们运行或安装软件,游戏出现提示丢失某些DLL文件或OCX文件的原因可能是原始安装包文件不完整造成,原因可能是某些系统防护软件将重要的DLL文件识别为可疑,阻止并放入了隔离单里,还有一些常见的DLL文件缺少是因为系统没有安装齐全的微软运行库,还有部分情况是因为......
  • ROS 中仿真 UR 机械臂
    本文参考:UR5机械臂+ROSnoetic+Ubuntu20.04+moveit实物和仿真驱动_little蔡的博客-CSDN博客ROS中仿真UR机械臂 仿真环境:本文使用的Ubantu版本:Ubuntu20.04ros版本:ros-noetic-desktop-full,安装此版本ros无需再安装moveit运动规划库创建工作空:创建工作空间进入工作空间......
  • CTF随题思路—Misc第十八届全国大学生信息安全竞赛(铁人三项)zeroshell_1
    用wireshark打开文件,先过滤HTTP发现该数据流的左下角有base64编码 将其复制解码后得到flag ......
  • Roslyn 是什么?
    Roslyn是什么?Roslyn是.NET平台的开源编译器平台,支持C#和VisualBasic(VB)两种编程语言。它不仅是一个传统的编译器,还提供了丰富的API,供开发者对代码进行分析、生成、重构等操作。其全名为".NETCompilerPlatform"。Roslyn的功能编译功能:将源代码(C#或VB)编译......
  • Microsoft 分布式事务处理协调器(Distributed Transaction Coordinator, MSDTC) 是一个
    Microsoft分布式事务处理协调器(DistributedTransactionCoordinator,MSDTC)是一个Windows操作系统中的重要服务,用于管理和协调分布式事务。它的主要作用是确保在分布式系统中涉及多个资源(如数据库、消息队列等)的事务保持一致性,确保这些资源能够在一个事务内正确地提交或回滚......
  • MoUSO Core Worker Process 是一个与 Windows 更新相关的进程,属于 Windows 操作系统中
    MoUSOCoreWorkerProcess是一个与Windows更新相关的进程,属于Windows操作系统中的一种系统进程。它的主要作用是与Microsoft更新服务、Windows更新、以及其他相关的自动化更新任务相关联。MoUSOCoreWorkerProcess进程的功能更新任务的协调:MoUSOCoreWorkerPro......
  • D455 Ros
     Part_1:安装librealsenseSDK2.0注册密钥sudoapt-keyadv--keyserverkeyserver.ubuntu.com--recv-keyF6E65AC044F831AC80A06380C8B3A55A6F3EFCDEsudoapt-keyadv--keyserverhkp://keyserver.ubuntu.com:80--recv-keyF6E65AC044F831AC80A06380C8B3A55A6F3EFCDE......
  • 达梦DM.Microsoft.EntityFreameworkCore查询报错invalid cast from DateTime to DateT
    1.问题达梦dotnetefcore的驱动DM.Microsoft.EntityFreameworkCore。如果实体中存在DateTimeOffset类型字段时,查询报错:invalidcastfromDateTimetoDateTimeOffset。Invalidcastfrom'System.DateTime'to'System.DateTimeOffset'System.Convert.DefaultToType(Sy......
  • sql server 2008 r2 展开时报错:参数名:viewInfo ( Microsoft SqlServer Management S
    HR服务器的数据库报了一个不常见的错误,记录下来分享给大伙,如果遇到同样的问题,希望可以得到解决。服务器环境:windowsserver2008(64Bit)数据库版本:SQLserver2008R2错误提示:值不能为空。参数名:viewInfo(Microsoft.SqlServer.Management.SqlStudio.Expl;如下图:  在路径:C:\Us......
  • 【ROS机器人入门】ROS的安装和更新,学不会头提给你
    打开官网www.ros.org,或者直接登录http://wiki.ros.org/noetic/Installation/Ubuntu进行所有操作前,先更新终端输入:sudoapt-getupdate终端输入:sudoapt-getupgrade 1.1ConfigureyourUbunturepositories 这一步配置ubuntu的软件仓库,一般在不熟悉的时候不动1......