2#include <ossia/network/sockets/configuration.hpp>
3#include <ossia/network/sockets/writers.hpp>
5#include <boost/asio/io_context.hpp>
6#include <boost/asio/placeholders.hpp>
7#include <boost/asio/post.hpp>
8#include <boost/asio/serial_port.hpp>
9#include <boost/asio/write.hpp>
11#include <nano_signal_slot.hpp>
13#include <linux/serial.h>
14#include <linux/tty_flags.h>
18#elif defined(__APPLE__)
25template <
typename Framing>
29 using proto = boost::asio::serial_port;
30 using socket = boost::asio::serial_port;
31 using encoder =
typename Framing::template encoder<boost::asio::serial_port>;
32 using decoder =
typename Framing::template decoder<boost::asio::serial_port>;
34 serial_socket(
const serial_configuration& conf, boost::asio::io_context& ctx)
36 , m_conf{std::move(conf)}
38 , m_encoder{this->m_port}
39 , m_decoder{this->m_port}
43 int set_custom_baud_rate(
int rate)
47 auto fd = m_port.native_handle();
48 struct serial_struct serinfo;
49 memset(&serinfo, 0,
sizeof(serinfo));
52 if(ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
56 if(serinfo.baud_base == 0)
60 serinfo.flags &= ~ASYNC_SPD_MASK;
61 serinfo.flags |= ASYNC_SPD_CUST;
62 serinfo.custom_divisor = (serinfo.baud_base + (rate / 2)) / rate;
63 if(serinfo.custom_divisor < 1)
65 serinfo.baud_base = rate;
66 serinfo.custom_divisor = 1;
70 if(ioctl(fd, TIOCSSERIAL, &serinfo) < 0)
72 if(ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
75 fcntl(fd, F_SETFL, 0);
78 struct termios options;
79 tcgetattr(fd, &options);
80 cfsetispeed(&options, B38400);
81 cfsetospeed(&options, B38400);
83 options.c_cflag |= (CLOCAL | CREAD);
84 options.c_cflag &= ~CRTSCTS;
85 if(tcsetattr(fd, TCSANOW, &options) != 0)
88#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) \
89 || defined(__OpenBSD__) || defined(__DragonFly__)
90 auto fd = m_port.native_handle();
91#define IOSSIOSPEED _IOW('T', 2, speed_t)
92 if(ioctl(fd, IOSSIOSPEED, &rate, 1) < 0)
102 m_port.open(m_conf.port);
106 m_port.set_option(proto::baud_rate(m_conf.baud_rate));
110 m_port.set_option(proto::baud_rate(38400));
112 int new_baud =
static_cast<int>(m_conf.baud_rate);
113 set_custom_baud_rate(new_baud);
115 m_port.set_option(proto::character_size(m_conf.character_size));
116 m_port.set_option(proto::flow_control(
117 static_cast<proto::flow_control::type
>(m_conf.flow_control)));
118 m_port.set_option(proto::parity(
static_cast<proto::parity::type
>(m_conf.parity)));
120 proto::stop_bits(
static_cast<proto::stop_bits::type
>(m_conf.stop_bits)));
122 boost::asio::post(m_context, [
this] { on_open(); });
125 template <
typename F>
128 struct proc : stream_processor<serial_socket, F>
131 m_decoder.receive(proc{*
this, std::move(f)});
139 boost::asio::post(m_context, [
this] {
146 void write(
const char* data, std::size_t sz) { m_encoder.write(data, sz); }
148 bool connected() const noexcept {
return true; }
150 Nano::Signal<void()> on_open;
151 Nano::Signal<void()> on_close;
152 Nano::Signal<void()> on_fail;
154 boost::asio::io_context& m_context;
155 serial_configuration m_conf;
156 boost::asio::serial_port m_port;