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
154 unsigned shutdown : 1;
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);
178 const struct io_svc *svc);
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");
379 chan, ctx, exec, flags, rxlen, txtimeo, func, arg);
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)
417 if ((flags & user->
flags) != flags) {
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(
666 if ((flags & user->
flags) != flags) {
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(
866 int errc = !result ? 0 :
get_errc();
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 1058 assert(write_queue);
cnd_t p_cond
The condition variable used to wake up the receive queue producer.
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...
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.
This header file is part of the I/O library; it contains the user-defined CAN channel declarations...
const struct ev_exec_vtbl *const ev_exec_t
An abstract task executor.
int spscring_c_abort_wait(struct spscring *ring)
Aborts a wait operation previously registered with spscring_c_submit_wait().
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.
A CAN channel read operation.
#define EV_TASK_INIT(exec, func)
The static initializer for ev_task.
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.
struct ev_task * current_write
The write operation currently being executed.
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.
struct sllist write_queue
The queue containing pending write operations.
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.
struct ev_task write_task
The task responsible for initiating write operations.
io_ctx_t * ctx
A pointer to the I/O context with which the channel is registered.
void sllist_push_front(struct sllist *list, struct slnode *node)
Pushes a node to the front of a singly-linked list.
Indicates that the time specified in the call was reached without acquiring the requested resource...
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.
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.
mtx_t c_mtx
The mutex protecting the receive queue consumer.
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.
ev_exec_t * exec
A pointer to the executor used to execute all I/O tasks.
struct ev_task * current_read
The read operation currently being executed.
struct spscring rxring
The ring buffer used to control the receive queue.
struct slnode * sllist_remove(struct sllist *list, struct slnode *node)
Removes a node from a singly-linked list.
A mutex type that supports neither timeout nor test and return.
unsigned write_posted
A flag indicating whether write_task has been posted to exec.
int mtx_unlock(mtx_t *mtx)
Unlocks the mutex at mtx.
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.
This header file is part of the utilities library; it contains the native and platform-independent er...
ev_exec_t * exec
A pointer to the executor to which the task is (to be) submitted.
This header file is part of the utilities library; it contains the time function declarations.
struct ev_task task
The task (to be) submitted upon completion (or cancellation) of the read operation.
int cnd_init(cnd_t *cond)
Creates a condition variable.
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 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.
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...
struct sllist read_queue
The queue containing pending read operations.
struct io_user_can_frame * rxbuf
The receive queue.
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.
#define LELY_IO_TX_TIMEOUT
The default timeout (in milliseconds) for I/O write operations.
int txtimeo
The timeout (in milliseconds) when writing a CAN frame asynchronously.
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.
const struct can_msg * msg
A pointer to the CAN frame to be written.
struct io_svc svc
The I/O service representing the channel.
io_user_can_chan_write_t * func
A pointer to the function to be invoked when a CAN frame needs to be written.
unsigned shutdown
A flag indicating whether the I/O service has been shut down.
int errno2c(int errnum)
Transforms a standard C error number to a native error code.
This header file is part of the utilities library; it contains the diagnostic declarations.
mtx_t mtx
The mutex protecting the channel and the queues of pending operations.
cnd_t c_cond
The condition variable used to wake up the receive queue consumer.
void * arg
The user-specific value to be passed as the second argument to func.
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.
unsigned read_posted
A flag indicating whether read_task has been posted to exec.
void io_ctx_remove(io_ctx_t *ctx, struct io_svc *svc)
Unregisters an I/O service with an I/O context.
#define LELY_IO_USER_CAN_RXLEN
The default receive queue length (in number of CAN frames) of the user-defined 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...
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...
void io_user_can_chan_destroy(io_can_chan_t *chan)
Destroys a user-defined CAN channel.
int sllist_empty(const struct sllist *list)
Returns 1 if the singly-linked list is empty, and 0 if not.
struct ev_task read_task
The task responsible for initiating read operations.
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.
#define structof(ptr, type, member)
Obtains the address of a structure from the address of one of its members.
struct can_msg * msg
The address at which to store the CAN frame.
The virtual table of an I/O service.
void cnd_destroy(cnd_t *cond)
Releases all resources used by the condition variable at cond.
#define IO_SVC_INIT(vptr)
The static initializer for io_svc.
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...
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.
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...
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.
The implementation of a user-defined CAN channel.
struct timespec * tp
The address at which to store the system time at which the CAN frame or CAN error frame was received...
const struct io_can_chan_vtbl * chan_vptr
A pointer to the virtual table for the CAN channel interface.
This is the public header file of the utilities library.
const struct io_dev_vtbl * dev_vptr
A pointer to the virtual table for the I/O device interface.
int flags
The flags specifying which CAN bus features are enabled.
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...
mtx_t p_mtx
The mutex protecting the receive queue producer.
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 Bit Rate Switch (BRS) flag (only available in CAN FD format frames).