39 #ifndef LELY_IO_USER_CAN_RXLEN
44 #define LELY_IO_USER_CAN_RXLEN 1024
58 static size_t io_user_can_chan_dev_cancel(
io_dev_t *dev,
struct ev_task *task);
59 static size_t io_user_can_chan_dev_abort(
io_dev_t *dev,
struct ev_task *task);
62 static const struct io_dev_vtbl io_user_can_chan_dev_vtbl = {
63 &io_user_can_chan_dev_get_ctx,
64 &io_user_can_chan_dev_get_exec,
65 &io_user_can_chan_dev_cancel,
66 &io_user_can_chan_dev_abort
71 static int io_user_can_chan_get_flags(
const io_can_chan_t *chan);
73 struct can_err *err,
struct timespec *tp,
int timeout);
74 static void io_user_can_chan_submit_read(
76 static int io_user_can_chan_write(
78 static void io_user_can_chan_submit_write(
83 &io_user_can_chan_get_dev,
84 &io_user_can_chan_get_flags,
85 &io_user_can_chan_read,
86 &io_user_can_chan_submit_read,
87 &io_user_can_chan_write,
88 &io_user_can_chan_submit_write
92 static void io_user_can_chan_svc_shutdown(
struct io_svc *svc);
95 static const struct io_svc_vtbl io_user_can_chan_svc_vtbl = {
97 &io_user_can_chan_svc_shutdown
170 static void io_user_can_chan_read_task_func(
struct ev_task *task);
171 static void io_user_can_chan_write_task_func(
struct ev_task *task);
183 static void io_user_can_chan_p_signal(
struct spscring *ring,
void *
arg);
184 static void io_user_can_chan_c_signal(
struct spscring *ring,
void *
arg);
190 static size_t io_user_can_chan_do_abort_tasks(
struct io_user_can_chan *user);
193 io_user_can_chan_alloc(
void)
203 io_user_can_chan_free(
void *ptr)
206 free(io_user_can_chan_from_chan(ptr));
218 if (
flags & ~IO_CAN_BUS_FLAG_MASK) {
231 user->
dev_vptr = &io_user_can_chan_dev_vtbl;
232 user->
chan_vptr = &io_user_can_chan_vtbl;
246 user->
exec, &io_user_can_chan_read_task_func);
248 user->
exec, &io_user_can_chan_write_task_func);
253 goto error_init_p_mtx;
258 goto error_init_p_cond;
263 goto error_init_c_mtx;
268 goto error_init_c_cond;
276 goto error_alloc_rxbuf;
326 io_user_can_chan_svc_shutdown(&user->
svc);
340 if (io_user_can_chan_do_abort_tasks(user))
346 "io_user_can_chan_fini() invoked with pending operations");
389 io_user_can_chan_free((
void *)chan);
399 io_user_can_chan_fini(chan);
400 io_user_can_chan_free((
void *)chan);
406 const struct timespec *tp,
int timeout)
425 .ts = tp ? *tp : (
struct timespec){ 0, 0 } };
426 return io_user_can_chan_on_frame(user, &frame, timeout);
431 const struct timespec *tp,
int timeout)
443 .ts = tp ? *tp : (
struct timespec){ 0, 0 } };
444 return io_user_can_chan_on_frame(user, &frame, timeout);
448 io_user_can_chan_dev_get_ctx(
const io_dev_t *dev)
456 io_user_can_chan_dev_get_exec(
const io_dev_t *dev)
470 struct sllist read_queue, write_queue;
485 io_user_can_chan_do_pop(user, &read_queue, &write_queue, task);
490 size_t nread = io_can_chan_read_queue_post(
492 n = n < SIZE_MAX - nread ? n + nread : SIZE_MAX;
493 size_t nwrite = io_can_chan_write_queue_post(
495 n = n < SIZE_MAX - nwrite ? n + nwrite : SIZE_MAX;
511 io_user_can_chan_do_pop(user, &queue, &queue, task);
537 struct can_err *err,
struct timespec *tp,
int timeout)
543 struct timespec ts = { 0, 0 };
576 &io_user_can_chan_c_signal, user))
604 int is_err = frame->is_err;
607 else if (is_err && err)
654 io_user_can_chan_write(
677 return user->
func(msg, timeout, user->
arg);
681 io_user_can_chan_submit_write(
709 }
else if ((flags & user->
flags) != flags) {
715 }
else if (!user->
func) {
736 io_user_can_chan_svc_shutdown(
struct io_svc *svc)
749 io_user_can_chan_do_abort_tasks(user);
756 io_user_can_chan_dev_cancel(dev, NULL);
760 io_user_can_chan_read_task_func(
struct ev_task *task)
782 int result = io_user_can_chan_read(
783 chan, read->
msg, read->
err, read->
tp, 0);
784 int errc = result >= 0 ? 0 :
get_errc();
789 io_can_chan_read_post(read, result, errc);
811 if (post_read && wouldblock) {
818 io_user_can_chan_c_signal, user);
828 if (
task && wouldblock)
841 io_user_can_chan_write_task_func(
struct ev_task *
task)
864 int result = io_user_can_chan_write(
871 io_can_chan_write_post(write,
errc);
893 if (
task && wouldblock)
906 io_user_can_chan_from_dev(
const io_dev_t *dev)
922 io_user_can_chan_from_svc(
const struct io_svc *
svc)
938 struct timespec ts = { 0, 0 };
970 &io_user_can_chan_p_signal, user))
997 user->
rxbuf[i] = *frame;
1007 io_user_can_chan_p_signal(
struct spscring *ring,
void *arg)
1024 io_user_can_chan_c_signal(
struct spscring *ring,
void *
arg)
1030 #if !LELY_NO_THREADS
1036 #if !LELY_NO_THREADS
1043 #if !LELY_NO_THREADS
@ CAN_FLAG_FDF
The FD Format (FDF) flag, formerly known as Extended Data Length (EDL).
@ CAN_FLAG_BRS
The Bit Rate Switch (BRS) flag (only available in CAN FD format frames).
This header file is part of the I/O library; it contains the I/O context and service declarations.
void io_ctx_insert(io_ctx_t *ctx, struct io_svc *svc)
Registers an I/O service with an I/O context.
#define IO_SVC_INIT(vptr)
The static initializer for io_svc.
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 utilities library; it contains the diagnostic declarations.
void diag(enum diag_severity severity, int errc, const char *format,...)
Emits a diagnostic message.
This header file is part of the utilities library; it contains the native and platform-independent er...
int errnum2c(errnum_t errnum)
Transforms a platform-independent error number to a native error code.
@ ERRNUM_NOSYS
Function not supported.
@ ERRNUM_WOULDBLOCK
Operation would block.
@ ERRNUM_INVAL
Invalid argument.
@ ERRNUM_AGAIN
Resource unavailable, try again.
@ ERRNUM_CANCELED
Operation canceled.
int get_errc(void)
Returns the last (thread-specific) native error code set by a system call or library function.
void set_errc(int errc)
Sets the current (thread-specific) native error code to errc.
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
void set_errnum(errnum_t errnum)
Sets the current (thread-specific) platform-independent error number to errnum.
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 ev_exec_post(ev_exec_t *exec, struct ev_task *task)
Submits *task to *exec for execution.
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.
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
const struct io_can_chan_vtbl *const io_can_chan_t
An abstract CAN channel.
@ IO_CAN_BUS_FLAG_BRS
Bit Rate Switch support is enabled.
@ IO_CAN_BUS_FLAG_FDF
FD Format (formerly Extended Data Length) support is enabled.
@ IO_CAN_BUS_FLAG_ERR
Reception of error frames is enabled.
#define LELY_IO_TX_TIMEOUT
The default timeout (in milliseconds) for I/O write operations.
This header file is part of the I/O library; it contains the user-defined CAN channel declarations.
int io_user_can_chan_write_t(const struct can_msg *msg, int timeout, void *arg)
The type of function invoked by a user-defined CAN channel when a CAN frame needs to be written.
This is the public header file of the utilities library.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
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.
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.
const struct io_dev_vtbl *const io_dev_t
An abstract I/O device.
#define LELY_IO_USER_CAN_RXLEN
The default receive queue length (in number of CAN frames) of the user-defined CAN channel.
void io_user_can_chan_destroy(io_can_chan_t *chan)
Destroys a user-defined CAN channel.
int io_user_can_chan_on_msg(io_can_chan_t *chan, const struct can_msg *msg, const struct timespec *tp, int timeout)
Processes an incoming CAN frame.
int io_user_can_chan_on_err(io_can_chan_t *chan, const struct can_err *err, const struct timespec *tp, int timeout)
Processes an incoming CAN error frame.
io_can_chan_t * io_user_can_chan_create(io_ctx_t *ctx, ev_exec_t *exec, int flags, size_t rxlen, int txtimeo, io_user_can_chan_write_t *func, void *arg)
Creates a new user-defined CAN channel.
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.
#define TIME_UTC
An integer constant greater than 0 that designates the UTC time base.
void sllist_init(struct sllist *list)
Initializes 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.
void sllist_push_front(struct sllist *list, struct slnode *node)
Pushes a node to the front of a singly-linked list.
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
void sllist_push_back(struct sllist *list, struct slnode *node)
Pushes a node to the back of a singly-linked list.
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
struct slnode * sllist_pop_front(struct sllist *list)
Pops a node from the front of a singly-linked list.
This header file is part of the utilities library; it contains the single-producer,...
size_t spscring_c_alloc(struct spscring *ring, size_t *psize)
Allocates a consecutive range of indices, including wrapping, in a single-producer,...
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,...
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...
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,...
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...
int spscring_c_abort_wait(struct spscring *ring)
Aborts a wait operation previously registered with spscring_c_submit_wait().
void spscring_init(struct spscring *ring, size_t size)
Initializes a single-producer, single-consumer ring buffer with the specified size.
size_t spscring_p_alloc(struct spscring *ring, size_t *psize)
Allocates a consecutive range of indices, including wrapping, in a single-producer,...
This header file is part of the C11 and POSIX compatibility library; it includes <stdlib....
A CAN or CAN FD format frame.
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...
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
A CAN channel read operation.
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the read operation.
struct timespec * tp
The address at which to store the system time at which the CAN frame or CAN error frame was received.
struct can_msg * msg
The address at which to store the CAN frame.
struct can_err * err
The address at which to store the CAN error frame.
A CAN channel write operation.
const struct can_msg * msg
A pointer to the CAN frame to be written.
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the write operation.
int errc
The error number, obtained as if by get_errc(), if an error occurred or the operation was canceled.
The virtual table of an I/O service.
The implementation of a user-defined CAN channel.
struct ev_task write_task
The task responsible for initiating write operations.
void * arg
The user-specific value to be passed as the second argument to func.
ev_exec_t * exec
A pointer to the executor used to execute all I/O tasks.
unsigned write_posted
A flag indicating whether write_task has been posted to exec.
const struct io_can_chan_vtbl * chan_vptr
A pointer to the virtual table for the CAN channel interface.
int txtimeo
The timeout (in milliseconds) when writing a CAN frame asynchronously.
cnd_t p_cond
The condition variable used to wake up the receive queue producer.
struct io_svc svc
The I/O service representing the channel.
struct spscring rxring
The ring buffer used to control the receive queue.
const struct io_dev_vtbl * dev_vptr
A pointer to the virtual table for the I/O device interface.
struct ev_task * current_write
The write operation currently being executed.
io_user_can_chan_write_t * func
A pointer to the function to be invoked when a CAN frame needs to be written.
cnd_t c_cond
The condition variable used to wake up the receive queue consumer.
mtx_t p_mtx
The mutex protecting the receive queue producer.
io_ctx_t * ctx
A pointer to the I/O context with which the channel is registered.
struct ev_task * current_read
The read operation currently being executed.
unsigned shutdown
A flag indicating whether the I/O service has been shut down.
struct ev_task read_task
The task responsible for initiating read operations.
unsigned read_posted
A flag indicating whether read_task has been posted to exec.
mtx_t mtx
The mutex protecting the channel and the queues of pending operations.
struct sllist read_queue
The queue containing pending read operations.
mtx_t c_mtx
The mutex protecting the receive queue consumer.
struct sllist write_queue
The queue containing pending write operations.
int flags
The flags specifying which CAN bus features are enabled.
struct io_user_can_frame * rxbuf
The receive queue.
A single-producer, single-consumer ring buffer.
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.
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.
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
This header file is part of the C11 and POSIX compatibility library; it includes <threads....
int cnd_init(cnd_t *cond)
Creates a condition variable.
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...
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:
int mtx_lock(mtx_t *mtx)
Blocks until it locks the mutex at mtx.
pthread_cond_t cnd_t
A complete object type that holds an identifier for a condition variable.
void cnd_destroy(cnd_t *cond)
Releases all resources used by the condition variable at cond.
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...
void thrd_yield(void)
Endeavors to permit other threads to run, even if the current thread would ordinarily continue to run...
@ thrd_timedout
Indicates that the time specified in the call was reached without acquiring the requested resource.
@ thrd_success
Indicates that the requested operation succeeded.
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
pthread_mutex_t mtx_t
A complete object type that holds an identifier for a mutex.
void mtx_destroy(mtx_t *mtx)
Releases any resources used by the mutex at mtx.
@ mtx_plain
A mutex type that supports neither timeout nor test and return.
This header file is part of the utilities library; it contains the time function declarations.
void timespec_add_msec(struct timespec *tp, uint_least64_t msec)
Adds msec milliseconds to the time at tp.