12#include "isobus/utility/system_timing.hpp"
13#include "isobus/utility/to_string.hpp"
20#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
39 messagesToBeTransmittedQueue(queueCapacity), receivedMessagesQueue(queueCapacity)
45#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
53 if (
nullptr != frameHandler)
56 if (frameHandler->get_is_valid())
58#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
69#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
72 if (
nullptr != frameHandler)
74 frameHandler =
nullptr;
76 messagesToBeTransmittedQueue.clear();
77 receivedMessagesQueue.clear();
83 if ((
nullptr != frameHandler) && frameHandler->get_is_valid() && frameHandler->write_frame(frame))
92 if ((
nullptr != frameHandler) && frameHandler->get_is_valid() && (!receivedMessagesQueue.is_full()))
95 if (frameHandler->read_frame(frame))
97 receivedMessagesQueue.push(frame);
104#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
112 receiveThreadRunning =
true;
113 if (
nullptr == receiveMessageThread)
115 receiveMessageThread.reset(
new std::thread([
this]() { receive_thread_function(); }));
121 receiveThreadRunning =
false;
122 if (
nullptr != receiveMessageThread)
124 if (receiveMessageThread->joinable())
126 receiveMessageThread->join();
128 receiveMessageThread =
nullptr;
134 while (receiveThreadRunning)
136 if ((
nullptr != frameHandler) && frameHandler->get_is_valid())
138 if (!receive_can_frame())
141 std::this_thread::yield();
150 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
167 LOG_ERROR(
"[HardwareInterface] Cannot set number of channels after interface is started.");
188 LOG_ERROR(
"[HardwareInterface] Cannot assign frame handlers after interface is started.");
194 LOG_ERROR(
"[HardwareInterface] Unable to set frame handler at channel " + to_string(channelIndex) +
195 ", because there are only " + to_string(
hardwareChannels.size()) +
" channels set. " +
196 "Use set_number_of_can_channels() to increase the number of channels before assigning frame handlers.");
202 LOG_ERROR(
"[HardwareInterface] Unable to set frame handler at channel " + to_string(channelIndex) +
", because it is already assigned.");
212 return static_cast<std::uint8_t
>(
hardwareChannels.size() & std::numeric_limits<std::uint8_t>::max());
221 LOG_ERROR(
"[HardwareInterface] Cannot remove frame handlers after interface is started.");
227 LOG_ERROR(
"[HardwareInterface] Unable to remove frame handler at channel " + to_string(channelIndex) +
228 ", because there are only " + to_string(
hardwareChannels.size()) +
" channels set.");
234 LOG_ERROR(
"[HardwareInterface] Unable to remove frame handler at channel " + to_string(channelIndex) +
", because it is not assigned.");
244 std::shared_ptr<CANHardwarePlugin> retVal;
257#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
272 LOG_ERROR(
"[HardwareInterface] Cannot stop interface before it is started.");
279#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
299 LOG_ERROR(
"[HardwareInterface] Cannot transmit message before interface is started.");
305 LOG_ERROR(
"[HardwareInterface] Cannot transmit message on channel " + to_string(frame.
channel) +
306 ", because there are only " + to_string(
hardwareChannels.size()) +
" channels set.");
311 if (
nullptr == channel->frameHandler)
313 LOG_ERROR(
"[HardwareInterface] Cannot transmit message on channel " + to_string(frame.
channel) +
", because it is not assigned.");
317 if (channel->frameHandler->get_is_valid())
319 channel->messagesToBeTransmittedQueue.push(frame);
320#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
362#if defined CAN_STACK_DISABLE_THREADS || defined ARDUINO
390 isobus::CANMessageFrame frame;
391 while (channel->messagesToBeTransmittedQueue.peek(frame))
393 if (channel->transmit_can_frame(frame))
395 frameTransmittedEventDispatcher.invoke(frame);
396 on_transmit_can_message_frame_from_hardware(frame);
397 channel->messagesToBeTransmittedQueue.pop();
409#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
414 hardwareLock.unlock();
418 std::unique_lock<std::mutex> threadLock(
updateMutex);
The hardware abstraction layer that separates the stack from the underlying CAN driver.
A class that acts as a logging sink. The intent is that someone could make their own derived class of...
Stores the data for a single CAN channel.
CANHardware(std::size_t queueCapacity)
Constructor for the CANHardware.
virtual ~CANHardware()
Destructor for the CANHardware.
void receive_thread_function()
The receiving thread loop for this CAN channel.
bool receive_can_frame()
Receives a frame from the hardware and adds it to the receive queue.
void start_threads()
Starts the receiving thread for this CAN channel.
bool stop()
Stops this hardware channel.
bool start()
Starts this hardware channel.
void stop_threads()
Stops the receiving thread for this CAN channel.
bool transmit_can_frame(const CANMessageFrame &frame) const
Try to transmit the frame to the hardware.
static bool stop()
Stops all CAN management threads and discards all remaining messages in the Tx and Rx queues.
static std::vector< std::unique_ptr< CANHardware > > hardwareChannels
A list of all CAN channel's metadata.
static EventDispatcher< const CANMessageFrame & > frameReceivedEventDispatcher
The event dispatcher for when a CAN message frame is received from hardware event.
static EventDispatcher< const CANMessageFrame & > frameTransmittedEventDispatcher
The event dispatcher for when a CAN message has been transmitted via hardware.
static std::uint8_t get_number_of_can_channels()
Returns the number of configured CAN channels that the class is managing.
static EventDispatcher< const CANMessageFrame & > & get_can_frame_received_event_dispatcher()
Get the event dispatcher for when a CAN message frame is received from hardware event.
static EventDispatcher periodicUpdateEventDispatcher
The event dispatcher for when a periodic update is called.
static Mutex updateMutex
A mutex for the main thread.
static std::uint32_t periodicUpdateInterval
The period between calls to the network manager update function in milliseconds.
static EventDispatcher & get_periodic_update_event_dispatcher()
Get the event dispatcher for when a periodic update is called.
static void stop_threads()
Stops all threads related to the hardware interface.
static bool started
Stores if the threads have been started.
static bool unassign_can_channel_frame_handler(std::uint8_t channelIndex)
Removes a CAN driver from a channel.
static void update()
Call this periodically if you have threads disabled.
static bool set_number_of_can_channels(std::uint8_t value, std::size_t queueCapacity=40)
Sets the number of CAN channels to manage.
static void start_threads()
Starts all threads related to the hardware interface.
static std::shared_ptr< CANHardwarePlugin > get_assigned_can_channel_frame_handler(std::uint8_t channelIndex)
Gets the CAN driver assigned to a channel.
static bool transmit_can_frame(const CANMessageFrame &frame)
Called externally, adds a message to a CAN channel's Tx queue.
static Mutex hardwareChannelsMutex
Mutex to protect hardwareChannels
static std::uint32_t lastUpdateTimestamp
The last time the network manager was updated.
static CANHardwareInterface SINGLETON
Singleton instance of the CANHardwareInterface class.
virtual ~CANHardwareInterface()
Deconstructor for the CANHardwareInterface class for stopping threads.
static std::uint32_t get_periodic_update_interval()
Get the interval between periodic updates to the network manager.
static EventDispatcher< const CANMessageFrame & > & get_can_frame_transmitted_event_dispatcher()
Get the event dispatcher for when a CAN message frame will be send to hardware event.
static bool is_running()
Checks if the CAN stack and CAN drivers are running.
static bool assign_can_channel_frame_handler(std::uint8_t channelIndex, std::shared_ptr< CANHardwarePlugin > canDriver)
Assigns a CAN driver to a channel.
static void update_thread_function()
The main thread loop for updating the stack.
static std::condition_variable updateThreadWakeupCondition
A condition variable to allow for signaling the updateThread to wakeup.
static std::unique_ptr< std::thread > updateThread
The main thread.
static void set_periodic_update_interval(std::uint32_t value)
Set the interval between periodic updates to the network manager.
static bool start()
Starts the threads for managing the CAN stack and CAN drivers.
A CAN frame for interfacing with a hardware layer, like socket CAN or other interface.
std::uint8_t channel
The CAN channel index associated with the frame.
This namespace encompasses all of the ISO11783 stack's functionality to reduce global namespace pollu...
bool send_can_message_frame_to_hardware(const CANMessageFrame &frame)
The sending abstraction layer between the hardware and the stack.
void periodic_update_from_hardware()
The periodic update abstraction layer between the hardware and the stack.
void receive_can_message_frame_from_hardware(const CANMessageFrame &frame)
The receiving abstraction layer between the hardware and the stack.