diff --git b/.dep.inc a/.dep.inc new file mode 100644 index 0000000..38ba445 --- /dev/null +++ a/.dep.inc @@ -0,0 +1,5 @@ +# This code depends on make tool being used +DEPFILES=$(wildcard $(addsuffix .d, ${OBJECTFILES} ${TESTOBJECTFILES})) +ifneq (${DEPFILES},) +include ${DEPFILES} +endif diff --git b/.gitignore a/.gitignore new file mode 100644 index 0000000..95832e8 --- /dev/null +++ a/.gitignore @@ -0,0 +1,2 @@ +/build/ +/dist/ \ No newline at end of file diff --git b/Exception.hpp a/Exception.hpp new file mode 100644 index 0000000..1126843 --- /dev/null +++ a/Exception.hpp @@ -0,0 +1,30 @@ +#pragma once + +// System includes +#include +#include +#include +#include + + +class Exception : public std::runtime_error +{ +public: + Exception(const char *file, int line, const std::string &arg) + : std::runtime_error(arg) + { + msg_ = std::string(file) + ":" + std::to_string(line) + ": " + arg; + } + + ~Exception() throw() {} + + const char *what() const throw() override + { + return msg_.c_str(); + } + +private: + std::string msg_; +}; + +#define THROW_EXCEPT(arg) throw Exception(__FILE__, __LINE__, arg); diff --git b/Makefile a/Makefile new file mode 100644 index 0000000..05de621 --- /dev/null +++ a/Makefile @@ -0,0 +1,128 @@ +# +# There exist several targets which are by default empty and which can be +# used for execution of your targets. These targets are usually executed +# before and after some main targets. They are: +# +# .build-pre: called before 'build' target +# .build-post: called after 'build' target +# .clean-pre: called before 'clean' target +# .clean-post: called after 'clean' target +# .clobber-pre: called before 'clobber' target +# .clobber-post: called after 'clobber' target +# .all-pre: called before 'all' target +# .all-post: called after 'all' target +# .help-pre: called before 'help' target +# .help-post: called after 'help' target +# +# Targets beginning with '.' are not intended to be called on their own. +# +# Main targets can be executed directly, and they are: +# +# build build a specific configuration +# clean remove built files from a configuration +# clobber remove all built files +# all build all configurations +# help print help mesage +# +# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and +# .help-impl are implemented in nbproject/makefile-impl.mk. +# +# Available make variables: +# +# CND_BASEDIR base directory for relative paths +# CND_DISTDIR default top distribution directory (build artifacts) +# CND_BUILDDIR default top build directory (object files, ...) +# CONF name of current configuration +# CND_PLATFORM_${CONF} platform name (current configuration) +# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration) +# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration) +# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration) +# CND_PACKAGE_DIR_${CONF} directory of package (current configuration) +# CND_PACKAGE_NAME_${CONF} name of package (current configuration) +# CND_PACKAGE_PATH_${CONF} path to package (current configuration) +# +# NOCDDL + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin + + +# build +build: .build-post + +.build-pre: +# Add your pre 'build' code here... + +.build-post: .build-impl +# Add your post 'build' code here... + + +# clean +clean: .clean-post + +.clean-pre: +# Add your pre 'clean' code here... + +.clean-post: .clean-impl +# Add your post 'clean' code here... + + +# clobber +clobber: .clobber-post + +.clobber-pre: +# Add your pre 'clobber' code here... + +.clobber-post: .clobber-impl +# Add your post 'clobber' code here... + + +# all +all: .all-post + +.all-pre: +# Add your pre 'all' code here... + +.all-post: .all-impl +# Add your post 'all' code here... + + +# build tests +build-tests: .build-tests-post + +.build-tests-pre: +# Add your pre 'build-tests' code here... + +.build-tests-post: .build-tests-impl +# Add your post 'build-tests' code here... + + +# run tests +test: .test-post + +.test-pre: build-tests +# Add your pre 'test' code here... + +.test-post: .test-impl +# Add your post 'test' code here... + + +# help +help: .help-post + +.help-pre: +# Add your pre 'help' code here... + +.help-post: .help-impl +# Add your post 'help' code here... + + + +# include project implementation makefile +include nbproject/Makefile-impl.mk + +# include project make variables +include nbproject/Makefile-variables.mk diff --git b/SerialPort.cpp a/SerialPort.cpp new file mode 100644 index 0000000..3abbd6c --- /dev/null +++ a/SerialPort.cpp @@ -0,0 +1,677 @@ +// System includes +#include +#include +#include // Standard input/output definitions +#include // String function definitions +#include // UNIX standard function definitions +#include // File control definitions +#include // Error number definitions +// #include // POSIX terminal control definitions (struct termios) +#include // For throwing std::system_error +#include // Used for TCGETS2, which is required for custom baud rates +#include +// #include // Terminal control definitions (struct termios) +#include +#include +#include +#include + +// User includes +#include "Exception.hpp" +#include "SerialPort.hpp" + +#define BOTHER 0010000 + +SerialPort::SerialPort() +{ + echo_ = false; + timeout_ms_ = defaultTimeout_ms_; + baudRateType_ = BaudRateType::STANDARD; + baudRateStandard_ = defaultBaudRate_; + readBufferSize_B_ = defaultReadBufferSize_B_; + readBuffer_.reserve(readBufferSize_B_); + state_ = State::CLOSED; +} + +SerialPort::SerialPort(const std::string& device, BaudRate baudRate) + : SerialPort() +{ + device_ = device; + baudRateType_ = BaudRateType::STANDARD; + baudRateStandard_ = baudRate; +} + +SerialPort::SerialPort(const std::string& device, speed_t baudRate) + : SerialPort() +{ + device_ = device; + baudRateType_ = BaudRateType::CUSTOM; + baudRateCustom_ = baudRate; +} + +SerialPort::SerialPort( + const std::string& device, + BaudRate baudRate, + NumDataBits numDataBits, + Parity parity, + NumStopBits numStopBits) + : SerialPort() +{ + device_ = device; + baudRateType_ = BaudRateType::STANDARD; + baudRateStandard_ = baudRate; + numDataBits_ = numDataBits; + parity_ = parity; + numStopBits_ = numStopBits; +} + +SerialPort::~SerialPort() +{ + try + { + Close(); + } + catch(...) + { + // We can't do anything about this! + // But we don't want to throw within destructor, so swallow + } +} + +void SerialPort::SetDevice(const std::string& device) +{ + device_ = device; + if(state_ == State::OPEN) + ConfigureTermios(); +} + +void SerialPort::SetBaudRate(BaudRate baudRate) +{ + baudRateType_ = BaudRateType::STANDARD; + baudRateStandard_ = baudRate; + if(state_ == State::OPEN) + ConfigureTermios(); +} + +void SerialPort::SetBaudRate(speed_t baudRate) +{ + baudRateType_ = BaudRateType::CUSTOM; + baudRateCustom_ = baudRate; + if(state_ == State::OPEN) + ConfigureTermios(); +} + +void SerialPort::SetNumDataBits(NumDataBits numDataBits) +{ + numDataBits_ = numDataBits; + if(state_ == State::OPEN) + ConfigureTermios(); +} + +void SerialPort::SetParity(Parity parity) +{ + parity_ = parity; + if(state_ == State::OPEN) + ConfigureTermios(); +} + +void SerialPort::SetNumStopBits(NumStopBits numStopBits) +{ + numStopBits_ = numStopBits; + if(state_ == State::OPEN) + ConfigureTermios(); +} + +void SerialPort::Open() +{ + if(device_.empty()) + { + THROW_EXCEPT("Attempted to open file when file path has not been assigned to."); + } + + // Attempt to open file + //this->fileDesc = open(this->filePath, O_RDWR | O_NOCTTY | O_NDELAY); + + // O_RDONLY for read-only, O_WRONLY for write only, O_RDWR for both read/write access + // 3rd, optional parameter is mode_t mode + fileDesc_ = open(device_.c_str(), O_RDWR); + + // Check status + if(fileDesc_ == -1) + { + THROW_EXCEPT("Could not open device " + device_ + ". Is the device name correct and do you have read/write permission?"); + } + + ConfigureTermios(); + + // std::cout << "COM port opened successfully." << std::endl; + state_ = State::OPEN; +} + +void SerialPort::SetEcho(bool value) +{ + echo_ = value; + ConfigureTermios(); +} + +void SerialPort::ConfigureTermios() +{ + // std::cout << "Configuring COM port \"" << device_ << "\"." << std::endl; + //================== CONFIGURE ==================// + + // termios tty = GetTermios(); + termios2 tty = GetTermios2(); + + //================= (.c_cflag) ===============// + + // Set num. data bits + // See https://man7.org/linux/man-pages/man3/tcflush.3.html + tty.c_cflag &= ~CSIZE; // CSIZE is a mask for the number of bits per character + switch(numDataBits_) + { + case NumDataBits::FIVE: + tty.c_cflag |= CS5; + break; + case NumDataBits::SIX: + tty.c_cflag |= CS6; + break; + case NumDataBits::SEVEN: + tty.c_cflag |= CS7; + break; + case NumDataBits::EIGHT: + tty.c_cflag |= CS8; + break; + default: + THROW_EXCEPT("numDataBits_ value not supported!"); + } + + // Set parity + // See https://man7.org/linux/man-pages/man3/tcflush.3.html + switch(parity_) + { + case Parity::NONE: + tty.c_cflag &= ~PARENB; + break; + case Parity::EVEN: + tty.c_cflag |= PARENB; + tty.c_cflag &= ~PARODD; // Clearing PARODD makes the parity even + break; + case Parity::ODD: + tty.c_cflag |= PARENB; + tty.c_cflag |= PARODD; + break; + default: + THROW_EXCEPT("parity_ value not supported!"); + + } + + // Set num. stop bits + switch(numStopBits_) + { + case NumStopBits::ONE: + tty.c_cflag &= ~CSTOPB; + break; + case NumStopBits::TWO: + tty.c_cflag |= CSTOPB; + break; + default: + THROW_EXCEPT("numStopBits_ value not supported!"); + } + + tty.c_cflag &= ~CRTSCTS; // Disable hadrware flow control (RTS/CTS) + tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1) + + +//===================== BAUD RATE =================// + + // We used to use cfsetispeed() and cfsetospeed() with the B... macros, but this didn't allow + // us to set custom baud rates. So now to support both standard and custom baud rates lets + // just make everything "custom". This giant switch statement could be replaced with a map/lookup + // in the future + if (baudRateType_ == BaudRateType::STANDARD) + { + tty.c_cflag &= ~CBAUD; + tty.c_cflag |= CBAUDEX; + switch(baudRateStandard_) + { + case BaudRate::B_0: + // cfsetispeed(&tty, B0); + // cfsetospeed(&tty, B0); + tty.c_ispeed = 0; + tty.c_ospeed = 0; + break; + case BaudRate::B_50: + // cfsetispeed(&tty, B50); + // cfsetospeed(&tty, B50); + tty.c_ispeed = 50; + tty.c_ospeed = 50; + break; + case BaudRate::B_75: + // cfsetispeed(&tty, B75); + // cfsetospeed(&tty, B75); + tty.c_ispeed = 75; + tty.c_ospeed = 75; + break; + case BaudRate::B_110: + // cfsetispeed(&tty, B110); + // cfsetospeed(&tty, B110); + tty.c_ispeed = 110; + tty.c_ospeed = 110; + break; + case BaudRate::B_134: + // cfsetispeed(&tty, B134); + // cfsetospeed(&tty, B134); + tty.c_ispeed = 134; + tty.c_ospeed = 134; + break; + case BaudRate::B_150: + // cfsetispeed(&tty, B150); + // cfsetospeed(&tty, B150); + tty.c_ispeed = 150; + tty.c_ospeed = 150; + break; + case BaudRate::B_200: + // cfsetispeed(&tty, B200); + // cfsetospeed(&tty, B200); + tty.c_ispeed = 200; + tty.c_ospeed = 200; + break; + case BaudRate::B_300: + // cfsetispeed(&tty, B300); + // cfsetospeed(&tty, B300); + tty.c_ispeed = 300; + tty.c_ospeed = 300; + break; + case BaudRate::B_600: + // cfsetispeed(&tty, B600); + // cfsetospeed(&tty, B600); + tty.c_ispeed = 600; + tty.c_ospeed = 600; + break; + case BaudRate::B_1200: + // cfsetispeed(&tty, B1200); + // cfsetospeed(&tty, B1200); + tty.c_ispeed = 1200; + tty.c_ospeed = 1200; + break; + case BaudRate::B_1800: + // cfsetispeed(&tty, B1800); + // cfsetospeed(&tty, B1800); + tty.c_ispeed = 1800; + tty.c_ospeed = 1800; + break; + case BaudRate::B_2400: + // cfsetispeed(&tty, B2400); + // cfsetospeed(&tty, B2400); + tty.c_ispeed = 2400; + tty.c_ospeed = 2400; + break; + case BaudRate::B_4800: + // cfsetispeed(&tty, B4800); + // cfsetospeed(&tty, B4800); + tty.c_ispeed = 4800; + tty.c_ospeed = 4800; + break; + case BaudRate::B_9600: + // cfsetispeed(&tty, B9600); + // cfsetospeed(&tty, B9600); + tty.c_ispeed = 9600; + tty.c_ospeed = 9600; + break; + case BaudRate::B_19200: + // cfsetispeed(&tty, B19200); + // cfsetospeed(&tty, B19200); + tty.c_ispeed = 19200; + tty.c_ospeed = 19200; + break; + case BaudRate::B_38400: + // cfsetispeed(&tty, B38400); + // cfsetospeed(&tty, B38400); + tty.c_ispeed = 38400; + tty.c_ospeed = 38400; + break; + case BaudRate::B_57600: + // cfsetispeed(&tty, B57600); + // cfsetospeed(&tty, B57600); + tty.c_ispeed = 57600; + tty.c_ospeed = 57600; + break; + case BaudRate::B_115200: + // cfsetispeed(&tty, B115200); + // cfsetospeed(&tty, B115200); + tty.c_ispeed = 115200; + tty.c_ospeed = 115200; + break; + case BaudRate::B_230400: + // cfsetispeed(&tty, B230400); + // cfsetospeed(&tty, B230400); + tty.c_ispeed = 230400; + tty.c_ospeed = 230400; + break; + case BaudRate::B_460800: + // cfsetispeed(&tty, B460800); + // cfsetospeed(&tty, B460800); + tty.c_ispeed = 460800; + tty.c_ospeed = 460800; + break; + default: + throw std::runtime_error(std::string() + "baudRate passed to " + __PRETTY_FUNCTION__ + " unrecognized."); + } + } + // This does no different than STANDARD atm, but let's keep + // them separate for now.... + else if (baudRateType_ == BaudRateType::CUSTOM) + { + tty.c_cflag &= ~CBAUD; + tty.c_cflag |= CBAUDEX; + // tty.c_cflag |= BOTHER; + tty.c_ispeed = baudRateCustom_; + tty.c_ospeed = baudRateCustom_; + + + // #include + // // configure port to use custom speed instead of 38400 + // struct serial_struct ss; + // ioctl(fileDesc_, TIOCGSERIAL, &ss); + // ss.flags = (ss.flags & ~ASYNC_SPD_MASK) | ASYNC_SPD_CUST; + // ss.custom_divisor = (ss.baud_base + (baudRateCustom_ / 2)) / baudRateCustom_; + // int closestSpeed = ss.baud_base / ss.custom_divisor; + + // if (closestSpeed < baudRateCustom_ * 98 / 100 || closestSpeed > baudRateCustom_ * 102 / 100) { + // printf("Cannot set serial port speed to %d. Closest possible is %d\n", baudRateCustom_, closestSpeed); + // } + + // ioctl(fileDesc_, TIOCSSERIAL, &ss); + + // cfsetispeed(&tty, B38400); + // cfsetospeed(&tty, B38400); + } + else + { + // Should never get here, bug in this libraries code! + assert(false); + } + + //===================== (.c_oflag) =================// + + tty.c_oflag = 0; // No remapping, no delays + tty.c_oflag &= ~OPOST; // Make raw + + //================= CONTROL CHARACTERS (.c_cc[]) ==================// + + // c_cc[VTIME] sets the inter-character timer, in units of 0.1s. + // Only meaningful when port is set to non-canonical mode + // VMIN = 0, VTIME = 0: No blocking, return immediately with what is available + // VMIN > 0, VTIME = 0: read() waits for VMIN bytes, could block indefinitely + // VMIN = 0, VTIME > 0: Block until any amount of data is available, OR timeout occurs + // VMIN > 0, VTIME > 0: Block until either VMIN characters have been received, or VTIME + // after first character has elapsed + // c_cc[WMIN] sets the number of characters to block (wait) for when read() is called. + // Set to 0 if you don't want read to block. Only meaningful when port set to non-canonical mode + + if(timeout_ms_ == -1) + { + // Always wait for at least one byte, this could + // block indefinitely + tty.c_cc[VTIME] = 0; + tty.c_cc[VMIN] = 1; + } + else if(timeout_ms_ == 0) + { + // Setting both to 0 will give a non-blocking read + tty.c_cc[VTIME] = 0; + tty.c_cc[VMIN] = 0; + } + else if(timeout_ms_ > 0) + { + tty.c_cc[VTIME] = (cc_t)(timeout_ms_/100); // 0.5 seconds read timeout + tty.c_cc[VMIN] = 0; + } + + //======================== (.c_iflag) ====================// + + tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); + + //=========================== LOCAL MODES (c_lflag) =======================// + + // Canonical input is when read waits for EOL or EOF characters before returning. In non-canonical mode, the rate at which + // read() returns is instead controlled by c_cc[VMIN] and c_cc[VTIME] + tty.c_lflag &= ~ICANON; // Turn off canonical input, which is suitable for pass-through + // Configure echo depending on echo_ boolean + if(echo_) + { + tty.c_lflag |= ECHO; + } + else + { + tty.c_lflag &= ~(ECHO); + } + tty.c_lflag &= ~ECHOE; // Turn off echo erase (echo erase only relevant if canonical input is active) + tty.c_lflag &= ~ECHONL; // + tty.c_lflag &= ~ISIG; // Disables recognition of INTR (interrupt), QUIT and SUSP (suspend) characters + + + // Try and use raw function call + //cfmakeraw(&tty); + + // this->SetTermios(tty); + this->SetTermios2(tty); + + /* + // Flush port, then apply attributes + tcflush(this->fileDesc, TCIFLUSH); + + if(tcsetattr(this->fileDesc, TCSANOW, &tty) != 0) + { + // Error occurred + this->sp->PrintError(SmartPrint::Ss() << "Could not apply terminal attributes for \"" << this->filePath << "\" - " << strerror(errno)); + return; + }*/ +} + +void SerialPort::Write(const std::string& data) +{ + + if(state_ != State::OPEN) + THROW_EXCEPT(std::string() + __PRETTY_FUNCTION__ + " called but state != OPEN. Please call Open() first."); + + if(fileDesc_ < 0) + { + THROW_EXCEPT(std::string() + __PRETTY_FUNCTION__ + " called but file descriptor < 0, indicating file has not been opened."); + } + + int writeResult = write(fileDesc_, data.c_str(), data.size()); + + // Check status + if (writeResult == -1) + { + throw std::system_error(EFAULT, std::system_category()); + } +} + +void SerialPort::WriteBinary( const std::vector& data ) +{ + + if(state_ != State::OPEN) + THROW_EXCEPT(std::string() + __PRETTY_FUNCTION__ + " called but state != OPEN. Please call Open() first."); + + if(fileDesc_ < 0) + { + THROW_EXCEPT(std::string() + __PRETTY_FUNCTION__ + " called but file descriptor < 0, indicating file has not been opened."); + } + + int writeResult = write(fileDesc_, data.data(), data.size()); + + // Check status + if (writeResult == -1) + { + throw std::system_error(EFAULT, std::system_category()); + } + } + +void SerialPort::Read(std::string& data) +{ + data.clear(); + + if(fileDesc_ == 0) + { + //this->sp->PrintError(SmartPrint::Ss() << "Read() was called but file descriptor (fileDesc) was 0, indicating file has not been opened."); + //return false; + THROW_EXCEPT("Read() was called but file descriptor (fileDesc) was 0, indicating file has not been opened."); + } + + // Allocate memory for read buffer + // char buf [256]; + // memset (&buf, '\0', sizeof buf); + + // Read from file + // We provide the underlying raw array from the readBuffer_ vector to this C api. + // This will work because we do not delete/resize the vector while this method + // is called + ssize_t n = read( fileDesc_, &readBuffer_[0], readBufferSize_B_ ); + + // Error Handling + if( n < 0 ) + { + // Read was unsuccessful + throw std::system_error(EFAULT, std::system_category()); + } + + if( n > 0 ) + { + // buf[n] = '\0'; + // printf("%s\r\n", buf); + // data.append(buf); + data = std::string( &readBuffer_[0], n ); + //std::cout << *str << " and size of string =" << str->size() << "\r\n"; + } +} + +void SerialPort::ReadBinary(std::vector& data) +{ + data.clear(); + + if( fileDesc_ == 0 ) + { + THROW_EXCEPT("Read() was called but file descriptor (fileDesc) was 0, indicating file has not been opened."); + } + + // Read from file + // We provide the underlying raw array from the readBuffer_ vector to this C api. + // This will work because we do not delete/resize the vector while this method + // is called + ssize_t n = read(fileDesc_, &readBuffer_[0], readBufferSize_B_); + + // Error Handling + if( n < 0 ) + { + // Read was unsuccessful + throw std::system_error(EFAULT, std::system_category()); + } + + if( n > 0 ) + { + copy(readBuffer_.begin(), readBuffer_.begin() + n, back_inserter(data)); + } +} + + // termios SerialPort::GetTermios() { +// if(fileDesc_ == -1) +// throw std::runtime_error("GetTermios() called but file descriptor was not valid."); + + // struct termios tty; + // memset(&tty, 0, sizeof(tty)); + + // // Get current settings (will be stored in termios structure) + // if(tcgetattr(fileDesc_, &tty) != 0) + // { + // // Error occurred + // std::cout << "Could not get terminal attributes for \"" << device_ << "\" - " << strerror(errno) << std::endl; + // throw std::system_error(EFAULT, std::system_category()); + // //return false; + // } + + // return tty; + // } + + // void SerialPort::SetTermios(termios myTermios) + // { + // // Flush port, then apply attributes + // tcflush(fileDesc_, TCIFLUSH); + + // if(tcsetattr(fileDesc_, TCSANOW, &myTermios) != 0) + // { + // // Error occurred + // std::cout << "Could not apply terminal attributes for \"" << device_ << "\" - " << strerror(errno) << std::endl; + // throw std::system_error(EFAULT, std::system_category()); + + // } + + // // Successful! + // } + +termios2 SerialPort::GetTermios2() +{ + struct termios2 term2; + + ioctl(fileDesc_, TCGETS2, &term2); + + return term2; + + // term2.c_cflag &= ~CBAUD; /* Remove current BAUD rate */ + // term2.c_cflag |= BOTHER; /* Allow custom BAUD rate using int input */ + // term2.c_ispeed = speed; /* Set the input BAUD rate */ + // term2.c_ospeed = speed; /* Set the output BAUD rate */ + + // ioctl(fd, TCSETS2, &term2); +} + +void SerialPort::SetTermios2(termios2 tty) +{ + ioctl(fileDesc_, TCSETS2, &tty); +} + +void SerialPort::Close() +{ + if(fileDesc_ != -1) + { + auto retVal = close(fileDesc_); + if(retVal != 0) + THROW_EXCEPT("Tried to close serial port " + device_ + ", but close() failed."); + + fileDesc_ = -1; + } + + state_ = State::CLOSED; +} + +void SerialPort::SetTimeout(int32_t timeout_ms) +{ + if(timeout_ms < -1) + THROW_EXCEPT(std::string() + "timeout_ms provided to " + __PRETTY_FUNCTION__ + " was < -1, which is invalid."); + + if(timeout_ms > 25500) + THROW_EXCEPT(std::string() + "timeout_ms provided to " + __PRETTY_FUNCTION__ + " was > 25500, which is invalid."); + + if(state_ == State::OPEN) + THROW_EXCEPT(std::string() + __PRETTY_FUNCTION__ + " called while state == OPEN."); + + timeout_ms_ = timeout_ms; +} + +int32_t SerialPort::Available() +{ + if(state_ != State::OPEN) + THROW_EXCEPT(std::string() + __PRETTY_FUNCTION__ + " called but state != OPEN. Please call Open() first."); + + int32_t ret = 0; + ioctl(fileDesc_, FIONREAD, &ret); + return ret; + +} + +State SerialPort::GetState() +{ + return state_; +} diff --git b/SerialPort.hpp a/SerialPort.hpp new file mode 100644 index 0000000..f5cf8a1 --- /dev/null +++ a/SerialPort.hpp @@ -0,0 +1,223 @@ +#pragma once + +// System headers +#include +#include // For file I/O (reading/writing to COM port) +#include +// #include // POSIX terminal control definitions (struct termios) +// #include // Terminal control definitions (struct termios) +#include +#include +#include + +// User headers +#include "Exception.hpp" + +/// \brief Represents the baud rate "types" that can be used with the serial port. STANDARD represents all +/// the standard baud rates as provided by UNIX, CUSTOM represents a baud rate defined by an arbitray integer. +enum class BaudRateType +{ + STANDARD, + CUSTOM, +}; + +/// \brief Strongly-typed enumeration of baud rates for use with the SerialPort class +/// \details Specifies all the same baud rates as UNIX, as well as B_CUSTOM to specify your +/// own. See https://linux.die.net/man/3/cfsetispeed for list of supported UNIX baud rates. +enum class BaudRate +{ + B_0, + B_50, + B_75, + B_110, + B_134, + B_150, + B_200, + B_300, + B_600, + B_1200, + B_1800, + B_2400, + B_4800, + B_9600, + B_19200, + B_38400, + B_57600, + B_115200, + B_230400, + B_460800, + B_CUSTOM, // Placeholder +}; + +/// \brief Enumeration of all the valid num. of data bits. Must align with the options +/// provided in termbits.h, i.e. CS5, CS6, CS7 and CS8. +enum class NumDataBits +{ + FIVE, + SIX, + SEVEN, + EIGHT, +}; + +enum class Parity +{ + NONE, + EVEN, + ODD, +}; + +enum class NumStopBits +{ + ONE, + TWO, +}; + +/// \brief Represents the state of the serial port. +enum class State +{ + CLOSED, + OPEN, +}; + +/// \brief SerialPort object is used to perform rx/tx serial communication. +class SerialPort +{ +public: + /// \brief Default constructor. You must specify at least the device before calling Open(). + SerialPort(); + + /// \brief Constructor that sets up serial port with the basic (required) parameters. + SerialPort(const std::string &device, BaudRate baudRate); + + /// \brief Constructor that sets up serial port and allows the user to specify all the common parameters. + SerialPort(const std::string &device, BaudRate baudRate, NumDataBits numDataBits, Parity parity, NumStopBits numStopBits); + + /// \brief Constructor that sets up serial port with the basic parameters, and a custom baud rate. + SerialPort(const std::string &device, speed_t baudRate); + + /// \brief Destructor. Closes serial port if still open. + virtual ~SerialPort(); + + /// \brief Sets the device to use for serial port communications. + /// \details Method can be called when serial port is in any state. + void SetDevice(const std::string &device); + + /// \brief Call this to set a standard baud rate. + void SetBaudRate(BaudRate baudRate); + + /// \brief Call this to set a custom baud rate. + void SetBaudRate(speed_t baudRate); + + /// \brief Call this to set the num. of data bits. + void SetNumDataBits(NumDataBits numDataBits); + + /// \brief Call this to set the parity. + void SetParity(Parity parity); + + void SetNumStopBits(NumStopBits numStopBits); + + /// \brief Sets the read timeout (in milliseconds)/blocking mode. + /// \details Only call when state != OPEN. This method manupulates VMIN and VTIME. + /// \param timeout_ms Set to -1 to infinite timeout, 0 to return immediately with any data (non + /// blocking, or >0 to wait for data for a specified number of milliseconds). Timeout will + /// be rounded to the nearest 100ms (a Linux API restriction). Maximum value limited to + /// 25500ms (another Linux API restriction). + void SetTimeout(int32_t timeout_ms); + + /// \brief Enables/disables echo. + /// \param value Pass in true to enable echo, false to disable echo. + void SetEcho(bool value); + + /// \brief Opens the COM port for use. + /// \throws CppLinuxSerial::Exception if device cannot be opened. + /// \note Must call this before you can configure the COM port. + void Open(); + + /// \brief Closes the COM port. + void Close(); + + /// \brief Sends a text message over the com port. + /// \param data The data that will be written to the COM port. + /// \throws CppLinuxSerial::Exception if state != OPEN. + void Write(const std::string& data); + + /// \brief Sends a binary message over the com port. + /// \param data The data that will be written to the COM port. + /// \throws CppLinuxSerial::Exception if state != OPEN. + void WriteBinary(const std::vector& data); + + /// \brief Use to read text from the COM port. + /// \param data The object the read characters from the COM port will be saved to. + /// \param wait_ms The amount of time to wait for data. Set to 0 for non-blocking mode. Set to -1 + /// to wait indefinitely for new data. + /// \throws CppLinuxSerial::Exception if state != OPEN. + void Read(std::string& data); + + /// \brief Use to read binary data from the COM port. + /// \param data The object the read uint8_t bytes from the COM port will be saved to. + /// \param wait_ms The amount of time to wait for data. Set to 0 for non-blocking mode. Set to -1 + /// to wait indefinitely for new data. + /// \throws CppLinuxSerial::Exception if state != OPEN. + void ReadBinary(std::vector& data); + + /// \brief Use to get number of bytes available in receive buffer. + /// \returns The number of bytes available in the receive buffer (ready to be read). + /// \throws CppLinuxSerial::Exception if state != OPEN. + int32_t Available(); + + /// \brief Use to get the state of the serial port + /// \returns The state of the serial port + State GetState(); + +private: + + /// \brief Configures the tty device as a serial port. + /// \warning Device must be open (valid file descriptor) when this is called. + void ConfigureTermios(); + + // void SetTermios(termios myTermios); + + /// \brief Returns a populated termios2 structure for the serial port pointed to by the file descriptor. + termios2 GetTermios2(); + + /// \brief Assigns the provided tty settings to the serial port pointed to by the file descriptor. + void SetTermios2(termios2 tty); + + /// \brief Keeps track of the serial port's state. + State state_; + + /// \brief The file path to the serial port device (e.g. "/dev/ttyUSB0"). + std::string device_; + + /// \brief The type of baud rate that the user has specified. + BaudRateType baudRateType_; + + /// \brief The current baud rate if baudRateType_ == STANDARD. + BaudRate baudRateStandard_; + + /// \brief The current baud rate if baudRateType_ == CUSTOM. + speed_t baudRateCustom_; + + /// \brief The num. of data bits. Defaults to 8 (most common). + NumDataBits numDataBits_ = NumDataBits::EIGHT; + + /// \brief The parity. Defaults to none (most common). + Parity parity_ = Parity::NONE; + + /// \brief The num. of stop bits. Defaults to 1 (most common). + NumStopBits numStopBits_ = NumStopBits::ONE; + + /// \brief The file descriptor for the open file. This gets written to when Open() is called. + int fileDesc_; + + bool echo_; + + int32_t timeout_ms_; + + std::vector readBuffer_; + unsigned char readBufferSize_B_; + + static constexpr BaudRate defaultBaudRate_ = BaudRate::B_57600; + static constexpr int32_t defaultTimeout_ms_ = -1; + static constexpr unsigned char defaultReadBufferSize_B_ = 255; +}; diff --git b/main.cpp a/main.cpp new file mode 100644 index 0000000..cde43ad --- /dev/null +++ a/main.cpp @@ -0,0 +1,36 @@ +#include "SerialPort.hpp" + +#include +#include +#include + +int main(int argc, char** argv) +{ + SerialPort oPort; + + oPort.SetDevice( "/dev/ttyUSB0" ); + oPort.SetNumDataBits(NumDataBits::EIGHT); + oPort.SetParity(Parity::NONE); + oPort.SetNumStopBits(NumStopBits::ONE); + oPort.SetBaudRate( BaudRate::B_2400 ); + + oPort.Open(); + + // Create data package. + std::vector data_binair; + std::string data_string; + + for( uint8_t nCount = 0; nCount < 255; nCount++ ) + { + data_binair.push_back( nCount ); + data_string += std::to_string(nCount); + } + while( 1 ) + { + oPort.WriteBinary( data_binair ); + oPort.Write( data_string ); + } + + return 0; +} + diff --git b/nbproject/Makefile-Debug.mk a/nbproject/Makefile-Debug.mk new file mode 100644 index 0000000..0035b84 --- /dev/null +++ a/nbproject/Makefile-Debug.mk @@ -0,0 +1,89 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a -pre and a -post target defined where you can add customized code. +# +# This makefile implements configuration specific macros and targets. + + +# Environment +MKDIR=mkdir +CP=cp +GREP=grep +NM=nm +CCADMIN=CCadmin +RANLIB=ranlib +CC=gcc +CCC=g++ +CXX=g++ +FC=gfortran +AS=as + +# Macros +CND_PLATFORM=GNU-Linux +CND_DLIB_EXT=so +CND_CONF=Debug +CND_DISTDIR=dist +CND_BUILDDIR=build + +# Include project Makefile +include Makefile + +# Object Directory +OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM} + +# Object Files +OBJECTFILES= \ + ${OBJECTDIR}/SerialPort.o \ + ${OBJECTDIR}/main.o + + +# C Compiler Flags +CFLAGS= + +# CC Compiler Flags +CCFLAGS=-m64 +CXXFLAGS=-m64 + +# Fortran Compiler Flags +FFLAGS= + +# Assembler Flags +ASFLAGS= + +# Link Libraries and Options +LDLIBSOPTIONS= + +# Build Targets +.build-conf: ${BUILD_SUBPROJECTS} + "${MAKE}" -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/serialport + +${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/serialport: ${OBJECTFILES} + ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} + ${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/serialport ${OBJECTFILES} ${LDLIBSOPTIONS} + +${OBJECTDIR}/SerialPort.o: SerialPort.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -g -std=c++14 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/SerialPort.o SerialPort.cpp + +${OBJECTDIR}/main.o: main.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -g -std=c++14 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/main.o main.cpp + +# Subprojects +.build-subprojects: + +# Clean Targets +.clean-conf: ${CLEAN_SUBPROJECTS} + ${RM} -r ${CND_BUILDDIR}/${CND_CONF} + +# Subprojects +.clean-subprojects: + +# Enable dependency checking +.dep.inc: .depcheck-impl + +include .dep.inc diff --git b/nbproject/Makefile-Release.mk a/nbproject/Makefile-Release.mk new file mode 100644 index 0000000..72bd10b --- /dev/null +++ a/nbproject/Makefile-Release.mk @@ -0,0 +1,89 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a -pre and a -post target defined where you can add customized code. +# +# This makefile implements configuration specific macros and targets. + + +# Environment +MKDIR=mkdir +CP=cp +GREP=grep +NM=nm +CCADMIN=CCadmin +RANLIB=ranlib +CC=gcc +CCC=g++ +CXX=g++ +FC=gfortran +AS=as + +# Macros +CND_PLATFORM=GNU-Linux +CND_DLIB_EXT=so +CND_CONF=Release +CND_DISTDIR=dist +CND_BUILDDIR=build + +# Include project Makefile +include Makefile + +# Object Directory +OBJECTDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM} + +# Object Files +OBJECTFILES= \ + ${OBJECTDIR}/SerialPort.o \ + ${OBJECTDIR}/main.o + + +# C Compiler Flags +CFLAGS= + +# CC Compiler Flags +CCFLAGS= +CXXFLAGS= + +# Fortran Compiler Flags +FFLAGS= + +# Assembler Flags +ASFLAGS= + +# Link Libraries and Options +LDLIBSOPTIONS= + +# Build Targets +.build-conf: ${BUILD_SUBPROJECTS} + "${MAKE}" -f nbproject/Makefile-${CND_CONF}.mk ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/serialport + +${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/serialport: ${OBJECTFILES} + ${MKDIR} -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM} + ${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/serialport ${OBJECTFILES} ${LDLIBSOPTIONS} + +${OBJECTDIR}/SerialPort.o: SerialPort.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -std=c++14 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/SerialPort.o SerialPort.cpp + +${OBJECTDIR}/main.o: main.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} "$@.d" + $(COMPILE.cc) -O2 -std=c++14 -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/main.o main.cpp + +# Subprojects +.build-subprojects: + +# Clean Targets +.clean-conf: ${CLEAN_SUBPROJECTS} + ${RM} -r ${CND_BUILDDIR}/${CND_CONF} + +# Subprojects +.clean-subprojects: + +# Enable dependency checking +.dep.inc: .depcheck-impl + +include .dep.inc diff --git b/nbproject/Makefile-impl.mk a/nbproject/Makefile-impl.mk new file mode 100644 index 0000000..b1cfa30 --- /dev/null +++ a/nbproject/Makefile-impl.mk @@ -0,0 +1,133 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a pre- and a post- target defined where you can add customization code. +# +# This makefile implements macros and targets common to all configurations. +# +# NOCDDL + + +# Building and Cleaning subprojects are done by default, but can be controlled with the SUB +# macro. If SUB=no, subprojects will not be built or cleaned. The following macro +# statements set BUILD_SUB-CONF and CLEAN_SUB-CONF to .build-reqprojects-conf +# and .clean-reqprojects-conf unless SUB has the value 'no' +SUB_no=NO +SUBPROJECTS=${SUB_${SUB}} +BUILD_SUBPROJECTS_=.build-subprojects +BUILD_SUBPROJECTS_NO= +BUILD_SUBPROJECTS=${BUILD_SUBPROJECTS_${SUBPROJECTS}} +CLEAN_SUBPROJECTS_=.clean-subprojects +CLEAN_SUBPROJECTS_NO= +CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}} + + +# Project Name +PROJECTNAME=serialport + +# Active Configuration +DEFAULTCONF=Debug +CONF=${DEFAULTCONF} + +# All Configurations +ALLCONFS=Debug Release + + +# build +.build-impl: .build-pre .validate-impl .depcheck-impl + @#echo "=> Running $@... Configuration=$(CONF)" + "${MAKE}" -f nbproject/Makefile-${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .build-conf + + +# clean +.clean-impl: .clean-pre .validate-impl .depcheck-impl + @#echo "=> Running $@... Configuration=$(CONF)" + "${MAKE}" -f nbproject/Makefile-${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .clean-conf + + +# clobber +.clobber-impl: .clobber-pre .depcheck-impl + @#echo "=> Running $@..." + for CONF in ${ALLCONFS}; \ + do \ + "${MAKE}" -f nbproject/Makefile-$${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .clean-conf; \ + done + +# all +.all-impl: .all-pre .depcheck-impl + @#echo "=> Running $@..." + for CONF in ${ALLCONFS}; \ + do \ + "${MAKE}" -f nbproject/Makefile-$${CONF}.mk QMAKE=${QMAKE} SUBPROJECTS=${SUBPROJECTS} .build-conf; \ + done + +# build tests +.build-tests-impl: .build-impl .build-tests-pre + @#echo "=> Running $@... Configuration=$(CONF)" + "${MAKE}" -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-tests-conf + +# run tests +.test-impl: .build-tests-impl .test-pre + @#echo "=> Running $@... Configuration=$(CONF)" + "${MAKE}" -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .test-conf + +# dependency checking support +.depcheck-impl: + @echo "# This code depends on make tool being used" >.dep.inc + @if [ -n "${MAKE_VERSION}" ]; then \ + echo "DEPFILES=\$$(wildcard \$$(addsuffix .d, \$${OBJECTFILES} \$${TESTOBJECTFILES}))" >>.dep.inc; \ + echo "ifneq (\$${DEPFILES},)" >>.dep.inc; \ + echo "include \$${DEPFILES}" >>.dep.inc; \ + echo "endif" >>.dep.inc; \ + else \ + echo ".KEEP_STATE:" >>.dep.inc; \ + echo ".KEEP_STATE_FILE:.make.state.\$${CONF}" >>.dep.inc; \ + fi + +# configuration validation +.validate-impl: + @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ + then \ + echo ""; \ + echo "Error: can not find the makefile for configuration '${CONF}' in project ${PROJECTNAME}"; \ + echo "See 'make help' for details."; \ + echo "Current directory: " `pwd`; \ + echo ""; \ + fi + @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ + then \ + exit 1; \ + fi + + +# help +.help-impl: .help-pre + @echo "This makefile supports the following configurations:" + @echo " ${ALLCONFS}" + @echo "" + @echo "and the following targets:" + @echo " build (default target)" + @echo " clean" + @echo " clobber" + @echo " all" + @echo " help" + @echo "" + @echo "Makefile Usage:" + @echo " make [CONF=] [SUB=no] build" + @echo " make [CONF=] [SUB=no] clean" + @echo " make [SUB=no] clobber" + @echo " make [SUB=no] all" + @echo " make help" + @echo "" + @echo "Target 'build' will build a specific configuration and, unless 'SUB=no'," + @echo " also build subprojects." + @echo "Target 'clean' will clean a specific configuration and, unless 'SUB=no'," + @echo " also clean subprojects." + @echo "Target 'clobber' will remove all built files from all configurations and," + @echo " unless 'SUB=no', also from subprojects." + @echo "Target 'all' will will build all configurations and, unless 'SUB=no'," + @echo " also build subprojects." + @echo "Target 'help' prints this message." + @echo "" + diff --git b/nbproject/Makefile-variables.mk a/nbproject/Makefile-variables.mk new file mode 100644 index 0000000..576098b --- /dev/null +++ a/nbproject/Makefile-variables.mk @@ -0,0 +1,35 @@ +# +# Generated - do not edit! +# +# NOCDDL +# +CND_BASEDIR=`pwd` +CND_BUILDDIR=build +CND_DISTDIR=dist +# Debug configuration +CND_PLATFORM_Debug=GNU-Linux +CND_ARTIFACT_DIR_Debug=dist/Debug/GNU-Linux +CND_ARTIFACT_NAME_Debug=serialport +CND_ARTIFACT_PATH_Debug=dist/Debug/GNU-Linux/serialport +CND_PACKAGE_DIR_Debug=dist/Debug/GNU-Linux/package +CND_PACKAGE_NAME_Debug=serialport.tar +CND_PACKAGE_PATH_Debug=dist/Debug/GNU-Linux/package/serialport.tar +# Release configuration +CND_PLATFORM_Release=GNU-Linux +CND_ARTIFACT_DIR_Release=dist/Release/GNU-Linux +CND_ARTIFACT_NAME_Release=serialport +CND_ARTIFACT_PATH_Release=dist/Release/GNU-Linux/serialport +CND_PACKAGE_DIR_Release=dist/Release/GNU-Linux/package +CND_PACKAGE_NAME_Release=serialport.tar +CND_PACKAGE_PATH_Release=dist/Release/GNU-Linux/package/serialport.tar +# +# include compiler specific variables +# +# dmake command +ROOT:sh = test -f nbproject/private/Makefile-variables.mk || \ + (mkdir -p nbproject/private && touch nbproject/private/Makefile-variables.mk) +# +# gmake command +.PHONY: $(shell test -f nbproject/private/Makefile-variables.mk || (mkdir -p nbproject/private && touch nbproject/private/Makefile-variables.mk)) +# +include nbproject/private/Makefile-variables.mk diff --git b/nbproject/Package-Debug.bash a/nbproject/Package-Debug.bash new file mode 100644 index 0000000..8c12d40 --- /dev/null +++ a/nbproject/Package-Debug.bash @@ -0,0 +1,76 @@ +#!/bin/bash -x + +# +# Generated - do not edit! +# + +# Macros +TOP=`pwd` +CND_PLATFORM=GNU-Linux +CND_CONF=Debug +CND_DISTDIR=dist +CND_BUILDDIR=build +CND_DLIB_EXT=so +NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging +TMPDIRNAME=tmp-packaging +OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/serialport +OUTPUT_BASENAME=serialport +PACKAGE_TOP_DIR=serialport/ + +# Functions +function checkReturnCode +{ + rc=$? + if [ $rc != 0 ] + then + exit $rc + fi +} +function makeDirectory +# $1 directory path +# $2 permission (optional) +{ + mkdir -p "$1" + checkReturnCode + if [ "$2" != "" ] + then + chmod $2 "$1" + checkReturnCode + fi +} +function copyFileToTmpDir +# $1 from-file path +# $2 to-file path +# $3 permission +{ + cp "$1" "$2" + checkReturnCode + if [ "$3" != "" ] + then + chmod $3 "$2" + checkReturnCode + fi +} + +# Setup +cd "${TOP}" +mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package +rm -rf ${NBTMPDIR} +mkdir -p ${NBTMPDIR} + +# Copy files and create directories and links +cd "${TOP}" +makeDirectory "${NBTMPDIR}/serialport/bin" +copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 + + +# Generate tar file +cd "${TOP}" +rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/serialport.tar +cd ${NBTMPDIR} +tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/serialport.tar * +checkReturnCode + +# Cleanup +cd "${TOP}" +rm -rf ${NBTMPDIR} diff --git b/nbproject/Package-Release.bash a/nbproject/Package-Release.bash new file mode 100644 index 0000000..2c7d8a7 --- /dev/null +++ a/nbproject/Package-Release.bash @@ -0,0 +1,76 @@ +#!/bin/bash -x + +# +# Generated - do not edit! +# + +# Macros +TOP=`pwd` +CND_PLATFORM=GNU-Linux +CND_CONF=Release +CND_DISTDIR=dist +CND_BUILDDIR=build +CND_DLIB_EXT=so +NBTMPDIR=${CND_BUILDDIR}/${CND_CONF}/${CND_PLATFORM}/tmp-packaging +TMPDIRNAME=tmp-packaging +OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/serialport +OUTPUT_BASENAME=serialport +PACKAGE_TOP_DIR=serialport/ + +# Functions +function checkReturnCode +{ + rc=$? + if [ $rc != 0 ] + then + exit $rc + fi +} +function makeDirectory +# $1 directory path +# $2 permission (optional) +{ + mkdir -p "$1" + checkReturnCode + if [ "$2" != "" ] + then + chmod $2 "$1" + checkReturnCode + fi +} +function copyFileToTmpDir +# $1 from-file path +# $2 to-file path +# $3 permission +{ + cp "$1" "$2" + checkReturnCode + if [ "$3" != "" ] + then + chmod $3 "$2" + checkReturnCode + fi +} + +# Setup +cd "${TOP}" +mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package +rm -rf ${NBTMPDIR} +mkdir -p ${NBTMPDIR} + +# Copy files and create directories and links +cd "${TOP}" +makeDirectory "${NBTMPDIR}/serialport/bin" +copyFileToTmpDir "${OUTPUT_PATH}" "${NBTMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 + + +# Generate tar file +cd "${TOP}" +rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/serialport.tar +cd ${NBTMPDIR} +tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/serialport.tar * +checkReturnCode + +# Cleanup +cd "${TOP}" +rm -rf ${NBTMPDIR} diff --git b/nbproject/configurations.xml a/nbproject/configurations.xml new file mode 100644 index 0000000..ccbd549 --- /dev/null +++ a/nbproject/configurations.xml @@ -0,0 +1,86 @@ + + + + + Exception.hpp + SerialPort.hpp + + + + + SerialPort.cpp + main.cpp + + + + + Makefile + + + Makefile + + + + default + true + false + + + + 2 + 11 + + + + + + + + + + + + + + default + true + false + + + + 5 + + + 5 + 11 + + + 5 + + + 5 + + + + + + + + + + + + + diff --git b/nbproject/private/Makefile-variables.mk a/nbproject/private/Makefile-variables.mk new file mode 100644 index 0000000..a64183e --- /dev/null +++ a/nbproject/private/Makefile-variables.mk @@ -0,0 +1,7 @@ +# +# Generated - do not edit! +# +# NOCDDL +# +# Debug configuration +# Release configuration diff --git b/nbproject/private/c_standard_headers_indexer.c a/nbproject/private/c_standard_headers_indexer.c new file mode 100644 index 0000000..c2548d2 --- /dev/null +++ a/nbproject/private/c_standard_headers_indexer.c @@ -0,0 +1,75 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + */ + +// List of standard headers was taken in http://en.cppreference.com/w/c/header + +#include // Conditionally compiled macro that compares its argument to zero +#include // Functions to determine the type contained in character data +#include // Macros reporting error conditions +#include // Limits of float types +#include // Sizes of basic types +#include // Localization utilities +#include // Common mathematics functions +#include // Nonlocal jumps +#include // Signal handling +#include // Variable arguments +#include // Common macro definitions +#include // Input/output +#include // String handling +#include // General utilities: memory management, program utilities, string conversions, random numbers +#include // Time/date utilities +#include // (since C95) Alternative operator spellings +#include // (since C95) Extended multibyte and wide character utilities +#include // (since C95) Wide character classification and mapping utilities +#ifdef _STDC_C99 +#include // (since C99) Complex number arithmetic +#include // (since C99) Floating-point environment +#include // (since C99) Format conversion of integer types +#include // (since C99) Boolean type +#include // (since C99) Fixed-width integer types +#include // (since C99) Type-generic math (macros wrapping math.h and complex.h) +#endif +#ifdef _STDC_C11 +#include // (since C11) alignas and alignof convenience macros +#include // (since C11) Atomic types +#include // (since C11) noreturn convenience macros +#include // (since C11) Thread library +#include // (since C11) UTF-16 and UTF-32 character utilities +#endif diff --git b/nbproject/private/configurations.xml a/nbproject/private/configurations.xml new file mode 100644 index 0000000..30b54f8 --- /dev/null +++ a/nbproject/private/configurations.xml @@ -0,0 +1,72 @@ + + + Makefile + + + + localhost + 2 + + + + + + + + + + + + + + + gdb + + + + "${OUTPUT_PATH}" + + "${OUTPUT_PATH}" + + true + 0 + 0 + + + + + + + localhost + 2 + + + + + + + + + + + + + + + gdb + + + + "${OUTPUT_PATH}" + + "${OUTPUT_PATH}" + + true + 0 + 0 + + + + + + diff --git b/nbproject/private/cpp_standard_headers_indexer.cpp a/nbproject/private/cpp_standard_headers_indexer.cpp new file mode 100644 index 0000000..04f6fa6 --- /dev/null +++ a/nbproject/private/cpp_standard_headers_indexer.cpp @@ -0,0 +1,135 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + */ + +// List of standard headers was taken in http://en.cppreference.com/w/cpp/header + +#include // General purpose utilities: program control, dynamic memory allocation, random numbers, sort and search +#include // Functions and macro constants for signal management +#include // Macro (and function) that saves (and jumps) to an execution context +#include // Handling of variable length argument lists +#include // Runtime type information utilities +#include // std::bitset class template +#include // Function objects, designed for use with the standard algorithms +#include // Various utility components +#include // C-style time/date utilites +#include // typedefs for types such as size_t, NULL and others +#include // Low-level memory management utilities +#include // Higher level memory management utilities +#include // limits of integral types +#include // limits of float types +#include // standardized way to query properties of arithmetic types +#include // Exception handling utilities +#include // Standard exception objects +#include // Conditionally compiled macro that compares its argument to zero +#include // Macro containing the last error number +#include // functions to determine the type contained in character data +#include // functions for determining the type of wide character data +#include // various narrow character string handling functions +#include // various wide and multibyte string handling functions +#include // std::basic_string class template +#include // std::vector container +#include // std::deque container +#include // std::list container +#include // std::set and std::multiset associative containers +#include // std::map and std::multimap associative containers +#include // std::stack container adaptor +#include // std::queue and std::priority_queue container adaptors +#include // Algorithms that operate on containers +#include // Container iterators +#include // Common mathematics functions +#include // Complex number type +#include // Class for representing and manipulating arrays of values +#include // Numeric operations on values in containers +#include // forward declarations of all classes in the input/output library +#include // std::ios_base class, std::basic_ios class template and several typedefs +#include // std::basic_istream class template and several typedefs +#include // std::basic_ostream, std::basic_iostream class templates and several typedefs +#include // several standard stream objects +#include // std::basic_fstream, std::basic_ifstream, std::basic_ofstream class templates and several typedefs +#include // std::basic_stringstream, std::basic_istringstream, std::basic_ostringstream class templates and several typedefs +#include // std::strstream, std::istrstream, std::ostrstream(deprecated) +#include // Helper functions to control the format or input and output +#include // std::basic_streambuf class template +#include // C-style input-output functions +#include // Localization utilities +#include // C localization utilities +#include // empty header. The macros that appear in iso646.h in C are keywords in C++ +#if __cplusplus >= 201103L +#include // (since C++11) std::type_index +#include // (since C++11) Compile-time type information +#include // (since C++11) C++ time utilites +#include // (since C++11) std::initializer_list class template +#include // (since C++11) std::tuple class template +#include // (since C++11) Nested allocator class +#include // (since C++11) fixed-size types and limits of other types +#include // (since C++11) formatting macros , intmax_t and uintmax_t math and conversions +#include // (since C++11) defines std::error_code, a platform-dependent error code +#include // (since C++11) C-style Unicode character conversion functions +#include // (since C++11) std::array container +#include // (since C++11) std::forward_list container +#include // (since C++11) std::unordered_set and std::unordered_multiset unordered associative containers +#include // (since C++11) std::unordered_map and std::unordered_multimap unordered associative containers +#include // (since C++11) Random number generators and distributions +#include // (since C++11) Compile-time rational arithmetic +#include // (since C++11) Floating-point environment access functions +#include // (since C++11) Unicode conversion facilities +#include // (since C++11) Classes, algorithms and iterators to support regular expression processing +#include // (since C++11) Atomic operations library +#include // (since C++11)(deprecated in C++17) simply includes the header +#include // (since C++11)(deprecated in C++17) simply includes the headers (until C++17) (since C++17) and : the overloads equivalent to the contents of the C header tgmath.h are already provided by those headers +#include // (since C++11)(deprecated in C++17) defines one compatibility macro constant +#include // (since C++11)(deprecated in C++17) defines one compatibility macro constant +#include // (since C++11) std::thread class and supporting functions +#include // (since C++11) mutual exclusion primitives +#include // (since C++11) primitives for asynchronous computations +#include // (since C++11) thread waiting conditions +#endif +#if __cplusplus >= 201300L +#include // (since C++14) shared mutual exclusion primitives +#endif +#if __cplusplus >= 201500L +#include // (since C++17) std::any class template +#include // (since C++17) std::optional class template +#include // (since C++17) std::variant class template +#include // (since C++17) Polymorphic allocators and memory resources +#include // (since C++17) std::basic_string_view class template +#include // (since C++17) Predefined execution policies for parallel versions of the algorithms +#include // (since C++17) std::path class and supporting functions +#endif diff --git b/nbproject/private/launcher.properties a/nbproject/private/launcher.properties new file mode 100644 index 0000000..3edc2d8 --- /dev/null +++ a/nbproject/private/launcher.properties @@ -0,0 +1,42 @@ +# Launchers File syntax: +# +# [Must-have property line] +# launcher1.runCommand= +# [Optional extra properties] +# launcher1.displayName= +# launcher1.hide= +# launcher1.buildCommand= +# launcher1.runDir= +# launcher1.runInOwnTab= +# launcher1.symbolFiles= +# launcher1.env.= +# (If this value is quoted with ` it is handled as a native command which execution result will become the value) +# [Common launcher properties] +# common.runDir= +# (This value is overwritten by a launcher specific runDir value if the latter exists) +# common.env.= +# (Environment variables from common launcher are merged with launcher specific variables) +# common.symbolFiles= +# (This value is overwritten by a launcher specific symbolFiles value if the latter exists) +# +# In runDir, symbolFiles and env fields you can use these macroses: +# ${PROJECT_DIR} - project directory absolute path +# ${OUTPUT_PATH} - linker output path (relative to project directory path) +# ${OUTPUT_BASENAME}- linker output filename +# ${TESTDIR} - test files directory (relative to project directory path) +# ${OBJECTDIR} - object files directory (relative to project directory path) +# ${CND_DISTDIR} - distribution directory (relative to project directory path) +# ${CND_BUILDDIR} - build directory (relative to project directory path) +# ${CND_PLATFORM} - platform name +# ${CND_CONF} - configuration name +# ${CND_DLIB_EXT} - dynamic library extension +# +# All the project launchers must be listed in the file! +# +# launcher1.runCommand=... +# launcher2.runCommand=... +# ... +# common.runDir=... +# common.env.KEY=VALUE + +# launcher1.runCommand= \ No newline at end of file diff --git b/nbproject/private/private.xml a/nbproject/private/private.xml new file mode 100644 index 0000000..29fbbc9 --- /dev/null +++ a/nbproject/private/private.xml @@ -0,0 +1,15 @@ + + + + 1 + 0 + + + + + file:/home/pgroen/projects/serialport/Exception.hpp + file:/home/pgroen/projects/serialport/SerialPort.cpp + file:/home/pgroen/projects/serialport/main.cpp + + + diff --git b/nbproject/project.properties a/nbproject/project.properties new file mode 100644 index 0000000..bd89f3e --- /dev/null +++ a/nbproject/project.properties @@ -0,0 +1 @@ +#Tue May 24 23:09:12 CEST 2022 diff --git b/nbproject/project.xml a/nbproject/project.xml new file mode 100644 index 0000000..b6058c4 --- /dev/null +++ a/nbproject/project.xml @@ -0,0 +1,28 @@ + + + org.netbeans.modules.cnd.makeproject + + + SerPortTest + + cpp + hpp + UTF-8 + + + + + Debug + 1 + + + Release + 1 + + + + false + + + +