diff --git a/serial/CMakeLists.txt b/serial/CMakeLists.txt new file mode 100644 index 0000000..8cde274 --- /dev/null +++ b/serial/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 2.4.6) +include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake) + +# Set the build type. Options are: +# Coverage : w/ debug symbols, w/o optimization, w/ code-coverage +# Debug : w/ debug symbols, w/o optimization +# Release : w/o debug symbols, w/ optimization +# RelWithDebInfo : w/ debug symbols, w/ optimization +# MinSizeRel : w/o debug symbols, w/ optimization, stripped binaries +#set(ROS_BUILD_TYPE RelWithDebInfo) + +rosbuild_init() + +#set the default path for built executables to the "bin" directory +set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) +#set the default path for built libraries to the "lib" directory +set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) + +#uncomment if you have defined messages +#rosbuild_genmsg() +#uncomment if you have defined services +#rosbuild_gensrv() + +#common commands for building c++ executables and libraries +rosbuild_add_library(${PROJECT_NAME} src/serial.cpp) +#target_link_libraries(${PROJECT_NAME} another_library) +rosbuild_add_boost_directories() +rosbuild_link_boost(${PROJECT_NAME} system filesystem thread) +rosbuild_add_executable(test_serial src/test_serial.cpp) +target_link_libraries(test_serial serial) diff --git a/serial/Makefile b/serial/Makefile new file mode 100644 index 0000000..b75b928 --- /dev/null +++ b/serial/Makefile @@ -0,0 +1 @@ +include $(shell rospack find mk)/cmake.mk \ No newline at end of file diff --git a/serial/include/serial.h b/serial/include/serial.h new file mode 100644 index 0000000..4b7600e --- /dev/null +++ b/serial/include/serial.h @@ -0,0 +1,167 @@ +/** + * @file serial.h + * @author William Woodall + * @version 0.1 + * + * @section LICENSE + * + * The MIT License + * + * Copyright (c) 2011 William Woodall + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This provides a cross platform interface for interacting with Serial Ports. + */ + + +#ifndef SERIAL_H +#define SERIAL_H + +#include +#include + +#include +#include +#include +#include + +#define READ_BUFFER_SIZE 4 +#define SERIAL_BUFFER_SIZE 1024 + +class Serial { +public: + /** Constructor, creates a SerialPortBoost object without opening a port. */ + Serial(); + + /** + * Constructor, creates a SerialPortBoost object and opens the port. + * + * @param port A std::string containing the address of the serial port, + * which would be something like 'COM1' on Windows and '/dev/ttyS0' + * on Linux. + * + * @param baudrate An integer that represents the buadrate + * + * @param timeout A double that represents the time (in seconds) until a + * timeout on reads occur. Setting this to a negative number will + * silently disable the timeout on reads. + */ + Serial(std::string port, int baudrate = 9600, double timeout = -1.0); + // Serial(string port, int baudrate = 9600, int bytesize = EIGHTBITS, int parity = PARITY_NONE, int stopbits = STOPBITS_ONE, double timeout = -1.0, bool xonxoff = false, bool rtscts = false, double writeTimeout = -1.0, bool dsrdtr = false, double interCharTimeout = -1.0); + + /** Destructor */ + ~Serial(); + + /** Opens the serial port as long as the portname is set and the port isn't alreay open. */ + void open(); + + /** Closes the serial port and terminates threads. */ + void close(); + + /** Read size bytes from the serial port. + * If a timeout is set it may return less characters than requested. With no timeout + * it will block until the requested number of bytes have been read. + * + * @param buffer A char[] of length >= the size parameter to hold incoming data. + * + * @param size An integer defining how many bytes to be read. + * + * @return An integer representing the number of bytes read. + */ + int read(char* buffer, int size = 1); + + /** Read size bytes from the serial port. + * If a timeout is set it may return less characters than requested. With no timeout + * it will block until the requested number of bytes have been read. + * + * @param size An integer defining how many bytes to be read. + * + * @return A std::string containing the data read. + */ + std::string read(int size=1); + + /** Write length bytes from buffer to the serial port. + * + * @param data A char[] with data to be written to the serial port. + * + * @param length An integer representing the number of bytes to be written. + * + * @return An integer representing the number of bytes written. + */ + int write(char data[], int length); + + /** Write a string to the serial port. + * + * @param data A std::string to be written to the serial port. (must be null terminated) + * + * @return An integer representing the number of bytes written to the serial port. + */ + int write(std::string data); + + /** Checks the number of bytes waiting in the buffer. + * + * @return An integer representing the number of bytes in the serial buffer. + */ + int inWaiting(); + + /** Flushes the write buffer, blocks untill all data has been written. */ + void flush(); + + /** Sets the logic level of the RTS line. + * + * @param level The logic level to set the RTS to. Defaults to true. + */ + void setRTS(bool level = true); + + /** Sets the logic level of the DTR line. + * + * @param level The logic level to set the DTR to. Defaults to true. + */ + void setDTR(bool level = true); + + /** Gets the status of the CTS line. + * + * @return A boolean value that represents the current logic level of the CTS line. + */ + bool getCTS(); + + /** Gets the status of the DSR line. + * + * @return A boolean value that represents the current logic level of the DSR line. + */ + bool getDSR(); +private: + boost::asio::io_service io_service; + boost::asio::serial_port *serial_port; + + boost::thread * io_service_thread; + + char read_buffer[READ_BUFFER_SIZE]; + + + + std::string port; + int baudrate; + double timeout; +}; + +#endif \ No newline at end of file diff --git a/serial/mainpage.dox b/serial/mainpage.dox new file mode 100644 index 0000000..81ab75a --- /dev/null +++ b/serial/mainpage.dox @@ -0,0 +1,26 @@ +/** +\mainpage +\htmlinclude manifest.html + +\b boostserial is ... + + + + +\section codeapi Code API + + + + +*/ diff --git a/serial/manifest.xml b/serial/manifest.xml new file mode 100644 index 0000000..73ba409 --- /dev/null +++ b/serial/manifest.xml @@ -0,0 +1,15 @@ + + + + serial + + + William Woodall + BSD + + http://ros.org/wiki/serial + + + + + diff --git a/serial/src/serial.cpp b/serial/src/serial.cpp new file mode 100644 index 0000000..e9df07f --- /dev/null +++ b/serial/src/serial.cpp @@ -0,0 +1,95 @@ +#include "serial.h" + +Serial::Serial() { + ; +} + +Serial::Serial(std::string port, int baudrate, double timeout) { + this->port = port; + this->baudrate = baudrate; + this->timeout = timeout; + this->open(); +} + +Serial::~Serial() { + ; +} + +void Serial::open() { + this->serial_port = new boost::asio::serial_port(this->io_service, this->port); + + if(not serial_port->is_open()) { + std::cerr << "[AX2550] Failed to open serial port: " << this->port << std::endl; + return; + } + + try { + this->serial_port->set_option(boost::asio::serial_port_base::baud_rate(this->baudrate)); + // this->serial_port->set_option( + // boost::asio::serial_port_base::flow_control( + // boost::asio::serial_port_base::flow_control::none)); + // this->serial_port->set_option( + // boost::asio::serial_port_base::parity( + // boost::asio::serial_port_base::parity::even)); + // this->serial_port->set_option( + // boost::asio::serial_port_base::stop_bits( + // boost::asio::serial_port_base::stop_bits::one)); + // this->serial_port->set_option(boost::asio::serial_port_base::character_size(7)); + } catch(std::exception &e) { + std::cerr << "[AX2550] Error opening serial port: " << e.what() << std::endl; + try { + if(this->serial_port->is_open()) + this->serial_port->close(); + } catch(std::exception &e) { + std::cerr << "[AX2550] Error closing serial port: " << e.what() << std::endl; + } + this->serial_port = NULL; + } +} + +void Serial::close() { + ; +} + +int Serial::read(char* buffer, int size) { + return this->serial_port->read_some(boost::asio::buffer(buffer, size)); +} + +std::string Serial::read(int size) { + char serial_buffer[size]; + int number_read = this->serial_port->read_some(boost::asio::buffer(serial_buffer, size)); + serial_buffer[number_read] = NULL; + return std::string(serial_buffer); +} + +int Serial::write(char data[], int length) { + return -1; +} + +int Serial::write(std::string data) { + return -1; +} + +int Serial::inWaiting() { + return -1; +} + +void Serial::flush() { + ; +} + +void Serial::setRTS(bool level) { + ; +} + +void Serial::setDTR(bool level) { + ; +} + +bool Serial::getCTS() { + return false; +} + +bool Serial::getDSR() { + return false; +} \ No newline at end of file diff --git a/serial/src/test_serial.cpp b/serial/src/test_serial.cpp new file mode 100644 index 0000000..2df4600 --- /dev/null +++ b/serial/src/test_serial.cpp @@ -0,0 +1,50 @@ +#include "ros/ros.h" + +#include +#include + +#include "serial.h" + +Serial *serial; + +std::string toHex(std::string input) { + std::stringstream ss; + for(int i = 0; i != input.length(); i++) { + char temp[4]; + sprintf(temp, "%.2X", input[i]); + ss << " "; + if(input[i] == 0x0A) + ss << "LF"; + else if(input[i] == 0x0D) + ss << "NL"; + else + ss << input[i]; + ss << " " << std::hex << temp; + } + return ss.str(); +}; + +int main(int argc, char **argv) +{ + ros::init(argc, argv, "serial_test_node"); + + ros::NodeHandle n; + + std::string port("/dev/tty.usbserial-A900cfJA"); + + serial = new Serial(port); + + ros::Rate loop_rate(10); + + while (ros::ok()) { + std::string result = serial->read(1); + + ROS_INFO("%d,%s", result.length(), toHex(result).c_str()); + + ros::spinOnce(); + + loop_rate.sleep(); + } + + return 0; +} \ No newline at end of file