39#if defined(ESP_PLATFORM)
43#if CONFIG_VFS_SUPPORT_TERMIOS
51#include <driver/gpio.h>
52#include <esp_idf_version.h>
54#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,1,0)
55#include <esp_clk_tree.h>
57#include <esp_private/periph_ctrl.h>
60#include <esp_rom_gpio.h>
61#include <esp_intr_alloc.h>
65#include <hal/twai_types.h>
66#include <hal/twai_hal.h>
67#include <soc/gpio_sig_map.h>
78namespace openmrn_arduino
84static constexpr int TWAI_VFS_FD = 0;
87static constexpr BaseType_t WATCHDOG_TASK_PRIORITY = ESP_TASK_TCPIP_PRIO - 1;
90static constexpr BaseType_t WATCHDOG_TASK_STACK = 2548;
93static constexpr TickType_t STATUS_PRINT_INTERVAL = pdMS_TO_TICKS(10000);
97static constexpr uint32_t TWAI_DEFAULT_INTERRUPTS = 0xE7;
101static constexpr uint32_t TWAI_INTERRUPT_FLAGS = ESP_INTR_FLAG_LOWMED;
104static constexpr const char *TWAI_LOG_TAG =
"ESP-TWAI";
110 esp32_twai_stats_t stats;
113 twai_hal_context_t context;
116 intr_handle_t isr_handle;
137#if CONFIG_VFS_SUPPORT_SELECT
144 esp_vfs_select_sem_t select_sem;
160 fd_set writefds_orig;
168 fd_set exceptfds_orig;
177 os_thread_t wd_thread;
185static TwaiDriver twai;
189static inline bool is_twai_running()
191 return twai_hal_check_state_flags(&twai.context, TWAI_HAL_STATE_FLAG_RUNNING);
196static inline bool is_twai_recovering()
198 return twai_hal_check_state_flags(&twai.context, TWAI_HAL_STATE_FLAG_RECOVERING);
203static inline bool is_twai_err_warn()
205 return twai_hal_check_state_flags(&twai.context, TWAI_HAL_STATE_FLAG_ERR_WARN);
210static inline bool is_twai_err_passive()
212 return twai_hal_check_state_flags(&twai.context, TWAI_HAL_STATE_FLAG_ERR_PASSIVE);
217static inline bool is_twai_bus_off()
219 return twai_hal_check_state_flags(&twai.context, TWAI_HAL_STATE_FLAG_BUS_OFF);
223static inline bool is_twai_tx_occupied()
225 return twai_hal_check_state_flags(&twai.context, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED);
230static inline void twai_purge_rx_queue()
235 LOG(
VERBOSE,
"ESP-TWAI: purging RX-Q: %zu", twai.rx_buf->pending());
236 twai.stats.rx_missed += twai.rx_buf->pending();
237 twai.rx_buf->flush();
238 std::swap(n, twai.readable_notify);
244#if CONFIG_VFS_SUPPORT_SELECT
246 if (FD_ISSET(TWAI_VFS_FD, &twai.exceptfds_orig))
248 FD_SET(TWAI_VFS_FD, twai.exceptfds);
249 esp_vfs_select_triggered(twai.select_sem);
256static inline void twai_purge_tx_queue()
261 LOG(
VERBOSE,
"ESP-TWAI: purging TX-Q: %zu", twai.tx_buf->pending());
262 twai.stats.tx_failed += twai.tx_buf->pending();
263 twai.tx_buf->flush();
264 std::swap(n, twai.writable_notify);
270#if CONFIG_VFS_SUPPORT_SELECT
272 if (FD_ISSET(TWAI_VFS_FD, &twai.exceptfds_orig))
274 FD_SET(TWAI_VFS_FD, twai.exceptfds);
275 esp_vfs_select_triggered(twai.select_sem);
287static ssize_t twai_vfs_write(
int fd,
const void *buf,
size_t size)
289 LOG(
VERBOSE,
"ESP-TWAI: write(%d, %p, %zu)", fd, buf, size);
292 const struct can_frame *data = (
const struct can_frame *)buf;
293 size /=
sizeof(
struct can_frame);
294 bool bus_error =
false;
295 while (size && !bus_error)
297 if (is_twai_bus_off())
300 LOG_ERROR(
"ESP-TWAI: Bus is OFF, initiating recovery.");
301 twai_hal_start_bus_recovery(&twai.context);
305 else if (!is_twai_running())
307 LOG_ERROR(
"ESP-TWAI: TWAI driver is not running, unable to write "
308 "%zu frames.", size);
313 size_t frames_written = 0;
316 frames_written = twai.tx_buf->put(data, size < 8 ? size : 8);
318 if (frames_written == 0)
325 twai.stats.tx_processed += frames_written;
328 if (is_twai_running() && !is_twai_tx_occupied() && frames_written)
333 struct can_frame *frame =
nullptr;
334 twai_message_t tx_frame;
335 twai_hal_frame_t hal_frame;
336 if (twai.tx_buf->data_read_pointer(&frame) && frame !=
nullptr)
338 memset(&tx_frame, 0,
sizeof(twai_message_t));
339 tx_frame.identifier = frame->can_id;
340 tx_frame.extd = IS_CAN_FRAME_EFF(*frame);
341 tx_frame.rtr = IS_CAN_FRAME_RTR(*frame);
342 tx_frame.data_length_code = frame->can_dlc;
343 memcpy(tx_frame.data, frame->data, frame->can_dlc);
344 twai_hal_format_frame(&tx_frame, &hal_frame);
345 twai_hal_set_tx_buffer_and_transmit(&twai.context, &hal_frame);
348 sent += frames_written;
349 size -= frames_written;
354 twai_purge_tx_queue();
361 LOG(
VERBOSE,
"ESP-TWAI: write() %zu", sent *
sizeof(
struct can_frame));
362 return sent *
sizeof(
struct can_frame);
372static ssize_t twai_vfs_read(
int fd,
void *buf,
size_t size)
374 LOG(
VERBOSE,
"ESP-TWAI: read(%d, %p, %zu)", fd, buf, size);
377 ssize_t received = 0;
378 struct can_frame *data = (
struct can_frame *)buf;
379 size /=
sizeof(
struct can_frame);
382 size_t received_frames = 0;
385 received_frames = twai.rx_buf->get(data, size < 8 ? size : 8);
387 if (received_frames == 0)
391 twai.stats.rx_processed += received_frames;
392 size -= received_frames;
393 received += received_frames;
394 data += received_frames;
402 LOG(
VERBOSE,
"ESP-TWAI: read() %zu", received *
sizeof(
struct can_frame));
403 return received *
sizeof(
struct can_frame);
416static int twai_vfs_open(
const char *path,
int flags,
int mode)
420 twai.non_blocking = (flags & O_NONBLOCK);
422 LOG(
INFO,
"ESP-TWAI: Starting TWAI driver on:%s mode:%x (%s) fd:%d",
423 path, mode, twai.non_blocking ?
"non-blocking" :
"blocking",
425 twai_purge_rx_queue();
426 twai_purge_tx_queue();
427 twai_hal_start(&twai.context, TWAI_MODE_NORMAL);
439static int twai_vfs_close(
int fd)
441 LOG(
INFO,
"ESP-TWAI: Disabling TWAI driver using fd:%d", fd);
442 twai_purge_rx_queue();
443 twai_purge_tx_queue();
444 twai_hal_stop(&twai.context);
455static int twai_vfs_ioctl(
int fd,
int cmd, va_list args)
465 n =
reinterpret_cast<Notifiable*
>(va_arg(args, uintptr_t));
475 if (!twai.rx_buf->pending())
477 std::swap(n, twai.readable_notify);
484 if (!twai.tx_buf->space())
486 std::swap(n, twai.writable_notify);
507static int twai_vfs_fcntl(
int fd,
int cmd,
int arg)
514 if (twai.non_blocking)
516 result |= O_NONBLOCK;
519 else if (cmd == F_SETFL)
521 twai.non_blocking = arg & O_NONBLOCK;
532#if CONFIG_VFS_SUPPORT_SELECT
540static esp_err_t twai_vfs_start_select(
int nfds, fd_set *readfds,
541 fd_set *writefds, fd_set *exceptfds,
542 esp_vfs_select_sem_t
sem,
543 void **end_select_args)
549 FD_ZERO(&twai.readfds_orig);
550 FD_ZERO(&twai.writefds_orig);
551 FD_ZERO(&twai.exceptfds_orig);
555 if (FD_ISSET(TWAI_VFS_FD, readfds) || FD_ISSET(TWAI_VFS_FD, writefds) ||
556 FD_ISSET(TWAI_VFS_FD, exceptfds))
558 twai.select_sem =
sem;
559 twai.readfds = readfds;
560 twai.readfds_orig = *readfds;
561 twai.writefds = writefds;
562 twai.writefds_orig = *writefds;
563 twai.exceptfds = exceptfds;
564 twai.exceptfds_orig = *exceptfds;
574 if (FD_ISSET(TWAI_VFS_FD, &twai.readfds_orig))
577 if (twai.rx_buf->pending())
579 FD_SET(TWAI_VFS_FD, readfds);
580 esp_vfs_select_triggered(
sem);
590static esp_err_t twai_vfs_end_select(
void *end_select_args)
595 FD_ZERO(&twai.readfds_orig);
596 FD_ZERO(&twai.writefds_orig);
597 FD_ZERO(&twai.exceptfds_orig);
604static inline uint32_t twai_rx_frames()
607 uint32_t rx_ready_count = twai_hal_get_rx_msg_count(&twai.context);
608 struct can_frame *can_frame =
nullptr;
609 uint32_t rx_count = 0;
610 ESP_EARLY_LOGV(TWAI_LOG_TAG,
"rx-ready-count: %" PRIu32, rx_ready_count);
611 for (uint32_t idx = 0; idx < rx_ready_count; idx++)
613 twai_hal_frame_t frame;
614 if (twai_hal_read_rx_buffer_and_clear(&twai.context, &frame))
616 if (frame.dlc > TWAI_FRAME_MAX_DLC)
619 twai.stats.rx_discard++;
620 ESP_EARLY_LOGE(TWAI_LOG_TAG,
"rx-discard:%" PRIu32,
621 twai.stats.rx_discard);
623 else if (twai.rx_buf->data_write_pointer(&can_frame))
625 twai_message_t rx_frame;
626 twai_hal_parse_frame(&frame, &rx_frame);
627 memcpy(can_frame->data, rx_frame.data, TWAI_FRAME_MAX_DLC);
628 can_frame->can_dlc = rx_frame.data_length_code;
629 can_frame->can_id = rx_frame.identifier;
632 SET_CAN_FRAME_EFF(*can_frame);
636 CLR_CAN_FRAME_EFF(*can_frame);
640 SET_CAN_FRAME_RTR(*can_frame);
644 CLR_CAN_FRAME_RTR(*can_frame);
646 rx_count += twai.rx_buf->advance(1);
647 ESP_EARLY_LOGV(TWAI_LOG_TAG,
"rx-OK");
651 twai.stats.rx_missed++;
652 ESP_EARLY_LOGV(TWAI_LOG_TAG,
"rx-missed:%" PRIu32,
653 twai.stats.rx_missed);
658 ESP_EARLY_LOGV(TWAI_LOG_TAG,
"rx-overrun");
661#ifndef SOC_TWAI_SUPPORTS_RX_STATUS
662 twai.stats.rx_overrun +=
663 twai_hal_clear_rx_fifo_overrun(&twai.context);
666 twai.stats.rx_overrun++;
675static inline uint32_t twai_tx_frame()
678 if (twai_hal_check_last_tx_successful(&twai.context))
680 ESP_EARLY_LOGV(TWAI_LOG_TAG,
"TX-OK");
681 twai.stats.tx_success++;
682 twai.tx_buf->consume(1);
686 ESP_EARLY_LOGV(TWAI_LOG_TAG,
"TX-FAIL");
687 twai.stats.tx_failed++;
691 struct can_frame *can_frame =
nullptr;
692 if (twai.tx_buf->data_read_pointer(&can_frame) && can_frame !=
nullptr)
694 twai_message_t tx_frame;
695 twai_hal_frame_t hal_frame;
696 memset(&tx_frame, 0,
sizeof(twai_message_t));
697 tx_frame.identifier = can_frame->can_id;
698 tx_frame.extd = IS_CAN_FRAME_EFF(*can_frame);
699 tx_frame.rtr = IS_CAN_FRAME_RTR(*can_frame);
700 tx_frame.data_length_code = can_frame->can_dlc;
701 memcpy(tx_frame.data, can_frame->data, can_frame->can_dlc);
702 twai_hal_format_frame(&tx_frame, &hal_frame);
703 twai_hal_set_tx_buffer_and_transmit(&twai.context, &hal_frame);
712static void twai_isr(
void *arg)
714 BaseType_t
wakeup = pdFALSE;
715 uint32_t events = twai_hal_get_events(&twai.context);
716 ESP_EARLY_LOGV(TWAI_LOG_TAG,
"events: %04" PRIx32, events);
718#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || \
719 defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
720 if (events & TWAI_HAL_EVENT_NEED_PERIPH_RESET)
722 ESP_EARLY_LOGV(TWAI_LOG_TAG,
"periph-reset");
723 twai_hal_prepare_for_reset(&twai.context);
724 periph_module_reset(PERIPH_TWAI_MODULE);
725 twai_hal_recover_from_reset(&twai.context);
726 twai.stats.rx_lost += twai_hal_get_reset_lost_rx_cnt(&twai.context);
727#if CONFIG_VFS_SUPPORT_SELECT
729 if (FD_ISSET(TWAI_VFS_FD, &twai.exceptfds_orig))
731 FD_SET(TWAI_VFS_FD, twai.exceptfds);
732 esp_vfs_select_triggered_isr(twai.select_sem, &
wakeup);
739 if ((events & TWAI_HAL_EVENT_RX_BUFF_FRAME) && twai_rx_frames())
741#if CONFIG_VFS_SUPPORT_SELECT
743 if (FD_ISSET(TWAI_VFS_FD, &twai.readfds_orig))
745 FD_SET(TWAI_VFS_FD, twai.readfds);
746 esp_vfs_select_triggered_isr(twai.select_sem, &
wakeup);
750 if (twai.readable_notify)
752 twai.readable_notify->notify_from_isr();
753 twai.readable_notify =
nullptr;
758 if ((events & TWAI_HAL_EVENT_TX_BUFF_FREE) && twai_tx_frame())
760#if CONFIG_VFS_SUPPORT_SELECT
762 if (FD_ISSET(TWAI_VFS_FD, &twai.writefds_orig))
764 FD_SET(TWAI_VFS_FD, twai.writefds);
765 esp_vfs_select_triggered_isr(twai.select_sem, &
wakeup);
769 if (twai.writable_notify)
771 twai.writable_notify->notify_from_isr();
772 twai.writable_notify =
nullptr;
777 if (events & TWAI_HAL_EVENT_BUS_RECOV_CPLT)
779 ESP_EARLY_LOGV(TWAI_LOG_TAG,
"bus recovery complete");
781 twai_hal_start(&twai.context, TWAI_MODE_NORMAL);
785 if (events & TWAI_HAL_EVENT_BUS_ERR)
787 twai.stats.bus_error++;
788 ESP_EARLY_LOGV(TWAI_LOG_TAG,
"bus-error:%" PRIu32,
789 twai.stats.bus_error);
793 if (events & TWAI_HAL_EVENT_ARB_LOST)
795 twai.stats.arb_loss++;
796 ESP_EARLY_LOGV(TWAI_LOG_TAG,
"arb-lost:%" PRIu32,
797 twai.stats.arb_loss);
802 portYIELD_FROM_ISR();
823void* twai_watchdog(
void* param)
825 LOG(
INFO,
"ESP-TWAI: Starting TWAI watchdog and reporting task");
826 size_t last_rx_pending = 0;
827 size_t last_tx_pending = 0;
828 uint32_t last_twai_state = 0;
835 ulTaskNotifyTake(pdTRUE, STATUS_PRINT_INTERVAL);
847 if (last_twai_state == twai.context.state_flags &&
848 is_twai_recovering())
851 "ESP-TWAI: Bus appears to be stuck, initiating bus recovery.");
852 twai_hal_start_bus_recovery(&twai.context);
854 last_twai_state = twai.context.state_flags;
858 if (last_rx_pending && last_rx_pending == twai.rx_buf->pending())
860 LOG_ERROR(
"ESP-TWAI: RX-Q appears stuck, purging RX-Q!");
861 twai_purge_rx_queue();
863 last_rx_pending = twai.rx_buf->pending();
867 if (last_tx_pending && last_tx_pending == twai.tx_buf->pending())
869 LOG_ERROR(
"ESP-TWAI: TX-Q appears stuck, purging TX-Q!");
870 twai_purge_tx_queue();
872 last_tx_pending = twai.tx_buf->pending();
874 if (twai.report_stats)
878 "RX:%" PRIu32
" (pending:%zu,overrun:%" PRIu32
879 ",discard:%" PRIu32
",missed:%" PRIu32
",lost:%" PRIu32
") "
880 "TX:%" PRIu32
" (pending:%zu,suc:%" PRIu32
881 ",fail:%" PRIu32
") "
882 "Bus (arb-err:%" PRIu32
",err:%" PRIu32
",state:%s)",
883 twai.stats.rx_processed, twai.rx_buf->pending(),
884 twai.stats.rx_overrun, twai.stats.rx_discard,
885 twai.stats.rx_missed, twai.stats.rx_lost,
886 twai.stats.tx_processed, twai.tx_buf->pending(),
887 twai.stats.tx_success, twai.stats.tx_failed,
888 twai.stats.arb_loss, twai.stats.bus_error,
889 is_twai_running() ?
"Running" :
890 is_twai_recovering() ?
"Recovering" :
891 is_twai_err_warn() ?
"Err-Warn" :
892 is_twai_err_passive() ?
"Err-Pasv" :
896 LOG(
VERBOSE,
"ESP-TWAI: Stopping TWAI watchdog and reporting task");
902 int rx,
int tx,
bool report,
size_t rx_size,
size_t tx_size,
903 const char *path,
int clock_out,
int bus_status, uint32_t isr_core)
904 : rxPin_(rx), txPin_(tx), extClockPin_(clock_out),
905 busStatusPin_(bus_status), preferredIsrCore_(isr_core), vfsPath_(path)
907 HASSERT(GPIO_IS_VALID_GPIO(rxPin_));
908 HASSERT(GPIO_IS_VALID_OUTPUT_GPIO(txPin_));
910 if (extClockPin_ != GPIO_NUM_NC)
912 HASSERT(GPIO_IS_VALID_OUTPUT_GPIO(extClockPin_));
915 if (busStatusPin_ != GPIO_NUM_NC)
917 HASSERT(GPIO_IS_VALID_OUTPUT_GPIO(busStatusPin_));
920 memset(&twai.stats, 0,
sizeof(esp32_twai_stats_t));
923 HASSERT(twai.rx_buf !=
nullptr);
927 HASSERT(twai.tx_buf !=
nullptr);
929 twai.report_stats = report;
932Esp32HardwareTwai::~Esp32HardwareTwai()
936 esp_intr_free(twai.isr_handle);
937 twai_hal_deinit(&twai.context);
941 esp_vfs_unregister(vfsPath_);
943 twai.tx_buf->destroy();
944 twai.rx_buf->destroy();
948 xTaskNotifyGive(twai.wd_thread);
955static void esp32_twai_isr_init(
void *param)
959 esp_intr_alloc(ETS_TWAI_INTR_SOURCE, TWAI_INTERRUPT_FLAGS, twai_isr,
960 nullptr, &twai.isr_handle));
963void Esp32HardwareTwai::hw_init()
966 "ESP-TWAI: Configuring TWAI (TX:%d, RX:%d, EXT-CLK:%d, BUS-CTRL:%d)",
967 txPin_, rxPin_, extClockPin_, busStatusPin_);
968 gpio_set_pull_mode((gpio_num_t)txPin_, GPIO_FLOATING);
969 esp_rom_gpio_connect_out_signal(txPin_, TWAI_TX_IDX,
false,
false);
970 esp_rom_gpio_pad_select_gpio(txPin_);
972 gpio_set_pull_mode((gpio_num_t)rxPin_, GPIO_FLOATING);
973 esp_rom_gpio_connect_in_signal(rxPin_, TWAI_RX_IDX,
false);
974 esp_rom_gpio_pad_select_gpio(rxPin_);
975 gpio_set_direction((gpio_num_t)rxPin_, GPIO_MODE_INPUT);
977 if (extClockPin_ != GPIO_NUM_NC)
979 gpio_set_pull_mode((gpio_num_t)extClockPin_, GPIO_FLOATING);
980 esp_rom_gpio_connect_out_signal(extClockPin_, TWAI_CLKOUT_IDX,
false,
982 esp_rom_gpio_pad_select_gpio((gpio_num_t)extClockPin_);
985 if (busStatusPin_ != GPIO_NUM_NC)
987 gpio_set_pull_mode((gpio_num_t)busStatusPin_, GPIO_FLOATING);
988 esp_rom_gpio_connect_out_signal(extClockPin_, TWAI_BUS_OFF_ON_IDX,
990 esp_rom_gpio_pad_select_gpio((gpio_num_t)busStatusPin_);
994 vfs.write = twai_vfs_write;
995 vfs.read = twai_vfs_read;
996 vfs.open = twai_vfs_open;
997 vfs.close = twai_vfs_close;
998 vfs.fcntl = twai_vfs_fcntl;
999 vfs.ioctl = twai_vfs_ioctl;
1000#if CONFIG_VFS_SUPPORT_SELECT
1001 vfs.start_select = twai_vfs_start_select;
1002 vfs.end_select = twai_vfs_end_select;
1004 vfs.flags = ESP_VFS_FLAG_DEFAULT;
1005 ESP_ERROR_CHECK(esp_vfs_register(vfsPath_, &vfs,
this));
1007 periph_module_reset(PERIPH_TWAI_MODULE);
1008 periph_module_enable(PERIPH_TWAI_MODULE);
1010 twai_timing_config_t timingCfg = TWAI_TIMING_CONFIG_125KBITS();
1011 twai_filter_config_t filterCfg = TWAI_FILTER_CONFIG_ACCEPT_ALL();
1013#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,1,0)
1015 if (timingCfg.clk_src == 0)
1017 timingCfg.clk_src = TWAI_CLK_SRC_DEFAULT;
1019 twai_hal_config_t twai_hal_cfg =
1022 .clock_source_hz = 0,
1026 esp_clk_tree_src_get_freq_hz((soc_module_clk_t)timingCfg.clk_src,
1027 ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &twai_hal_cfg.clock_source_hz);
1030 uint32_t brp = timingCfg.brp;
1031 if (timingCfg.quanta_resolution_hz)
1033 HASSERT(twai_hal_cfg.clock_source_hz % timingCfg.quanta_resolution_hz == 0);
1034 brp = twai_hal_cfg.clock_source_hz / timingCfg.quanta_resolution_hz;
1036 HASSERT(twai_ll_check_brp_validation(brp));
1039 HASSERT(twai_hal_init(&twai.context, &twai_hal_cfg));
1042 HASSERT(twai_hal_init(&twai.context));
1045 LOG(
VERBOSE,
"ESP-TWAI: Initiailizing peripheral");
1046 twai_hal_configure(&twai.context, &timingCfg, &filterCfg,
1047 TWAI_DEFAULT_INTERRUPTS, 0);
1049#if SOC_CPU_CORES_NUM > 1
1051 esp_ipc_call_blocking(preferredIsrCore_, esp32_twai_isr_init,
nullptr));
1053 esp32_twai_isr_init(
nullptr);
1058 WATCHDOG_TASK_STACK, twai_watchdog,
this);
1061void Esp32HardwareTwai::get_driver_stats(esp32_twai_stats_t *stats)
1064 memcpy(stats, &twai.stats,
sizeof(esp32_twai_stats_t));
OSSem sem[1]
One semaphore required per instance pointer.
static OSEvent wakeup
event used to wakeup select calls
See OSMutexLock in os/OS.hxx.
Lightweight locking class for protecting small critical sections.
Implements a smart buffer specifically designed for character device drivers.
static DeviceBuffer * create(size_t size, size_t level=0)
Create a DeviceBuffer instance.
An object that can schedule itself on an executor to run.
virtual void notify()=0
Generic callback.
Esp32HardwareTwai()
Default constructor.
#define CAN_IOC_READ_ACTIVE
read active ioctl.
#define NOTIFIABLE_TYPE
ioctl minor type used for the read/write active notifiable integration.
#define CAN_IOC_WRITE_ACTIVE
write active ioctl.
#define CAN_IOC_MAGIC
Magic number for this driver's ioctl calls.
#define IOC_SIZE(_num)
Decode ioctl size.
#define IOC_TYPE(_num)
Decode ioctl type.
#define LOG(level, message...)
Conditionally write a message to the logging output.
static const int VERBOSE
Loglevel that is usually not printed, reporting debugging information.
static const int WARNING
Loglevel that is always printed, reporting a warning or a retryable error.
static const int INFO
Loglevel that is printed by default, reporting some status information.
#define LOG_ERROR(message...)
Shorthand for LOG(LEVEL_ERROR, message...). See LOG.
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
#define DASSERT(x)
Debug assertion facility.
int os_thread_create(os_thread_t *thread, const char *name, int priority, size_t stack_size, void *(*start_routine)(void *), void *arg)
Create a thread.