Dual TWAI with Arduino ESP32

Fusion
Posts: 16
Joined: Wed Apr 26, 2017 3:34 pm

Dual TWAI with Arduino ESP32

Postby Fusion » Wed Sep 18, 2024 1:05 pm

Hi everyone!
In my search for some dual TWAI examples for Arduino, I ran into https://github.com/outlandnish/esp32_can which is a fork of the well known https://github.com/collin80/esp32_can/, however this fork was last updated way before the recent release of arduino-esp32 based on IDF 5.2.0+ in 3.1.0-RC1 and probably not tested.
After replacing twai_general_cfg with g_config etc., it unfortunately returns this error:

Code: Select all

/Documents/Arduino/libraries/esp32_can/src/esp32_can_builtin.cpp: In constructor 'ESP32CAN::ESP32CAN(gpio_num_t, gpio_num_t, uint8_t)':
/Documents/Arduino/libraries/esp32_can/src/esp32_can_builtin.cpp:57:16: error: request for member 'controller_id' in '((ESP32CAN*)this)->ESP32CAN::bus_handle', which is of pointer type 'twai_handle_t' {aka 'twai_obj_t*'} (maybe you meant to use '->' ?)
   57 |     bus_handle.controller_id = busNumber;
In similar code for IDF, controller_id is assigned to g_config, however I do not understand how the two controllers are supposed to be distinguished with one bus_handle. The IDF examples use twai_bus_0 and twai_bus_1.
The idea here though is to also distinguish boards that have one TWAI controller vs two, and boards that have an external MCP controller..

Code: Select all

#define Can0 CAN0

#if (SOC_TWAI_CONTROLLER_NUM == 2 and ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)) or defined (HAS_EXTERNAL_CAN_CONTROLLER)
#define Can1 CAN1
#endif

#if (SOC_TWAI_CONTROLLER_NUM == 2 and ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)) and defined (HAS_EXTERNAL_CAN_CONTROLLER)
#define Can2 CAN2
#endif
When I replace

Code: Select all

bus_handle.controller_id = busNumber;
with

Code: Select all

g_config.controller_id = busNumber;
I get rid of the error, but it seems that the controller ID is always 1 as the first instance with ID 0 gets overwritten.

Could someone more familiar with Arduino IDE be willing to have a look at this? I have the hardware to test it, but not the in-depth knowledge of how both controllers should be handled.

The files in question:
https://github.com/outlandnish/esp32_ca ... 32_can.cpp
https://github.com/outlandnish/esp32_ca ... sp32_can.h
https://github.com/outlandnish/esp32_ca ... uiltin.cpp
https://github.com/outlandnish/esp32_ca ... _builtin.h

Thanks!

Fusion
Posts: 16
Joined: Wed Apr 26, 2017 3:34 pm

Re: Dual TWAI with Arduino ESP32

Postby Fusion » Wed Sep 18, 2024 3:42 pm

I have changed a few things in esp32_can_builtin.cpp, but it looks like it isn't switching the controller id.

Code: Select all

17:28:30.013 -> Initializing ...
17:28:30.111 -> TWAI V2 driver installed with controller ID: 0, TX: 17, RX: 16, bus: 1082212888
17:28:30.111 -> TWAI V2 driver started with controller ID: 0, TX: 17, RX: 16
17:28:30.111 -> Builtin CAN0 Init OK ...
17:28:30.209 -> TWAI V2 driver installed with controller ID: 0, TX: 19, RX: 18, bus: 1082214008
17:28:30.209 -> TWAI V2 driver started with controller ID: 0, TX: 19, RX: 18
17:28:30.209 -> Builtin CAN1 Init OK ...
17:28:30.209 -> Ready ...!
17:28:30.307 -> Guru Meditation Error: Core  0 panic'ed (Load access fault). Exception was unhandled.
This is the .ino example

Code: Select all

#include "esp32_can.h"

void setup() {
  delay(3000);
  Serial.begin(115200);
  Serial.println("Initializing ...");

  pinMode(GPIO_NUM_0, OUTPUT);
  digitalWrite(GPIO_NUM_0, LOW); //enable CAN0 (RS) / HIGH for standby mode
  pinMode(GPIO_NUM_3, OUTPUT);
  digitalWrite(GPIO_NUM_3, LOW); //disable CAN0 Shutdown (SHDN), not mandatory / HIGH for shutdown mode
  CAN0.setCANPins(GPIO_NUM_16, GPIO_NUM_17);

  // Initialize builtin CAN0 controller at the specified speed
  if (CAN0.begin(500000)) {
    Serial.println("Builtin CAN0 Init OK ...");
  } else {
    Serial.println("BuiltIn CAN0 Init Failed ...");
  }

  pinMode(GPIO_NUM_1, OUTPUT);
  digitalWrite(GPIO_NUM_1, LOW); //enable CAN1 (RS) / HIGH for standby mode
  pinMode(GPIO_NUM_2, OUTPUT);
  digitalWrite(GPIO_NUM_2, LOW); //disable CAN1 Shutdown (SHDN), not mandatory / HIGH for shutdown mode
  CAN1.setCANPins(GPIO_NUM_18, GPIO_NUM_19);
	
  // Initialize bultin CAN1 controller at the specified speed
  if (CAN1.begin(500000)) {
    Serial.println("Builtin CAN1 Init OK ...");
  } else {
    Serial.println("BuiltIn CAN1 Init Failed ...");
  }

  CAN_FRAME txFrame;
  txFrame.rtr = 0;
  txFrame.id = 0x123;
  txFrame.extended = false;
  txFrame.length = 4;
  txFrame.data.uint8[0] = 0xFF;
  txFrame.data.uint8[1] = 0xFF;
  txFrame.data.uint8[2] = 0xFF;
  txFrame.data.uint8[3] = 0xFF;
  CAN0.sendFrame(txFrame);

  // CAN0.setRXFilter(0, 0x0d, 0x0c, false);
  // CAN0.watchFor(0x0d, 0x0c);
  CAN0.watchFor(); //allow everything else through
  // CAN0.setCallback(0, handleCAN0CB);

  // CAN1.setRXFilter(0, 0x230, 0x7F0, false);
  // CAN1.watchFor(); //allow everything else through
  // CAN1.setCallback(0, handleCAN1CB);

  Serial.println("Ready ...!");
}
And the modified esp32_can_builtin.cpp

Code: Select all

/*
  ESP32_CAN.cpp - Library for ESP32 built-in CAN module
    Now converted to use the built-in TWAI driver in ESP-IDF. This should allow for support for the
    full range of ESP32 hardware and probably be more stable than the old approach.
  
  Author: Collin Kidder
  
  Created: 31/1/18, significant rework 1/5/23
*/

#include "Arduino.h"
#include "esp32_can_builtin.h"

twai_handle_t twai_bus_0;
twai_handle_t twai_bus_1;
                                                                 //tx,         rx,           mode
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_17, GPIO_NUM_16, TWAI_MODE_NORMAL);
twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

QueueHandle_t callbackQueue;
QueueHandle_t rx_queue;

//because of the way the TWAI library works, it's just easier to store the valid timings here and anything not found here
//is just plain not supported. If you need a different speed then add it here. Be sure to leave the zero record at the end
//as it serves as a terminator
const VALID_TIMING valid_timings[] = 
{
    {TWAI_TIMING_CONFIG_1MBITS(), 1000000},
    {TWAI_TIMING_CONFIG_500KBITS(), 500000},
    {TWAI_TIMING_CONFIG_250KBITS(), 250000},
    {TWAI_TIMING_CONFIG_125KBITS(), 125000},
    {TWAI_TIMING_CONFIG_800KBITS(), 800000},
    {TWAI_TIMING_CONFIG_100KBITS(), 100000},
    {TWAI_TIMING_CONFIG_50KBITS(), 50000},
    {TWAI_TIMING_CONFIG_25KBITS(), 25000},
    //caution, these next entries are custom and haven't really been fully tested yet.
    //Note that brp can take values in multiples of 2 up to 128 and multiples of 4 up to 256
    //TSEG1 can be 1 to 16 and TSEG2 can be 1 to 8. There is a silent +1 added to the sum of these two.
    //The default clock is 80MHz so plan accordingly
    {{.brp = 100, .tseg_1 = 7, .tseg_2 = 2, .sjw = 3, .triple_sampling = false}, 80000}, 
    {{.brp = 120, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}, 33333},
    //this one is only possible on ECO2 ESP32 or ESP32-S3 not on the older ESP32 chips
    {{.brp = 200, .tseg_1 = 15, .tseg_2 = 4, .sjw = 3, .triple_sampling = false}, 20000},
    {TWAI_TIMING_CONFIG_25KBITS(), 0} //this is a terminator record. When the code sees an entry with 0 speed it stops searching
};

ESP32CAN::ESP32CAN(gpio_num_t rxPin, gpio_num_t txPin, uint8_t busNumber) : CAN_COMMON(32)
{
    // printf("ESP32CAN::ESP32CAN bus number: %d\n", busNumber);

#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
    if (busNumber == 0) {
        bus_handle = twai_bus_0;
    }
    else if (busNumber == 1) {
        bus_handle = twai_bus_1;
    }
    //bus_handle.controller_id = busNumber;
#endif
    g_config.rx_io = rxPin;
    g_config.tx_io = txPin;
    cyclesSinceTraffic = 0;
    initializedResources = false;
    readyForTraffic = false;
    g_config.tx_queue_len = BI_TX_BUFFER_SIZE;
    g_config.rx_queue_len = 6;
    rxBufferSize = BI_RX_BUFFER_SIZE;
}

ESP32CAN::ESP32CAN() : CAN_COMMON(BI_NUM_FILTERS) 
{
    g_config.tx_queue_len = BI_TX_BUFFER_SIZE;
    g_config.rx_queue_len = 6;

    rxBufferSize = BI_RX_BUFFER_SIZE;

    for (int i = 0; i < BI_NUM_FILTERS; i++)
    {
        filters[i].id = 0;
        filters[i].mask = 0;
        filters[i].extended = false;
        filters[i].configured = false;
    }
    initializedResources = false;
    readyForTraffic = false;
    cyclesSinceTraffic = 0;
}

void ESP32CAN::setCANPins(gpio_num_t rxPin, gpio_num_t txPin)
{
    g_config.rx_io = rxPin;
    g_config.tx_io = txPin;
}

void CAN_WatchDog_Builtin( void *pvParameters )
{
    ESP32CAN* espCan = (ESP32CAN*)pvParameters;
    const TickType_t xDelay = 200 / portTICK_PERIOD_MS;
    twai_status_info_t status_info;

    for(;;)
    {
        vTaskDelay( xDelay );
        espCan->cyclesSinceTraffic++;

        esp_err_t result;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
        result = twai_get_status_info_v2(espCan->bus_handle, &status_info);
#else
        result = twai_get_status_info(&status_info);
#endif
        if (result == ESP_OK)
        {
            if (status_info.state == TWAI_STATE_BUS_OFF)
            {
                espCan->cyclesSinceTraffic = 0;

#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
                result = twai_initiate_recovery_v2(espCan->bus_handle);
#else
                result = twai_initiate_recovery();
#endif
                if (result != ESP_OK)
                {
                    printf("Could not initiate bus recovery!\n");
                }
            }
        }
    }
}

//infinitely loops accepting frames from the TWAI driver. Calls
//our processing routine which then applies the custom 32 filters and
//decides whether to trigger callbacks or queue the frame (or throw it away)
void task_LowLevelRX(void *pvParameters)
{
    ESP32CAN* espCan = (ESP32CAN*)pvParameters;
    
    while (1)
    {
        twai_message_t message;
        if (espCan->readyForTraffic)
        {
            esp_err_t result;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
            result = twai_receive_v2(espCan->bus_handle, &message, pdMS_TO_TICKS(100));
#else
            result = twai_receive(&message, pdMS_TO_TICKS(100));
#endif
            if (result == ESP_OK)
            {
                espCan->processFrame(message);
            }
        }
        else vTaskDelay(pdMS_TO_TICKS(100));
    }
    
}

/*
Issue callbacks to registered functions and objects
Used to keep this kind of thing out of the interrupt handler
The callback type and mailbox are passed in the fid member of the
CAN_FRAME struct. It isn't really used by anything.
Layout of the storage:
bit   31 -    If set indicates an object callback
bits  24-30 - Idx into listener table
bits  0-7   - Mailbox number that triggered callback
*/
void task_CAN( void *pvParameters )
{
    ESP32CAN* espCan = (ESP32CAN*)pvParameters;
    CAN_FRAME rxFrame;

    while (1)
    {
        //receive next CAN frame from queue and fire off the callback
        if(xQueueReceive(callbackQueue, &rxFrame, portMAX_DELAY)==pdTRUE)
        {
            espCan->sendCallback(&rxFrame);
        }
    }
}

void ESP32CAN::sendCallback(CAN_FRAME *frame)
{
    //frame buffer
    CANListener *thisListener;
    int mb;
    int idx;

    mb = (frame->fid & 0xFF);
    if (mb == 0xFF) mb = -1;

    if (frame->fid & 0x80000000ul) //object callback
    {
        idx = (frame->fid >> 24) & 0x7F;
        thisListener = listener[idx];
        thisListener->gotFrame(frame, mb);
    }
    else //C function callback
    {
        if (mb > -1) (*cbCANFrame[mb])(frame);
        else (*cbGeneral)(frame);
    }
}

void ESP32CAN::setRXBufferSize(int newSize)
{
    rxBufferSize = newSize;
}

void ESP32CAN::setTXBufferSize(int newSize)
{
    g_config.tx_queue_len = newSize;
}

int ESP32CAN::_setFilterSpecific(uint8_t mailbox, uint32_t id, uint32_t mask, bool extended)
{
    if (mailbox < BI_NUM_FILTERS)
    {
        filters[mailbox].id = id & mask;
        filters[mailbox].mask = mask;
        filters[mailbox].extended = extended;
        filters[mailbox].configured = true;
        return mailbox;
    }
    return -1;
}

int ESP32CAN::_setFilter(uint32_t id, uint32_t mask, bool extended)
{
    for (int i = 0; i < BI_NUM_FILTERS; i++)
    {
        if (!filters[i].configured) 
        {
            _setFilterSpecific(i, id, mask, extended);
            return i;
        }
    }
    if (debuggingMode) Serial.println("Could not set filter!");
    return -1;
}

void ESP32CAN::_init()
{
    if (debuggingMode) Serial.println("Built in CAN Init");
    for (int i = 0; i < BI_NUM_FILTERS; i++)
    {
        filters[i].id = 0;
        filters[i].mask = 0;
        filters[i].extended = false;
        filters[i].configured = false;
    }

    if (!initializedResources)
    {
        if (debuggingMode) printf("Initializing resources for built-in CAN\n");

                                 //Queue size, item size
        callbackQueue = xQueueCreate(16, sizeof(CAN_FRAME));
        rx_queue = xQueueCreate(rxBufferSize, sizeof(CAN_FRAME));
        if (debuggingMode) Serial.println("Created queues.");

                  //func        desc    stack, params, priority, handle to task
        xTaskCreate(&task_CAN, "CAN_RX", 8192, this, 15, NULL);
        if (debuggingMode) Serial.println("task rx created.");
        if (debuggingMode) Serial.println("task low level rx created.");

#if defined(CONFIG_FREERTOS_UNICORE)
        xTaskCreate(&CAN_WatchDog_Builtin, "CAN_WD_BI", 2048, this, 10, NULL);
#else
        xTaskCreatePinnedToCore(&CAN_WatchDog_Builtin, "CAN_WD_BI", 2048, this, 10, NULL, 1);
#endif
        if (debuggingMode) Serial.println("task watchdog created.");
        initializedResources = true;
    }
    if (debuggingMode) Serial.println("_init done");
}

uint32_t ESP32CAN::init(uint32_t ul_baudrate)
{
    _init();
    set_baudrate(ul_baudrate);
    if (debuggingMode)
    {
        //Reconfigure alerts to detect Error Passive and Bus-Off error states
        uint32_t alerts_to_enable = TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_OFF | TWAI_ALERT_AND_LOG | TWAI_ALERT_ERR_ACTIVE 
                                  | TWAI_ALERT_ARB_LOST | TWAI_ALERT_BUS_ERROR | TWAI_ALERT_TX_FAILED | TWAI_ALERT_RX_QUEUE_FULL;

        esp_err_t result;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
        result = twai_reconfigure_alerts_v2(bus_handle, alerts_to_enable, NULL);
#else
        result = twai_reconfigure_alerts(alerts_to_enable, NULL);
#endif
        if (result == ESP_OK)
        {
            printf("Alerts reconfigured\n");
        }
        else
        {
            printf("Failed to reconfigure alerts");
        }
    }
    //this task implements our better filtering on top of the TWAI library. Accept all frames then filter in here VVVVV
#if defined(CONFIG_FREERTOS_UNICORE)
    xTaskCreate(&task_LowLevelRX, "CAN_LORX", 4096, this, 19, NULL);
#else
    xTaskCreatePinnedToCore(&task_LowLevelRX, "CAN_LORX", 4096, this, 19, NULL, 1);
#endif
    readyForTraffic = true;
    return ul_baudrate;
}

uint32_t ESP32CAN::beginAutoSpeed()
{
    twai_general_config_t oldMode = g_config;

    _init();

    readyForTraffic = false;
    twai_stop();
    g_config.mode = TWAI_MODE_LISTEN_ONLY;
    int idx = 0;
    while (valid_timings[idx].speed != 0)
    {
        t_config = valid_timings[idx].cfg;
        disable();
        Serial.print("Trying Speed ");
        Serial.print(valid_timings[idx].speed);
        enable();
        delay(600); //wait a while
        if (cyclesSinceTraffic < 2) //only would happen if there had been traffic
        {
            disable();
            g_config.mode = oldMode.mode;
            enable();
            Serial.println(" SUCCESS!");
            return valid_timings[idx].speed;
        }
        else
        {
            Serial.println(" FAILED.");
        }
        idx++;
    }
    Serial.println("None of the tested CAN speeds worked!");
    twai_stop();
    return 0;
}

uint32_t ESP32CAN::set_baudrate(uint32_t ul_baudrate)
{
    disable();
    //now try to find a valid timing to use
    int idx = 0;
    while (valid_timings[idx].speed != 0)
    {
        if (valid_timings[idx].speed == ul_baudrate)
        {
            t_config = valid_timings[idx].cfg;
            enable();
            return ul_baudrate;
        }
        idx++;
    }
    printf("Could not find a valid bit timing! You will need to add your desired speed to the library!\n");
    return 0;
}

void ESP32CAN::setListenOnlyMode(bool state)
{
    disable();
    g_config.mode = state?TWAI_MODE_LISTEN_ONLY:TWAI_MODE_NORMAL;
    enable();
}

void ESP32CAN::enable()
{
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
    if (bus_handle == twai_bus_0) {
        g_config.controller_id = 0;
    }
    else if (bus_handle == twai_bus_1) {
        g_config.controller_id = 1;
    }

    //printf("ESP32CAN::enable controller_id: %d\n", g_config.controller_id);

    if (twai_driver_install_v2(&g_config, &t_config, &f_config, &bus_handle) == ESP_OK) {
        printf("TWAI V2 driver installed with controller ID: %d, RX: %d, TX: %d, bus: %d\n", g_config.controller_id, g_config.rx_io, g_config.tx_io, bus_handle);
    } else {
        printf("Failed to install TWAI V2 driver for controller ID: %d\n", g_config.controller_id);
        return;
    }
    //Start TWAI driver
    if (twai_start_v2(bus_handle) == ESP_OK) {
        printf("TWAI V2 driver started with controller ID: %d, RX: %d, TX: %d\n", g_config.controller_id, g_config.rx_io, g_config.tx_io);
    } else {
        printf("Failed to start TWAI V2 driver for controller ID: %d\n", g_config.controller_id);
        return;
    }
#else
    if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK)
    {
        //printf("TWAI Driver installed\n");
    }
    else
    {
        printf("Failed to install TWAI driver\n");
        return;
    }
    // Start TWAI driver
    if (twai_start() == ESP_OK)
    {
        //printf("TWAI Driver started\n");
    }
    else
    {
        printf("Failed to start TWAI driver\n");
        return;
    }
#endif

    readyForTraffic = true;
}

void ESP32CAN::disable()
{
    readyForTraffic = false;
    twai_stop();
    vTaskDelay(pdMS_TO_TICKS(100)); //a bit of delay here seems to fix a race condition triggered by task_LowLevelRX
    twai_driver_uninstall();
}

//This function is too big to be running in interrupt context. Refactored so it doesn't.
bool ESP32CAN::processFrame(twai_message_t &frame)
{
    CANListener *thisListener;
    CAN_FRAME msg;

    cyclesSinceTraffic = 0; //reset counter to show that we are receiving traffic

    msg.id = frame.identifier;
    msg.length = frame.data_length_code;
    msg.rtr = frame.rtr;
    msg.extended = frame.extd;
    for (int i = 0; i < 8; i++) msg.data.byte[i] = frame.data[i];
    
    for (int i = 0; i < BI_NUM_FILTERS; i++)
    {
        if (!filters[i].configured) continue;
        if ((msg.id & filters[i].mask) == filters[i].id && (filters[i].extended == msg.extended))
        {
            //frame is accepted, lets see if it matches a mailbox callback
            if (cbCANFrame[i])
            {
                msg.fid = i;
                xQueueSend(callbackQueue, &msg, 0);
                return true;
            }
            else if (cbGeneral)
            {
                msg.fid = 0xFF;
                xQueueSend(callbackQueue, &msg, 0);
                return true;
            }
            else
            {
                for (int listenerPos = 0; listenerPos < SIZE_LISTENERS; listenerPos++)
                {
                    thisListener = listener[listenerPos];
                    if (thisListener != NULL)
                    {
                        if (thisListener->isCallbackActive(i)) 
                        {
                            msg.fid = 0x80000000ul + (listenerPos << 24ul) + i;
                            xQueueSend(callbackQueue, &msg, 0);
                            return true;
                        }
                        else if (thisListener->isCallbackActive(numFilters)) //global catch-all 
                        {
                            msg.fid = 0x80000000ul + (listenerPos << 24ul) + 0xFF;
                            xQueueSend(callbackQueue, &msg, 0);
                            return true;
                        }
                    }
                }
            }
            
            //otherwise, send frame to input queue
            xQueueSend(rx_queue, &msg, 0);
            if (debuggingMode) Serial.write('_');
            return true;
        }
    }
    return false;
}

bool ESP32CAN::sendFrame(CAN_FRAME& txFrame)
{
    twai_message_t __TX_frame;

    __TX_frame.identifier = txFrame.id;
    __TX_frame.data_length_code = txFrame.length;
    __TX_frame.rtr = txFrame.rtr;
    __TX_frame.extd = txFrame.extended;
    for (int i = 0; i < 8; i++) __TX_frame.data[i] = txFrame.data.byte[i];

    //don't wait long if the queue was full. The end user code shouldn't be sending faster
    //than the buffer can empty. Set a bigger TX buffer or delay sending if this is a problem.
    esp_err_t result;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
    result = twai_transmit_v2(bus_handle, &__TX_frame, pdMS_TO_TICKS(4));
#else
    result = twai_transmit(&__TX_frame, pdMS_TO_TICKS(4));
#endif
    switch (result)
    {
    case ESP_OK:
        if (debuggingMode) Serial.write('<');
        break;
    case ESP_ERR_TIMEOUT:
        if (debuggingMode) Serial.write('T');
        break;
    case ESP_ERR_INVALID_ARG:
    case ESP_FAIL:
    case ESP_ERR_INVALID_STATE:
    case ESP_ERR_NOT_SUPPORTED:
        if (debuggingMode) Serial.write('!');
        break;
    }
    
    return true;
}

bool ESP32CAN::rx_avail()
{
    if (!rx_queue) return false;
    return uxQueueMessagesWaiting(rx_queue) > 0?true:false;
}

uint16_t ESP32CAN::available()
{
    if (!rx_queue) return 0;
    return uxQueueMessagesWaiting(rx_queue);
}

uint32_t ESP32CAN::get_rx_buff(CAN_FRAME &msg)
{
    CAN_FRAME frame;
    //receive next CAN frame from queue
    if(xQueueReceive(rx_queue,&frame, 0) == pdTRUE)
    {
        msg = frame; //do a copy in the case that the receive worked
        return true;
    }
    return false; //otherwise we leave the msg variable alone and just return false
}

Who is online

Users browsing this forum: No registered users and 93 guests