Lely core libraries 1.9.2
io_context.cpp
Go to the documentation of this file.
1
24#include "coapp.hpp"
25#include <lely/can/net.hpp>
26#include <lely/aio/detail/timespec.hpp>
28
29#include <mutex>
30
31namespace lely {
32
33namespace canopen {
34
35using namespace aio;
36
39 Impl_(IoContext* self, TimerBase& timer, CanBusBase& bus,
40 BasicLockable* mutex);
41
42 void
43 lock() override {
44 if (mutex) mutex->lock();
45 }
46 void
47 unlock() override {
48 if (mutex) mutex->unlock();
49 }
50
51 void operator()(::std::error_code ec) noexcept;
52 void operator()(::std::error_code ec, int result) noexcept;
53
54 int OnNext(const timespec* tp) noexcept;
55 int OnSend(const can_msg* msg) noexcept;
56
57 IoContext* self{nullptr};
58
59 TimerBase& timer;
60 TimerBase::WaitOperation wait_op;
61
62 CanBusBase& bus;
63 CanBusBase::Frame msg CAN_MSG_INIT;
64 CanBusBase::Info info CAN_MSG_INFO_INIT;
65 int state{0};
66 int error{0};
67 CanBusBase::ReadOperation read_op;
68
69 BasicLockable* mutex{nullptr};
70
71 unique_c_ptr<CANNet> net;
72};
73
74IoContext::IoContext(aio::TimerBase& timer, aio::CanBusBase& bus,
75 BasicLockable* mutex)
76 : impl_(new Impl_(this, timer, bus, mutex)) {}
77
78IoContext::~IoContext() = default;
79
80aio::ExecutorBase
81IoContext::GetExecutor() const noexcept {
82 return impl_->timer.GetExecutor();
83}
84
85CANNet*
86IoContext::net() const noexcept {
87 return impl_->net.get();
88}
89
90void
92 net()->setTime(aio::detail::ToTimespec(impl_->timer.GetClock().GetTime()));
93}
94
95IoContext::Impl_::Impl_(IoContext* self_, TimerBase& timer_, CanBusBase& bus_,
96 BasicLockable* mutex_)
97 : self(self_),
98 timer(timer_),
99 wait_op(::std::ref(*this)),
100 bus(bus_),
101 read_op(&msg, &info, ::std::ref(*this)),
102 mutex(mutex_),
103 net(make_unique_c<CANNet>()) {
104 // Initialize the CAN network clock with the current time.
105 net->setTime(aio::detail::ToTimespec(timer.GetClock().GetTime()));
106
107 // Register the OnNext() member function as the function to be invoked when
108 // the time at which the next timer triggers is updated.
109 net->setNextFunc<Impl_, &Impl_::OnNext>(this);
110 // Register the OnSend() member function as the function to be invoked when a
111 // CAN frame needs to be sent.
112 net->setSendFunc<Impl_, &Impl_::OnSend>(this);
113
114 // Start waiting for timeouts.
115 timer.SubmitWait(wait_op);
116
117 // Start receiving CAN frames.
118 bus.SubmitRead(read_op);
119}
120
121void
122IoContext::Impl_::operator()(::std::error_code ec) noexcept {
123 if (!ec) {
124 ::std::lock_guard<Impl_> lock(*this);
125 self->SetTime();
126 }
127 timer.SubmitWait(wait_op);
128}
129
130void
131IoContext::Impl_::operator()(::std::error_code ec, int result) noexcept {
132 if (!ec) {
133 ::std::lock_guard<Impl_> lock(*this);
134 if (result == 1) {
135 net->recv(msg);
136 } else if (!result) {
137 if (info.state != state) {
138 ::std::swap(info.state, state);
139 self->OnCanState(static_cast<CanState>(state),
140 static_cast<CanState>(info.state));
141 }
142 if (info.error != error) {
143 error = info.error;
144 self->OnCanError(static_cast<CanError>(error));
145 }
146 }
147 }
148 bus.SubmitRead(read_op);
149}
150
151int
152IoContext::Impl_::OnNext(const timespec* tp) noexcept {
153 timer.SetTime(TimerBase::time_point(aio::detail::FromTimespec(*tp)));
154 return 0;
155}
156
157int
158IoContext::Impl_::OnSend(const can_msg* msg) noexcept {
159 // The CAN network interface does not support asynchronous writes, so we try a
160 // non-blocking synchronous write.
161 ::std::error_code ec;
162 if (!bus.Write(*msg, ec)) {
163 if (ec) set_errc(ec.value());
164 return -1;
165 }
166 return 0;
167}
168
169} // namespace canopen
170
171} // namespace lely
An opaque CAN network interface type.
Definition: net.hpp:83
An abstract interface conforming to the BasicLockable concept.
Definition: coapp.hpp:40
virtual void unlock()=0
Releases the lock held by the execution agent. Throws no exceptions.
virtual void lock()=0
Blocks until a lock can be obtained for the current execution agent (thread, process,...
The I/O context.
Definition: io_context.hpp:42
IoContext(aio::TimerBase &timer, aio::CanBusBase &bus, BasicLockable *mutex=nullptr)
Creates a new I/O context.
Definition: io_context.cpp:74
void SetTime()
Update the CAN network time.
Definition: io_context.cpp:91
CANNet * net() const noexcept
Returns a pointer to the internal CAN network interface from <lely/can/net.hpp>.
Definition: io_context.cpp:86
aio::ExecutorBase GetExecutor() const noexcept
Returns the executor used to process I/O events on the CAN bus.
Definition: io_context.cpp:81
The type of objects thrown as exceptions to report a system error with an associated error code.
Definition: exception.hpp:54
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
Definition: errnum.c:957
This header file is part of the C++ CANopen application library; it contains the I/O context declarat...
Global namespace for the Lely Industries N.V. libraries.
Definition: buf.hpp:32
unique_c_ptr< T > make_unique_c(Args &&... args)
Creates an instance of a trivial, standard layout or incomplete C type and wraps it in a lely::unique...
Definition: c_type.hpp:111
STL namespace.
This header file is part of the CAN library; it contains the C++ interface of the CAN network interfa...
This is the internal header file of the C++ CANopen application library.
A CAN or CAN FD format frame.
Definition: msg.h:88
The internal implementation of the I/O context.
Definition: io_context.cpp:38
void unlock() override
Releases the lock held by the execution agent. Throws no exceptions.
Definition: io_context.cpp:47
void lock() override
Blocks until a lock can be obtained for the current execution agent (thread, process,...
Definition: io_context.cpp:43
A time type with nanosecond resolution.
Definition: time.h:83