Zakladna test verzia

This commit is contained in:
2021-08-18 06:24:49 +02:00
parent 16b26bf681
commit 1efcffabe0
7 changed files with 815 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
.vscode/
CMakeFiles/
CMakeCache.txt
timeout
cmake_install.cmake
serial-port/

15
CMakeLists.txt Executable file
View File

@@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.1)
project(TEST)
## Target
set(CMAKE_CXX_STANDARD 11)
set(TEST_SRCS main.cpp TimeoutSerial.cpp)
add_executable(timeout ${TEST_SRCS})
## Link libraries
set(BOOST_LIBS date_time system)
find_package(Boost COMPONENTS ${BOOST_LIBS} REQUIRED)
target_link_libraries(timeout ${Boost_LIBRARIES})
find_package(Threads REQUIRED)
target_link_libraries(timeout ${CMAKE_THREAD_LIBS_INIT})

208
Makefile Normal file
View File

@@ -0,0 +1,208 @@
# CMAKE generated file: DO NOT EDIT!
# Generated by "Unix Makefiles" Generator, CMake Version 3.16
# Default target executed when no arguments are given to make.
default_target: all
.PHONY : default_target
# Allow only one "make -f Makefile2" at a time, but pass parallelism.
.NOTPARALLEL:
#=============================================================================
# Special targets provided by cmake.
# Disable implicit rules so canonical targets will work.
.SUFFIXES:
# Remove some rules from gmake that .SUFFIXES does not remove.
SUFFIXES =
.SUFFIXES: .hpux_make_needs_suffix_list
# Suppress display of executed commands.
$(VERBOSE).SILENT:
# A target that is always out of date.
cmake_force:
.PHONY : cmake_force
#=============================================================================
# Set environment variables for the build.
# The shell in which to execute make rules.
SHELL = /bin/sh
# The CMake executable.
CMAKE_COMMAND = /usr/bin/cmake
# The command to remove a file.
RM = /usr/bin/cmake -E remove -f
# Escaping for special characters.
EQUALS = =
# The top-level source directory on which CMake was run.
CMAKE_SOURCE_DIR = /home/jaro/serialport-downloader
# The top-level build directory on which CMake was run.
CMAKE_BINARY_DIR = /home/jaro/serialport-downloader
#=============================================================================
# Targets provided globally by CMake.
# Special rule for the target rebuild_cache
rebuild_cache:
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
/usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
.PHONY : rebuild_cache
# Special rule for the target rebuild_cache
rebuild_cache/fast: rebuild_cache
.PHONY : rebuild_cache/fast
# Special rule for the target edit_cache
edit_cache:
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..."
/usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available.
.PHONY : edit_cache
# Special rule for the target edit_cache
edit_cache/fast: edit_cache
.PHONY : edit_cache/fast
# The main all target
all: cmake_check_build_system
$(CMAKE_COMMAND) -E cmake_progress_start /home/jaro/serialport-downloader/CMakeFiles /home/jaro/serialport-downloader/CMakeFiles/progress.marks
$(MAKE) -f CMakeFiles/Makefile2 all
$(CMAKE_COMMAND) -E cmake_progress_start /home/jaro/serialport-downloader/CMakeFiles 0
.PHONY : all
# The main clean target
clean:
$(MAKE) -f CMakeFiles/Makefile2 clean
.PHONY : clean
# The main clean target
clean/fast: clean
.PHONY : clean/fast
# Prepare targets for installation.
preinstall: all
$(MAKE) -f CMakeFiles/Makefile2 preinstall
.PHONY : preinstall
# Prepare targets for installation.
preinstall/fast:
$(MAKE) -f CMakeFiles/Makefile2 preinstall
.PHONY : preinstall/fast
# clear depends
depend:
$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
.PHONY : depend
#=============================================================================
# Target rules for targets named timeout
# Build rule for target.
timeout: cmake_check_build_system
$(MAKE) -f CMakeFiles/Makefile2 timeout
.PHONY : timeout
# fast build rule for target.
timeout/fast:
$(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/build
.PHONY : timeout/fast
TimeoutSerial.o: TimeoutSerial.cpp.o
.PHONY : TimeoutSerial.o
# target to build an object file
TimeoutSerial.cpp.o:
$(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/TimeoutSerial.cpp.o
.PHONY : TimeoutSerial.cpp.o
TimeoutSerial.i: TimeoutSerial.cpp.i
.PHONY : TimeoutSerial.i
# target to preprocess a source file
TimeoutSerial.cpp.i:
$(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/TimeoutSerial.cpp.i
.PHONY : TimeoutSerial.cpp.i
TimeoutSerial.s: TimeoutSerial.cpp.s
.PHONY : TimeoutSerial.s
# target to generate assembly for a file
TimeoutSerial.cpp.s:
$(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/TimeoutSerial.cpp.s
.PHONY : TimeoutSerial.cpp.s
main.o: main.cpp.o
.PHONY : main.o
# target to build an object file
main.cpp.o:
$(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/main.cpp.o
.PHONY : main.cpp.o
main.i: main.cpp.i
.PHONY : main.i
# target to preprocess a source file
main.cpp.i:
$(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/main.cpp.i
.PHONY : main.cpp.i
main.s: main.cpp.s
.PHONY : main.s
# target to generate assembly for a file
main.cpp.s:
$(MAKE) -f CMakeFiles/timeout.dir/build.make CMakeFiles/timeout.dir/main.cpp.s
.PHONY : main.cpp.s
# Help Target
help:
@echo "The following are some of the valid targets for this Makefile:"
@echo "... all (the default if no target is provided)"
@echo "... clean"
@echo "... depend"
@echo "... rebuild_cache"
@echo "... edit_cache"
@echo "... timeout"
@echo "... TimeoutSerial.o"
@echo "... TimeoutSerial.i"
@echo "... TimeoutSerial.s"
@echo "... main.o"
@echo "... main.i"
@echo "... main.s"
.PHONY : help
#=============================================================================
# Special targets to cleanup operation of make.
# Special rule to run CMake to check the build system integrity.
# No rule that depends on this can have commands that come from listfiles
# because they might be regenerated.
cmake_check_build_system:
$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
.PHONY : cmake_check_build_system

9
Makefile.windows Normal file
View File

@@ -0,0 +1,9 @@
#Using MinGW distro from http://nuwen.net/mingw.html that contains boost precompiled
all:
g++ -O2 -std=c++11 -c main.cpp -D_WIN32_WINNT=0x0501
g++ -O2 -std=c++11 -c TimeoutSerial.cpp -D_WIN32_WINNT=0x0501
g++ -o timeout.exe main.o TimeoutSerial.o -s -lwsock32 -lws2_32 -lboost_system
clean:
del timeout.exe main.o TimeoutSerial.o

265
TimeoutSerial.cpp Executable file
View File

@@ -0,0 +1,265 @@
/*
* File: TimeoutSerial.cpp
* Author: Terraneo Federico
* Distributed under the Boost Software License, Version 1.0.
* Created on September 12, 2009, 3:47 PM
*
* v1.06: C++11 support
*
* v1.05: Fixed a bug regarding reading after a timeout (again).
*
* v1.04: Fixed bug with timeout set to zero
*
* v1.03: Fix for Mac OS X, now fully working on Mac.
*
* v1.02: Code cleanup, speed improvements, bug fixes.
*
* v1.01: Fixed a bug that caused errors while reading after a timeout.
*
* v1.00: First release.
*/
#include "TimeoutSerial.h"
#include <string>
#include <algorithm>
#include <iostream>
#include <boost/bind.hpp>
#include <sys/ioctl.h>
using namespace std;
using namespace boost;
TimeoutSerial::TimeoutSerial(): io(), port(io), timer(io),
timeout(boost::posix_time::seconds(0)) {}
TimeoutSerial::TimeoutSerial(const std::string& devname, unsigned int baud_rate,
asio::serial_port_base::parity opt_parity,
asio::serial_port_base::character_size opt_csize,
asio::serial_port_base::flow_control opt_flow,
asio::serial_port_base::stop_bits opt_stop)
: io(), port(io), timer(io), timeout(boost::posix_time::seconds(0))
{
open(devname,baud_rate,opt_parity,opt_csize,opt_flow,opt_stop);
}
void TimeoutSerial::open(const std::string& devname, unsigned int baud_rate,
asio::serial_port_base::parity opt_parity,
asio::serial_port_base::character_size opt_csize,
asio::serial_port_base::flow_control opt_flow,
asio::serial_port_base::stop_bits opt_stop)
{
if(isOpen()) close();
port.open(devname);
port.set_option(asio::serial_port_base::baud_rate(baud_rate));
port.set_option(opt_parity);
port.set_option(opt_csize);
port.set_option(opt_flow);
port.set_option(opt_stop);
}
bool TimeoutSerial::isOpen() const
{
return port.is_open();
}
void TimeoutSerial::close()
{
if(isOpen()==false) return;
port.close();
}
void TimeoutSerial::setTimeout(const boost::posix_time::time_duration& t)
{
timeout=t;
}
void TimeoutSerial::write(const char *data, size_t size)
{
asio::write(port,asio::buffer(data,size));
}
void TimeoutSerial::write(const std::vector<char>& data)
{
asio::write(port,asio::buffer(&data[0],data.size()));
}
void TimeoutSerial::writeString(const std::string& s)
{
asio::write(port,asio::buffer(s.c_str(),s.size()));
}
void TimeoutSerial::read(char *data, size_t size)
{
if(readData.size()>0)//If there is some data from a previous read
{
istream is(&readData);
size_t toRead=min(readData.size(),size);//How many bytes to read?
is.read(data,toRead);
data+=toRead;
size-=toRead;
if(size==0) return;//If read data was enough, just return
}
setupParameters=ReadSetupParameters(data,size);
performReadSetup(setupParameters);
//For this code to work, there should always be a timeout, so the
//request for no timeout is translated into a very long timeout
if(timeout!=boost::posix_time::seconds(0)) timer.expires_from_now(timeout);
else timer.expires_from_now(boost::posix_time::hours(100000));
timer.async_wait(boost::bind(&TimeoutSerial::timeoutExpired,this,
asio::placeholders::error));
result=resultInProgress;
bytesTransferred=0;
for(;;)
{
io.run_one();
switch(result)
{
case resultSuccess:
timer.cancel();
return;
case resultTimeoutExpired:
port.cancel();
throw(timeout_exception("Timeout expired"));
case resultError:
timer.cancel();
port.cancel();
throw(boost::system::system_error(boost::system::error_code(),
"Error while reading"));
//if resultInProgress remain in the loop
}
}
}
std::vector<char> TimeoutSerial::read(size_t size)
{
vector<char> result(size,'\0');//Allocate a vector with the desired size
read(&result[0],size);//Fill it with values
return result;
}
std::string TimeoutSerial::readString(size_t size)
{
string result(size,'\0');//Allocate a string with the desired size
read(&result[0],size);//Fill it with values
return result;
}
std::string TimeoutSerial::readStringUntil(const std::string& delim)
{
// Note: if readData contains some previously read data, the call to
// async_read_until (which is done in performReadSetup) correctly handles
// it. If the data is enough it will also immediately call readCompleted()
setupParameters=ReadSetupParameters(delim);
performReadSetup(setupParameters);
//For this code to work, there should always be a timeout, so the
//request for no timeout is translated into a very long timeout
if(timeout!=boost::posix_time::seconds(0)) timer.expires_from_now(timeout);
else timer.expires_from_now(boost::posix_time::hours(100000));
timer.async_wait(boost::bind(&TimeoutSerial::timeoutExpired,this,
asio::placeholders::error));
result=resultInProgress;
bytesTransferred=0;
for(;;)
{
io.run_one();
switch(result)
{
case resultSuccess:
{
timer.cancel();
bytesTransferred-=delim.size();//Don't count delim
istream is(&readData);
string result(bytesTransferred,'\0');//Alloc string
is.read(&result[0],bytesTransferred);//Fill values
is.ignore(delim.size());//Remove delimiter from stream
return result;
}
case resultTimeoutExpired:
port.cancel();
throw(timeout_exception("Timeout expired"));
case resultError:
timer.cancel();
port.cancel();
throw(boost::system::system_error(boost::system::error_code(),
"Error while reading"));
//if resultInProgress remain in the loop
}
}
}
TimeoutSerial::~TimeoutSerial() {}
void TimeoutSerial::performReadSetup(const ReadSetupParameters& param)
{
if(param.fixedSize)
{
asio::async_read(port,asio::buffer(param.data,param.size),boost::bind(
&TimeoutSerial::readCompleted,this,asio::placeholders::error,
asio::placeholders::bytes_transferred));
} else {
asio::async_read_until(port,readData,param.delim,boost::bind(
&TimeoutSerial::readCompleted,this,asio::placeholders::error,
asio::placeholders::bytes_transferred));
}
}
void TimeoutSerial::timeoutExpired(const boost::system::error_code& error)
{
if(!error && result==resultInProgress) result=resultTimeoutExpired;
}
void TimeoutSerial::readCompleted(const boost::system::error_code& error,
const size_t bytesTransferred)
{
if(!error)
{
result=resultSuccess;
this->bytesTransferred=bytesTransferred;
return;
}
//In case a asynchronous operation is cancelled due to a timeout,
//each OS seems to have its way to react.
#ifdef _WIN32
if(error.value()==995) return; //Windows spits out error 995
#elif defined(__APPLE__)
if(error.value()==45)
{
//Bug on OS X, it might be necessary to repeat the setup
//http://osdir.com/ml/lib.boost.asio.user/2008-08/msg00004.html
performReadSetup(setupParameters);
return;
}
#else //Linux
if(error.value()==125) return; //Linux outputs error 125
#endif
result=resultError;
}
void TimeoutSerial::setRTS(bool enabled)
{
int fd = port.native_handle();
int data = TIOCM_RTS;
if (!enabled)
ioctl(fd, TIOCMBIC, &data);
else
ioctl(fd, TIOCMBIS, &data);
}
void TimeoutSerial::setDTR(bool enabled)
{
int fd = port.native_handle();
int data = TIOCM_DTR;
if (!enabled)
ioctl(fd, TIOCMBIC, &data); // Clears the DTR pin
else
ioctl(fd, TIOCMBIS, &data); // Sets the DTR pin
}

236
TimeoutSerial.h Executable file
View File

@@ -0,0 +1,236 @@
/*
* File: TimeoutSerial.h
* Author: Terraneo Federico
* Distributed under the Boost Software License, Version 1.0.
*
* Created on September 12, 2009, 3:47 PM
*/
#ifndef TIMEOUTSERIAL_H
#define TIMEOUTSERIAL_H
#include <stdexcept>
#include <boost/utility.hpp>
#include <boost/asio.hpp>
/**
* Thrown if timeout occurs
*/
class timeout_exception: public std::runtime_error
{
public:
timeout_exception(const std::string& arg): runtime_error(arg) {}
};
/**
* Serial port class, with timeout on read operations.
*/
class TimeoutSerial: private boost::noncopyable
{
public:
TimeoutSerial();
/**
* Opens a serial device. By default timeout is disabled.
* \param devname serial device name, example "/dev/ttyS0" or "COM1"
* \param baud_rate serial baud rate
* \param opt_parity serial parity, default none
* \param opt_csize serial character size, default 8bit
* \param opt_flow serial flow control, default none
* \param opt_stop serial stop bits, default 1
* \throws boost::system::system_error if cannot open the
* serial device
*/
TimeoutSerial(const std::string& devname, unsigned int baud_rate,
boost::asio::serial_port_base::parity opt_parity=
boost::asio::serial_port_base::parity(
boost::asio::serial_port_base::parity::none),
boost::asio::serial_port_base::character_size opt_csize=
boost::asio::serial_port_base::character_size(8),
boost::asio::serial_port_base::flow_control opt_flow=
boost::asio::serial_port_base::flow_control(
boost::asio::serial_port_base::flow_control::none),
boost::asio::serial_port_base::stop_bits opt_stop=
boost::asio::serial_port_base::stop_bits(
boost::asio::serial_port_base::stop_bits::one));
/**
* Opens a serial device.
* \param devname serial device name, example "/dev/ttyS0" or "COM1"
* \param baud_rate serial baud rate
* \param opt_parity serial parity, default none
* \param opt_csize serial character size, default 8bit
* \param opt_flow serial flow control, default none
* \param opt_stop serial stop bits, default 1
* \throws boost::system::system_error if cannot open the
* serial device
*/
void open(const std::string& devname, unsigned int baud_rate,
boost::asio::serial_port_base::parity opt_parity=
boost::asio::serial_port_base::parity(
boost::asio::serial_port_base::parity::none),
boost::asio::serial_port_base::character_size opt_csize=
boost::asio::serial_port_base::character_size(8),
boost::asio::serial_port_base::flow_control opt_flow=
boost::asio::serial_port_base::flow_control(
boost::asio::serial_port_base::flow_control::none),
boost::asio::serial_port_base::stop_bits opt_stop=
boost::asio::serial_port_base::stop_bits(
boost::asio::serial_port_base::stop_bits::one));
/**
* \return true if serial device is open
*/
bool isOpen() const;
/**
* Close the serial device
* \throws boost::system::system_error if any error
*/
void close();
/**
* Set the timeout on read/write operations.
* To disable the timeout, call setTimeout(boost::posix_time::seconds(0));
*/
void setTimeout(const boost::posix_time::time_duration& t);
/**
* Write data
* \param data array of char to be sent through the serial device
* \param size array size
* \throws boost::system::system_error if any error
*/
void write(const char *data, size_t size);
/**
* Write data
* \param data to be sent through the serial device
* \throws boost::system::system_error if any error
*/
void write(const std::vector<char>& data);
/**
* Write a string. Can be used to send ASCII data to the serial device.
* To send binary data, use write()
* \param s string to send
* \throws boost::system::system_error if any error
*/
void writeString(const std::string& s);
/**
* Read some data, blocking
* \param data array of char to be read through the serial device
* \param size array size
* \return numbr of character actually read 0<=return<=size
* \throws boost::system::system_error if any error
* \throws timeout_exception in case of timeout
*/
void read(char *data, size_t size);
/**
* Read some data, blocking
* \param size how much data to read
* \return the receive buffer. It iempty if no data is available
* \throws boost::system::system_error if any error
* \throws timeout_exception in case of timeout
*/
std::vector<char> read(size_t size);
/**
* Read a string, blocking
* Can only be used if the user is sure that the serial device will not
* send binary data. For binary data read, use read()
* The returned string is empty if no data has arrived
* \param size hw much data to read
* \return a string with the received data.
* \throws boost::system::system_error if any error
* \throws timeout_exception in case of timeout
*/
std::string readString(size_t size);
/**
* Read a line, blocking
* Can only be used if the user is sure that the serial device will not
* send binary data. For binary data read, use read()
* The returned string is empty if the line delimiter has not yet arrived.
* \param delimiter line delimiter, default="\n"
* \return a string with the received data. The delimiter is removed from
* the string.
* \throws boost::system::system_error if any error
* \throws timeout_exception in case of timeout
*/
std::string readStringUntil(const std::string& delim="\n");
void setRTS(bool enabled);
void setDTR(bool enabled);
~TimeoutSerial();
private:
/**
* Parameters of performReadSetup.
* Just wrapper class, no encapsulation provided
*/
class ReadSetupParameters
{
public:
ReadSetupParameters(): fixedSize(false), delim(""), data(0), size(0) {}
explicit ReadSetupParameters(const std::string& delim):
fixedSize(false), delim(delim), data(0), size(0) { }
ReadSetupParameters(char *data, size_t size): fixedSize(true),
delim(""), data(data), size(size) { }
//Using default copy constructor, operator=
bool fixedSize; ///< True if need to read a fixed number of parameters
std::string delim; ///< String end delimiter (valid if fixedSize=false)
char *data; ///< Pointer to data array (valid if fixedSize=true)
size_t size; ///< Array size (valid if fixedSize=true)
};
/**
* This member function sets up a read operation, both reading a specified
* number of characters and reading until a delimiter string.
*/
void performReadSetup(const ReadSetupParameters& param);
/**
* Callack called either when the read timeout is expired or canceled.
* If called because timeout expired, sets result to resultTimeoutExpired
*/
void timeoutExpired(const boost::system::error_code& error);
/**
* Callback called either if a read complete or read error occurs
* If called because of read complete, sets result to resultSuccess
* If called because read error, sets result to resultError
*/
void readCompleted(const boost::system::error_code& error,
const size_t bytesTransferred);
/**
* Possible outcome of a read. Set by callbacks, read from main code
*/
enum ReadResult
{
resultInProgress,
resultSuccess,
resultError,
resultTimeoutExpired
};
boost::asio::io_service io; ///< Io service object
boost::asio::serial_port port; ///< Serial port object
boost::asio::deadline_timer timer; ///< Timer for timeout
boost::posix_time::time_duration timeout; ///< Read/write timeout
boost::asio::streambuf readData; ///< Holds eventual read but not consumed
enum ReadResult result; ///< Used by read with timeout
size_t bytesTransferred; ///< Used by async read callback
ReadSetupParameters setupParameters; ///< Global because used in the OSX fix
};
#endif //TIMEOUTSERIAL_H

76
main.cpp Executable file
View File

@@ -0,0 +1,76 @@
/*
* File: main.cpp
* Author: fede.tft
*
* Created on September 10, 2009, 10:50 AM
*/
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
#include "TimeoutSerial.h"
using namespace std;
using namespace boost;
typedef vector< string > split_vector_type;
int main(int argc, char* argv[])
{
string line;
float temperature = NAN;
float humidity= NAN;
float pressure = NAN;
try {
TimeoutSerial serial("/dev/ttyUSB0",115200);
serial.setTimeout(posix_time::seconds(10));
serial.setDTR(false);
serial.setRTS(false);
sleep(5);
//Text test
serial.writeString("?\r\n");
line = serial.readStringUntil("\n");
trim(line);
cout << line << endl;
serial.writeString("measure\r\n");
for (;;) {
line = serial.readStringUntil("\n");
trim(line);
if (line == "") continue;
// cout << line << endl;
split_vector_type SplitVec; // #2: Search for tokens
split( SplitVec, line, is_any_of(" "), token_compress_on ); // SplitVec == { "hello abc","ABC","aBc goodbye" }
for (vector<string>::iterator t=SplitVec.begin(); t!=SplitVec.end(); ++t) {
split_vector_type kv;
split(kv, *t, is_any_of("="), token_compress_on);
// cout << "kv[0]=" << kv[0] << endl;
if (kv[0] == "temperature") temperature = stof(kv[1]);
if (kv[0] == "humidity") humidity = stof(kv[1]);
if (kv[0] == "pressure") pressure = stof(kv[1]);
}
if (pressure > 0.0) break;
}
cout << "teplota = " << temperature << endl;
cout << "vlhkost = " << humidity << endl;
cout << "tlak = " << pressure << endl;
serial.close();
} catch(boost::system::system_error& e)
{
cout<<"Error: "<<e.what()<<endl;
return 1;
}
}