39 #ifndef LELY_IO_VCAN_BITRATE 40 #define LELY_IO_VCAN_BITRATE 1000000 44 #ifndef LELY_IO_VCAN_RXLEN 49 #define LELY_IO_VCAN_RXLEN 1024 64 static int io_vcan_ctrl_get_bitrate(
66 static int io_vcan_ctrl_set_bitrate(
io_can_ctrl_t *ctrl,
int nominal,
int data);
72 &io_vcan_ctrl_stopped,
73 &io_vcan_ctrl_restart,
74 &io_vcan_ctrl_get_bitrate,
75 &io_vcan_ctrl_set_bitrate,
76 &io_vcan_ctrl_get_state
115 static inline struct io_vcan_ctrl *io_vcan_ctrl_from_ctrl(
121 static void io_vcan_ctrl_signal(
struct spscring *ring,
void *arg);
127 static void io_vcan_ctrl_do_stop(
struct io_vcan_ctrl *vcan_ctrl);
131 static size_t io_vcan_chan_dev_cancel(
io_dev_t *dev,
struct ev_task *task);
132 static size_t io_vcan_chan_dev_abort(
io_dev_t *dev,
struct ev_task *task);
135 static const struct io_dev_vtbl io_vcan_chan_dev_vtbl = {
136 &io_vcan_chan_dev_get_ctx,
137 &io_vcan_chan_dev_get_exec,
138 &io_vcan_chan_dev_cancel,
139 &io_vcan_chan_dev_abort
144 static int io_vcan_chan_get_flags(
const io_can_chan_t *chan);
146 struct can_err *err,
struct timespec *tp,
int timeout);
147 static void io_vcan_chan_submit_read(
149 static int io_vcan_chan_write(
151 static void io_vcan_chan_submit_write(
156 &io_vcan_chan_get_dev,
157 &io_vcan_chan_get_flags,
159 &io_vcan_chan_submit_read,
161 &io_vcan_chan_submit_write
165 static void io_vcan_chan_svc_shutdown(
struct io_svc *svc);
168 static const struct io_svc_vtbl io_vcan_chan_svc_vtbl = {
170 &io_vcan_chan_svc_shutdown
232 static void io_vcan_chan_read_task_func(
struct ev_task *task);
233 static void io_vcan_chan_write_task_func(
struct ev_task *task);
236 static inline struct io_vcan_chan *io_vcan_chan_from_chan(
238 static inline struct io_vcan_chan *io_vcan_chan_from_svc(
241 static void io_vcan_chan_signal(
struct spscring *ring,
void *arg);
243 static void io_vcan_chan_do_pop(
struct io_vcan_chan *vcan,
247 static size_t io_vcan_chan_do_abort_tasks(
struct io_vcan_chan *vcan);
250 io_vcan_ctrl_alloc(
void)
262 io_vcan_ctrl_free(
void *ptr)
265 free(io_vcan_ctrl_from_ctrl(ptr));
272 struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
298 goto error_init_cond;
328 struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
342 io_clock_t *clock,
int flags,
int nominal,
int data,
int state)
353 ctrl, clock, flags, nominal, data, state);
363 io_vcan_ctrl_free((
void *)ctrl);
373 io_vcan_ctrl_fini(ctrl);
374 io_vcan_ctrl_free((
void *)ctrl);
381 struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
390 io_vcan_ctrl_do_stop(vcan);
411 return io_vcan_ctrl_write(ctrl, NULL, msg, NULL, timeout);
418 return io_vcan_ctrl_write(ctrl, NULL, NULL, err, timeout);
422 io_vcan_chan_alloc(
void)
434 io_vcan_chan_free(
void *ptr)
437 free(io_vcan_chan_from_chan(ptr));
444 struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
453 vcan->
dev_vptr = &io_vcan_chan_dev_vtbl;
456 vcan->
svc = (
struct io_svc)IO_SVC_INIT(&io_vcan_chan_svc_vtbl);
462 vcan->exec, &io_vcan_chan_read_task_func);
463 vcan->write_task = (
struct ev_task)EV_TASK_INIT(
464 vcan->exec, &io_vcan_chan_write_task_func);
470 goto error_alloc_rxbuf;
481 goto error_init_cond;
490 vcan->read_posted = 0;
491 vcan->write_posted = 0;
495 vcan->current_write = NULL;
516 struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
523 io_vcan_chan_svc_shutdown(&vcan->
svc);
535 if (io_vcan_chan_do_abort_tasks(vcan))
541 "io_vcan_chan_fini() invoked with pending operations");
566 io_can_chan_t *tmp = io_vcan_chan_init(chan, ctx, exec, rxlen);
576 io_vcan_chan_free((
void *)chan);
586 io_vcan_chan_fini(chan);
587 io_vcan_chan_free((
void *)chan);
594 const struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
612 io_vcan_ctrl_insert(ctrl, chan);
626 io_vcan_ctrl_remove(ctrl, chan);
632 struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
637 io_vcan_ctrl_do_stop(vcan);
648 const struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
664 struct io_vcan_ctrl *vcan_ctrl = io_vcan_ctrl_from_ctrl(ctrl);
703 io_vcan_ctrl_get_bitrate(
const io_can_ctrl_t *ctrl,
int *pnominal,
int *pdata)
705 const struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
722 io_vcan_ctrl_set_bitrate(
io_can_ctrl_t *ctrl,
int nominal,
int data)
724 struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
729 io_vcan_ctrl_do_stop(vcan);
747 const struct io_vcan_ctrl *vcan = io_vcan_ctrl_from_ctrl(ctrl);
752 int state = vcan->
state;
771 struct io_vcan_ctrl *vcan_ctrl = io_vcan_ctrl_from_ctrl(ctrl);
772 struct io_vcan_chan *vcan_chan = io_vcan_chan_from_chan(chan);
794 struct io_vcan_ctrl *vcan_ctrl = io_vcan_ctrl_from_ctrl(ctrl);
795 struct io_vcan_chan *vcan_chan = io_vcan_chan_from_chan(chan);
797 struct sllist read_queue, write_queue;
810 vcan_chan->
ctrl = NULL;
828 io_vcan_ctrl_signal(
struct spscring *ring,
void *arg)
865 struct io_vcan_ctrl *vcan_ctrl = io_vcan_ctrl_from_ctrl(ctrl);
866 assert(!msg || !err);
871 struct timespec ts = { 0, 0 };
893 if ((flags & vcan_ctrl->
flags) != flags) {
926 if (chan && chan == &vcan_chan->
chan_vptr)
945 &io_vcan_ctrl_signal, vcan_ctrl))
964 &vcan_ctrl->
cond, &vcan_ctrl->
mtx, &ts);
995 if (chan && chan == &vcan_chan->
chan_vptr)
1005 .is_err = 0, .u.msg = *msg, .ts = ts
1009 .is_err = 1, .u.err = *err, .ts = ts
1014 #if !LELY_NO_THREADS 1029 struct sllist read_queue, write_queue;
1036 #if !LELY_NO_THREADS 1044 #if !LELY_NO_THREADS 1054 io_vcan_chan_dev_get_ctx(
const io_dev_t *dev)
1056 const struct io_vcan_chan *vcan = io_vcan_chan_from_dev(dev);
1062 io_vcan_chan_dev_get_exec(
const io_dev_t *dev)
1064 const struct io_vcan_chan *vcan = io_vcan_chan_from_dev(dev);
1072 struct io_vcan_chan *vcan = io_vcan_chan_from_dev(dev);
1076 struct sllist read_queue, write_queue;
1080 #if !LELY_NO_THREADS 1083 io_vcan_chan_do_pop(vcan, &read_queue, &write_queue, task);
1089 #if !LELY_NO_THREADS 1093 size_t nread = io_can_chan_read_queue_post(
1095 n = n < SIZE_MAX - nread ? n + nread : SIZE_MAX;
1096 size_t nwrite = io_can_chan_write_queue_post(
1098 n = n < SIZE_MAX - nwrite ? n + nwrite : SIZE_MAX;
1106 struct io_vcan_chan *vcan = io_vcan_chan_from_dev(dev);
1111 #if !LELY_NO_THREADS 1114 io_vcan_chan_do_pop(vcan, &queue, &queue, task);
1115 #if !LELY_NO_THREADS 1125 const struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
1133 const struct io_vcan_chan *vcan_chan = io_vcan_chan_from_chan(chan);
1135 io_vcan_ctrl_from_ctrl(vcan_chan->
ctrl);
1137 return vcan_ctrl->
flags;
1142 struct timespec *tp,
int timeout)
1144 struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
1146 #if !LELY_NO_THREADS 1148 struct timespec ts = { 0, 0 };
1161 #if !LELY_NO_THREADS 1174 #if !LELY_NO_THREADS 1183 #if !LELY_NO_THREADS 1194 &io_vcan_chan_signal, vcan))
1202 #if !LELY_NO_THREADS 1208 #if !LELY_NO_THREADS 1210 #if !LELY_NO_TIMEOUT 1218 #if !LELY_NO_TIMEOUT 1228 int is_err = frame->is_err;
1230 *msg = frame->u.msg;
1231 else if (is_err && err)
1232 *err = frame->u.err;
1236 #if !LELY_NO_THREADS 1246 struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
1254 #if !LELY_NO_THREADS 1258 #if !LELY_NO_THREADS 1262 }
else if (!vcan->
ctrl) {
1263 #if !LELY_NO_THREADS 1268 #if !LELY_NO_THREADS 1278 #if !LELY_NO_THREADS 1295 return io_vcan_ctrl_write(ctrl, chan, msg, NULL, timeout);
1301 struct io_vcan_chan *vcan = io_vcan_chan_from_chan(chan);
1309 #if !LELY_NO_THREADS 1313 #if !LELY_NO_THREADS 1317 }
else if (!vcan->
ctrl) {
1318 #if !LELY_NO_THREADS 1323 #if !LELY_NO_THREADS 1333 #if !LELY_NO_THREADS 1343 io_vcan_chan_svc_shutdown(
struct io_svc *svc)
1345 struct io_vcan_chan *vcan = io_vcan_chan_from_svc(svc);
1348 #if !LELY_NO_THREADS 1356 io_vcan_chan_do_abort_tasks(vcan);
1357 #if !LELY_NO_THREADS 1363 io_vcan_chan_dev_cancel(dev, NULL);
1367 io_vcan_chan_read_task_func(
struct ev_task *task)
1373 #if !LELY_NO_THREADS 1387 io_vcan_chan_signal, vcan))
1397 if (!frame->is_err && read->
msg)
1398 *read->
msg = frame->u.msg;
1399 if (frame->is_err && read->
err)
1400 *read->
err = frame->u.err;
1402 *read->
tp = frame->ts;
1403 io_can_chan_read_post(read, !frame->is_err, 0);
1407 #if !LELY_NO_THREADS 1413 io_vcan_chan_write_task_func(
struct ev_task *task)
1424 #if !LELY_NO_THREADS 1432 #if !LELY_NO_THREADS 1436 int result = io_vcan_chan_write(
1438 int errc = !result ? 0 :
get_errc();
1443 io_can_chan_write_post(write, errc);
1444 #if !LELY_NO_THREADS 1467 #if !LELY_NO_THREADS 1471 if (task && wouldblock)
1484 io_vcan_chan_from_dev(
const io_dev_t *dev)
1500 io_vcan_chan_from_svc(
const struct io_svc *svc)
1508 io_vcan_chan_signal(
struct spscring *ring,
void *arg)
1514 #if !LELY_NO_THREADS 1520 #if !LELY_NO_THREADS 1535 assert(write_queue);
void ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
A CAN or CAN FD format frame.
struct can_err * err
The address at which to store the CAN error frame.
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
unsigned shutdown
A flag indicating whether the I/O service has been shut down.
int spscring_c_abort_wait(struct spscring *ring)
Aborts a wait operation previously registered with spscring_c_submit_wait().
A CAN channel read operation.
int nominal
The nominal bitrate.
size_t spscring_p_commit(struct spscring *ring, size_t size)
Makes the specified number of indices available to a consumer and, if this satisfies a wait operation...
This header file is part of the I/O library; it contains the I/O context and service declarations...
This header file is part of the utilities library; it contains the single-producer, single-consumer ring buffer declarations.
int spscring_c_submit_wait(struct spscring *ring, size_t size, void(*func)(struct spscring *ring, void *arg), void *arg)
Checks if the requested range of indices, including wrapping, in a single-producer, single-consumer ring buffer is available for reading and, if not, registers a signal function to be invoked once the requested range becomes available.
int io_vcan_chan_is_open(const io_can_chan_t *chan)
Returns 1 if the CAN channel is open and 0 if not.
struct ev_task read_task
The task responsible for initiating read operations.
ev_exec_t * exec
A pointer to the executor used to execute all I/O tasks.
size_t ev_task_queue_abort(struct sllist *queue)
Aborts the tasks in queue by invoking ev_exec_on_task_fini() for each of them.
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
void sllist_push_front(struct sllist *list, struct slnode *node)
Pushes a node to the front of a singly-linked list.
#define sllist_foreach(list, node)
Iterates in order over each node in a singly-linked list.
Indicates that the time specified in the call was reached without acquiring the requested resource...
const struct io_dev_vtbl * dev_vptr
A pointer to the virtual table for the I/O device interface.
void io_vcan_chan_open(io_can_chan_t *chan, io_can_ctrl_t *ctrl)
Opens a virtual CAN channel by registering it with the specified virtual CAN controller.
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
Indicates that the requested operation succeeded.
int timespec_get(struct timespec *ts, int base)
Sets the interval at ts to hold the current calendar time based on the specified time base...
size_t ev_exec_abort(ev_exec_t *exec, struct ev_task *task)
Aborts the specified task submitted to *exec, if it has not yet begun executing, or all pending tasks...
void io_ctx_insert(io_ctx_t *ctx, struct io_svc *svc)
Registers an I/O service with an I/O context.
A node in a singly-linked list.
cnd_t cond
The condition variable used to wake up blocked synchronous read operations.
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
struct sllist * sllist_append(struct sllist *dst, struct sllist *src)
Appends the singly-linked list at src to the one at dst.
const struct io_can_ctrl_vtbl * ctrl_vptr
A pointer to the virtual table for the CAN controller interface.
unsigned read_posted
A flag indicating whether read_task has been posted to exec.
struct slnode * sllist_first(const struct sllist *list)
Returns a pointer to the first node in a singly-linked list.
This is the internal header file of the CAN bus operation queue functions.
const struct io_clock_vtbl *const io_clock_t
An abstract clock.
unsigned write_posted
A flag indicating whether write_task has been posted to exec.
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
mtx_t mtx
The mutex protecting the channel and the queues of pending operations.
A mutex type that supports neither timeout nor test and return.
struct sllist read_queue
The queue containing pending read operations.
struct io_svc svc
The I/O service representing the channel.
#define LELY_IO_VCAN_BITRATE
The default bitrate of a virtual CAN bus.
struct ev_task write_task
The task responsible for initiating write operations.
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
This header file is part of the I/O library; it contains the virtual CAN bus declarations.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
This header file is part of the C11 and POSIX compatibility library; it includes <threads.h>, if it exists, and defines any missing functionality.
FD Format (formerly Extended Data Length) support is enabled.
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
A CAN channel write operation.
Bit Rate Switch support is enabled.
const struct io_can_chan_vtbl *const io_can_chan_t
An abstract CAN channel.
pthread_cond_t cnd_t
A complete object type that holds an identifier for a condition variable.
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
io_can_ctrl_t * ctrl
A pointer to the virtual CAN controller with which this channel is registered.
This header file is part of the utilities library; it contains the time function declarations.
#define LELY_IO_VCAN_RXLEN
The default receive queue length (in number of CAN frames) of a vritual CAN channel.
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the read operation.
void io_vcan_chan_close(io_can_chan_t *chan)
Closes a virtual CAN channel.
int cnd_init(cnd_t *cond)
Creates a condition variable.
const struct io_can_chan_vtbl * chan_vptr
A pointer to the virtual table for the CAN channel interface.
io_can_ctrl_t * io_vcan_chan_get_ctrl(const io_can_chan_t *chan)
Returns a pointer to the virtual CAN controller with which a virtual CAN channel is registered...
size_t spscring_p_alloc(struct spscring *ring, size_t *psize)
Allocates a consecutive range of indices, including wrapping, in a single-producer, single-consumer ring buffer for writing.
void io_vcan_ctrl_set_state(io_can_ctrl_t *ctrl, int state)
Sets the state of a virtual CAN bus: one of CAN_STATE_ACTIVE, CAN_STATE_PASSIVE, CAN_STATE_BUSOFF, CAN_STATE_SLEEPING or CAN_STATE_STOPPED.
void ev_exec_on_task_init(ev_exec_t *exec)
Indicates to the specified executor that a task will be submitted for execution in the future...
size_t spscring_c_alloc(struct spscring *ring, size_t *psize)
Allocates a consecutive range of indices, including wrapping, in a single-producer, single-consumer ring buffer for reading.
struct io_can_chan_read * io_can_chan_read_from_task(struct ev_task *task)
Obtains a pointer to a CAN channel read operation from a pointer to its completion task...
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function...
int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
Atomically unlocks the mutex at mtx and endeavors to block until the condition variable at cond is si...
Resource unavailable, try again.
void thrd_yield(void)
Endeavors to permit other threads to run, even if the current thread would ordinarily continue to run...
The FD Format (FDF) flag, formerly known as Extended Data Length (EDL).
void spscring_init(struct spscring *ring, size_t size)
Initializes a single-producer, single-consumer ring buffer with the specified size.
struct spscring rxring
The ring buffer used to control the receive queue.
unsigned stopped
A flag indicating the virtual CAN controller is stopped.
int spscring_p_submit_wait(struct spscring *ring, size_t size, void(*func)(struct spscring *ring, void *arg), void *arg)
Checks if the requested range of indices, including wrapping, in a single-producer, single-consumer ring buffer is available for writing and, if not, registers a signal function to be invoked once the requested range becomes available.
int flags
The flags specifying which CAN bus features are enabled.
void slnode_init(struct slnode *node)
Initializes a node in a singly-linked list.
struct sllist write_queue
The queue containing pending write operations.
const struct can_msg * msg
A pointer to the CAN frame to be written.
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
int io_vcan_ctrl_write_msg(io_can_ctrl_t *ctrl, const struct can_msg *msg, int timeout)
Writes a CAN frame to a all virtual CAN channels registered with a virtual CAN controller.
This header file is part of the utilities library; it contains the diagnostic declarations.
int state
The state of the CAN node (one of CAN_STATE_ACTIVE, CAN_STATE_PASSIVE or CAN_STATE_BUSOFF).
struct slnode node
The node of the channel in the list of the virtual CAN controller.
int cnd_wait(cnd_t *cond, mtx_t *mtx)
Atomically unlocks the mutex at mtx and endeavors to block until the condition variable at cond is si...
Reception of error frames is enabled.
void io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
Unregisters an I/O service with an I/O context.
This header file is part of the C11 and POSIX compatibility library; it includes <stdint.h> and defines any missing functionality.
A single-producer, single-consumer ring buffer.
uint_least8_t flags
The flags (any combination of CAN_FLAG_IDE, CAN_FLAG_RTR, CAN_FLAG_FDF, CAN_FLAG_BRS and CAN_FLAG_ESI...
io_ctx_t * ctx
A pointer to the I/O context with which the channel is registered.
int spscring_p_abort_wait(struct spscring *ring)
Aborts a wait operation previously registered with spscring_p_submit_wait().
struct ev_task * current_write
The write operation currently being executed.
io_can_ctrl_t * io_vcan_ctrl_create(io_clock_t *clock, int flags, int nominal, int data, int state)
Creates a new virtual CAN controller.
struct io_vcan_frame * rxbuf
The receive queue.
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
io_clock_t * clock
A pointer to the clock used to obtain the timestamp when sending CAN frames.
struct can_msg * msg
The address at which to store the CAN frame.
mtx_t mtx
The mutex protecting the controller and the list of virtual CAN channels.
The virtual table of an I/O service.
int state
The state of the virtual CAN bus.
void cnd_destroy(cnd_t *cond)
Releases all resources used by the condition variable at cond.
int data
The data bitrate.
struct ev_task * ev_task_from_node(struct slnode *node)
Converts a pointer to a node in a queue to the address of the task containing the node...
cnd_t cond
The condition variable used to wake up blocked synchronous write operations.
struct sllist list
The list of registered virtual CAN channels.
The implementation of a virtual CAN channel.
const struct io_can_ctrl_vtbl *const io_can_ctrl_t
An abstract CAN controller.
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib.h> and defines any missing functionality.
void sllist_init(struct sllist *list)
Initializes a singly-linked list.
void timespec_add_msec(struct timespec *tp, uint_least64_t msec)
Adds msec milliseconds to the time at tp.
int io_vcan_ctrl_write_err(io_can_ctrl_t *ctrl, const struct can_err *err, int timeout)
Writes a CAN error frame to a all virtual CAN channels registered with a virtual CAN controller...
size_t spscring_c_commit(struct spscring *ring, size_t size)
Makes the specified number of indices available to a producer and, if this satisfies a wait operation...
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the write operation.
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
void io_vcan_chan_destroy(io_can_chan_t *chan)
Destroys a virtual CAN channel.
struct io_can_chan_write * io_can_chan_write_from_task(struct ev_task *task)
Obtains a pointer to a CAN channel write operation from a pointer to its completion task...
io_can_chan_t * io_vcan_chan_create(io_ctx_t *ctx, ev_exec_t *exec, size_t rxlen)
Creates a new virtual CAN channel.
int io_clock_gettime(const io_clock_t *clock, struct timespec *tp)
Obtains the current time value of the specified clock.
struct timespec * tp
The address at which to store the system time at which the CAN frame or CAN error frame was received...
The implementation of a virtual CAN controller.
void io_vcan_ctrl_destroy(io_can_ctrl_t *ctrl)
Destroys a virtual CAN controller.
This is the public header file of the utilities library.
int stopped
A flag indicating whether the controller is stopped.
int cnd_broadcast(cnd_t *cond)
Unblocks all of the threads that are blocked on the condition variable at cond at the time of the cal...
int mtx_init(mtx_t *mtx, int type)
Creates a mutex object with properties indicated by type, which must have one of the four values: ...
The error active state (TX/RX error count < 128).
The Bit Rate Switch (BRS) flag (only available in CAN FD format frames).