1 /*
2  * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #pragma once
8 
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12 
13 #include "soc/soc_caps.h"
14 #if SOC_TWAI_SUPPORTED
15 
16 #include "freertos/FreeRTOS.h"
17 #include "esp_types.h"
18 #include "esp_intr_alloc.h"
19 #include "esp_err.h"
20 #include "gpio.h"
21 #include "hal/twai_types.h"
22 
23 /* -------------------- Default initializers and flags ---------------------- */
24 /** @cond */    //Doxy command to hide preprocessor definitions from docs
25 /**
26  * @brief Initializer macro for general configuration structure.
27  *
28  * This initializer macros allows the TX GPIO, RX GPIO, and operating mode to be
29  * configured. The other members of the general configuration structure are
30  * assigned default values.
31  */
32 #define TWAI_GENERAL_CONFIG_DEFAULT(tx_io_num, rx_io_num, op_mode) {.mode = op_mode, .tx_io = tx_io_num, .rx_io = rx_io_num,        \
33                                                                     .clkout_io = TWAI_IO_UNUSED, .bus_off_io = TWAI_IO_UNUSED,      \
34                                                                     .tx_queue_len = 5, .rx_queue_len = 5,                           \
35                                                                     .alerts_enabled = TWAI_ALERT_NONE,  .clkout_divider = 0,        \
36                                                                     .intr_flags = ESP_INTR_FLAG_LEVEL1}
37 
38 /**
39  * @brief   Alert flags
40  *
41  * The following flags represents the various kind of alerts available in
42  * the TWAI driver. These flags can be used when configuring/reconfiguring
43  * alerts, or when calling twai_read_alerts().
44  *
45  * @note    The TWAI_ALERT_AND_LOG flag is not an actual alert, but will configure
46  *          the TWAI driver to log to UART when an enabled alert occurs.
47  */
48 #define TWAI_ALERT_TX_IDLE                  0x00000001  /**< Alert(1): No more messages to transmit */
49 #define TWAI_ALERT_TX_SUCCESS               0x00000002  /**< Alert(2): The previous transmission was successful */
50 #define TWAI_ALERT_RX_DATA                  0x00000004  /**< Alert(4): A frame has been received and added to the RX queue */
51 #define TWAI_ALERT_BELOW_ERR_WARN           0x00000008  /**< Alert(8): Both error counters have dropped below error warning limit */
52 #define TWAI_ALERT_ERR_ACTIVE               0x00000010  /**< Alert(16): TWAI controller has become error active */
53 #define TWAI_ALERT_RECOVERY_IN_PROGRESS     0x00000020  /**< Alert(32): TWAI controller is undergoing bus recovery */
54 #define TWAI_ALERT_BUS_RECOVERED            0x00000040  /**< Alert(64): TWAI controller has successfully completed bus recovery */
55 #define TWAI_ALERT_ARB_LOST                 0x00000080  /**< Alert(128): The previous transmission lost arbitration */
56 #define TWAI_ALERT_ABOVE_ERR_WARN           0x00000100  /**< Alert(256): One of the error counters have exceeded the error warning limit */
57 #define TWAI_ALERT_BUS_ERROR                0x00000200  /**< Alert(512): A (Bit, Stuff, CRC, Form, ACK) error has occurred on the bus */
58 #define TWAI_ALERT_TX_FAILED                0x00000400  /**< Alert(1024): The previous transmission has failed (for single shot transmission) */
59 #define TWAI_ALERT_RX_QUEUE_FULL            0x00000800  /**< Alert(2048): The RX queue is full causing a frame to be lost */
60 #define TWAI_ALERT_ERR_PASS                 0x00001000  /**< Alert(4096): TWAI controller has become error passive */
61 #define TWAI_ALERT_BUS_OFF                  0x00002000  /**< Alert(8192): Bus-off condition occurred. TWAI controller can no longer influence bus */
62 #define TWAI_ALERT_RX_FIFO_OVERRUN          0x00004000  /**< Alert(16384): An RX FIFO overrun has occurred */
63 #define TWAI_ALERT_TX_RETRIED               0x00008000  /**< Alert(32768): An message transmission was cancelled and retried due to an errata workaround */
64 #define TWAI_ALERT_PERIPH_RESET             0x00010000  /**< Alert(65536): The TWAI controller was reset */
65 #define TWAI_ALERT_ALL                      0x0001FFFF  /**< Bit mask to enable all alerts during configuration */
66 #define TWAI_ALERT_NONE                     0x00000000  /**< Bit mask to disable all alerts during configuration */
67 #define TWAI_ALERT_AND_LOG                  0x00020000  /**< Bit mask to enable alerts to also be logged when they occur. Note that logging from the ISR is disabled if CONFIG_TWAI_ISR_IN_IRAM is enabled (see docs). */
68 
69 /** @endcond */
70 
71 #define TWAI_IO_UNUSED                   ((gpio_num_t) -1)   /**< Marks GPIO as unused in TWAI configuration */
72 
73 /* ----------------------- Enum and Struct Definitions ---------------------- */
74 
75 /**
76  * @brief   TWAI driver states
77  */
78 typedef enum {
79     TWAI_STATE_STOPPED,             /**< Stopped state. The TWAI controller will not participate in any TWAI bus activities */
80     TWAI_STATE_RUNNING,             /**< Running state. The TWAI controller can transmit and receive messages */
81     TWAI_STATE_BUS_OFF,             /**< Bus-off state. The TWAI controller cannot participate in bus activities until it has recovered */
82     TWAI_STATE_RECOVERING,          /**< Recovering state. The TWAI controller is undergoing bus recovery */
83 } twai_state_t;
84 
85 /**
86  * @brief   Structure for general configuration of the TWAI driver
87  *
88  * @note    Macro initializers are available for this structure
89  */
90 typedef struct {
91     twai_mode_t mode;               /**< Mode of TWAI controller */
92     gpio_num_t tx_io;               /**< Transmit GPIO number */
93     gpio_num_t rx_io;               /**< Receive GPIO number */
94     gpio_num_t clkout_io;           /**< CLKOUT GPIO number (optional, set to -1 if unused) */
95     gpio_num_t bus_off_io;          /**< Bus off indicator GPIO number (optional, set to -1 if unused) */
96     uint32_t tx_queue_len;          /**< Number of messages TX queue can hold (set to 0 to disable TX Queue) */
97     uint32_t rx_queue_len;          /**< Number of messages RX queue can hold */
98     uint32_t alerts_enabled;        /**< Bit field of alerts to enable (see documentation) */
99     uint32_t clkout_divider;        /**< CLKOUT divider. Can be 1 or any even number from 2 to 14 (optional, set to 0 if unused) */
100     int intr_flags;                 /**< Interrupt flags to set the priority of the driver's ISR. Note that to use the ESP_INTR_FLAG_IRAM, the CONFIG_TWAI_ISR_IN_IRAM option should be enabled first. */
101 } twai_general_config_t;
102 
103 /**
104  * @brief   Structure to store status information of TWAI driver
105  */
106 typedef struct {
107     twai_state_t state;             /**< Current state of TWAI controller (Stopped/Running/Bus-Off/Recovery) */
108     uint32_t msgs_to_tx;            /**< Number of messages queued for transmission or awaiting transmission completion */
109     uint32_t msgs_to_rx;            /**< Number of messages in RX queue waiting to be read */
110     uint32_t tx_error_counter;      /**< Current value of Transmit Error Counter */
111     uint32_t rx_error_counter;      /**< Current value of Receive Error Counter */
112     uint32_t tx_failed_count;       /**< Number of messages that failed transmissions */
113     uint32_t rx_missed_count;       /**< Number of messages that were lost due to a full RX queue (or errata workaround if enabled) */
114     uint32_t rx_overrun_count;      /**< Number of messages that were lost due to a RX FIFO overrun */
115     uint32_t arb_lost_count;        /**< Number of instances arbitration was lost */
116     uint32_t bus_error_count;       /**< Number of instances a bus error has occurred */
117 } twai_status_info_t;
118 
119 /* ------------------------------ Public API -------------------------------- */
120 
121 /**
122  * @brief   Install TWAI driver
123  *
124  * This function installs the TWAI driver using three configuration structures.
125  * The required memory is allocated and the TWAI driver is placed in the stopped
126  * state after running this function.
127  *
128  * @param[in]   g_config    General configuration structure
129  * @param[in]   t_config    Timing configuration structure
130  * @param[in]   f_config    Filter configuration structure
131  *
132  * @note    Macro initializers are available for the configuration structures (see documentation)
133  *
134  * @note    To reinstall the TWAI driver, call twai_driver_uninstall() first
135  *
136  * @return
137  *      - ESP_OK: Successfully installed TWAI driver
138  *      - ESP_ERR_INVALID_ARG: Arguments are invalid
139  *      - ESP_ERR_NO_MEM: Insufficient memory
140  *      - ESP_ERR_INVALID_STATE: Driver is already installed
141  */
142 esp_err_t twai_driver_install(const twai_general_config_t *g_config, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config);
143 
144 /**
145  * @brief   Uninstall the TWAI driver
146  *
147  * This function uninstalls the TWAI driver, freeing the memory utilized by the
148  * driver. This function can only be called when the driver is in the stopped
149  * state or the bus-off state.
150  *
151  * @warning The application must ensure that no tasks are blocked on TX/RX
152  *          queues or alerts when this function is called.
153  *
154  * @return
155  *      - ESP_OK: Successfully uninstalled TWAI driver
156  *      - ESP_ERR_INVALID_STATE: Driver is not in stopped/bus-off state, or is not installed
157  */
158 esp_err_t twai_driver_uninstall(void);
159 
160 /**
161  * @brief   Start the TWAI driver
162  *
163  * This function starts the TWAI driver, putting the TWAI driver into the running
164  * state. This allows the TWAI driver to participate in TWAI bus activities such
165  * as transmitting/receiving messages. The TX and RX queue are reset in this function,
166  * clearing any messages that are unread or pending transmission. This function
167  * can only be called when the TWAI driver is in the stopped state.
168  *
169  * @return
170  *      - ESP_OK: TWAI driver is now running
171  *      - ESP_ERR_INVALID_STATE: Driver is not in stopped state, or is not installed
172  */
173 esp_err_t twai_start(void);
174 
175 /**
176  * @brief   Stop the TWAI driver
177  *
178  * This function stops the TWAI driver, preventing any further message from being
179  * transmitted or received until twai_start() is called. Any messages in the TX
180  * queue are cleared. Any messages in the RX queue should be read by the
181  * application after this function is called. This function can only be called
182  * when the TWAI driver is in the running state.
183  *
184  * @warning A message currently being transmitted/received on the TWAI bus will
185  *          be ceased immediately. This may lead to other TWAI nodes interpreting
186  *          the unfinished message as an error.
187  *
188  * @return
189  *      - ESP_OK: TWAI driver is now Stopped
190  *      - ESP_ERR_INVALID_STATE: Driver is not in running state, or is not installed
191  */
192 esp_err_t twai_stop(void);
193 
194 /**
195  * @brief   Transmit a TWAI message
196  *
197  * This function queues a TWAI message for transmission. Transmission will start
198  * immediately if no other messages are queued for transmission. If the TX queue
199  * is full, this function will block until more space becomes available or until
200  * it times out. If the TX queue is disabled (TX queue length = 0 in configuration),
201  * this function will return immediately if another message is undergoing
202  * transmission. This function can only be called when the TWAI driver is in the
203  * running state and cannot be called under Listen Only Mode.
204  *
205  * @param[in]   message         Message to transmit
206  * @param[in]   ticks_to_wait   Number of FreeRTOS ticks to block on the TX queue
207  *
208  * @note    This function does not guarantee that the transmission is successful.
209  *          The TX_SUCCESS/TX_FAILED alert can be enabled to alert the application
210  *          upon the success/failure of a transmission.
211  *
212  * @note    The TX_IDLE alert can be used to alert the application when no other
213  *          messages are awaiting transmission.
214  *
215  * @return
216  *      - ESP_OK: Transmission successfully queued/initiated
217  *      - ESP_ERR_INVALID_ARG: Arguments are invalid
218  *      - ESP_ERR_TIMEOUT: Timed out waiting for space on TX queue
219  *      - ESP_FAIL: TX queue is disabled and another message is currently transmitting
220  *      - ESP_ERR_INVALID_STATE: TWAI driver is not in running state, or is not installed
221  *      - ESP_ERR_NOT_SUPPORTED: Listen Only Mode does not support transmissions
222  */
223 esp_err_t twai_transmit(const twai_message_t *message, TickType_t ticks_to_wait);
224 
225 /**
226  * @brief   Receive a TWAI message
227  *
228  * This function receives a message from the RX queue. The flags field of the
229  * message structure will indicate the type of message received. This function
230  * will block if there are no messages in the RX queue
231  *
232  * @param[out]  message         Received message
233  * @param[in]   ticks_to_wait   Number of FreeRTOS ticks to block on RX queue
234  *
235  * @warning The flags field of the received message should be checked to determine
236  *          if the received message contains any data bytes.
237  *
238  * @return
239  *      - ESP_OK: Message successfully received from RX queue
240  *      - ESP_ERR_TIMEOUT: Timed out waiting for message
241  *      - ESP_ERR_INVALID_ARG: Arguments are invalid
242  *      - ESP_ERR_INVALID_STATE: TWAI driver is not installed
243  */
244 esp_err_t twai_receive(twai_message_t *message, TickType_t ticks_to_wait);
245 
246 /**
247  * @brief   Read TWAI driver alerts
248  *
249  * This function will read the alerts raised by the TWAI driver. If no alert has
250  * been issued when this function is called, this function will block until an alert
251  * occurs or until it timeouts.
252  *
253  * @param[out]  alerts          Bit field of raised alerts (see documentation for alert flags)
254  * @param[in]   ticks_to_wait   Number of FreeRTOS ticks to block for alert
255  *
256  * @note    Multiple alerts can be raised simultaneously. The application should
257  *          check for all alerts that have been enabled.
258  *
259  * @return
260  *      - ESP_OK: Alerts read
261  *      - ESP_ERR_TIMEOUT: Timed out waiting for alerts
262  *      - ESP_ERR_INVALID_ARG: Arguments are invalid
263  *      - ESP_ERR_INVALID_STATE: TWAI driver is not installed
264  */
265 esp_err_t twai_read_alerts(uint32_t *alerts, TickType_t ticks_to_wait);
266 
267 /**
268  * @brief   Reconfigure which alerts are enabled
269  *
270  * This function reconfigures which alerts are enabled. If there are alerts
271  * which have not been read whilst reconfiguring, this function can read those
272  * alerts.
273  *
274  * @param[in]   alerts_enabled  Bit field of alerts to enable (see documentation for alert flags)
275  * @param[out]  current_alerts  Bit field of currently raised alerts. Set to NULL if unused
276  *
277  * @return
278  *      - ESP_OK: Alerts reconfigured
279  *      - ESP_ERR_INVALID_STATE: TWAI driver is not installed
280  */
281 esp_err_t twai_reconfigure_alerts(uint32_t alerts_enabled, uint32_t *current_alerts);
282 
283 /**
284  * @brief   Start the bus recovery process
285  *
286  * This function initiates the bus recovery process when the TWAI driver is in
287  * the bus-off state. Once initiated, the TWAI driver will enter the recovering
288  * state and wait for 128 occurrences of the bus-free signal on the TWAI bus
289  * before returning to the stopped state. This function will reset the TX queue,
290  * clearing any messages pending transmission.
291  *
292  * @note    The BUS_RECOVERED alert can be enabled to alert the application when
293  *          the bus recovery process completes.
294  *
295  * @return
296  *      - ESP_OK: Bus recovery started
297  *      - ESP_ERR_INVALID_STATE: TWAI driver is not in the bus-off state, or is not installed
298  */
299 esp_err_t twai_initiate_recovery(void);
300 
301 /**
302  * @brief   Get current status information of the TWAI driver
303  *
304  * @param[out]  status_info     Status information
305  *
306  * @return
307  *      - ESP_OK: Status information retrieved
308  *      - ESP_ERR_INVALID_ARG: Arguments are invalid
309  *      - ESP_ERR_INVALID_STATE: TWAI driver is not installed
310  */
311 esp_err_t twai_get_status_info(twai_status_info_t *status_info);
312 
313 /**
314  * @brief   Clear the transmit queue
315  *
316  * This function will clear the transmit queue of all messages.
317  *
318  * @note    The transmit queue is automatically cleared when twai_stop() or
319  *          twai_initiate_recovery() is called.
320  *
321  * @return
322  *      - ESP_OK: Transmit queue cleared
323  *      - ESP_ERR_INVALID_STATE: TWAI driver is not installed or TX queue is disabled
324  */
325 esp_err_t twai_clear_transmit_queue(void);
326 
327 /**
328  * @brief   Clear the receive queue
329  *
330  * This function will clear the receive queue of all messages.
331  *
332  * @note    The receive queue is automatically cleared when twai_start() is
333  *          called.
334  *
335  * @return
336  *      - ESP_OK: Transmit queue cleared
337  *      - ESP_ERR_INVALID_STATE: TWAI driver is not installed
338  */
339 esp_err_t twai_clear_receive_queue(void);
340 
341 #ifdef __cplusplus
342 }
343 #endif
344 
345 #endif //SOC_TWAI_SUPPORTED
346