2024-12-28 16:46:15 +00:00
/*
xdrv_91_esp32_twai . ino - ESP32 TWAI support for Tasmota
2025-01-01 13:14:23 +00:00
SPDX - FileCopyrightText : 2025 Theo Arends
2024-12-28 16:46:15 +00:00
SPDX - License - Identifier : GPL - 3.0 - only
*/
# ifdef ESP32
# ifdef USE_ESP32_TWAI
2025-01-01 13:14:23 +00:00
# if SOC_TWAI_SUPPORTED
2024-12-28 16:46:15 +00:00
/*********************************************************************************************\
2025-01-01 13:14:23 +00:00
* ESP32 Two - Wire Automotive Interface ( TWAI ) or Controller Area Network ( CAN ) busses .
* - Supports all TWAI busses provided by different ESP32 architectures .
* - Needs external tranceiver like M5Unit Mini CAN ( not isolated ! ) or M5Unit CANBus ( isolated ) .
2024-12-28 16:46:15 +00:00
*
2025-01-01 13:14:23 +00:00
* The TWAI controller is not compatible with ISO11898 - 1 FD Format frames , and will interpret
* such frames as errors . CAN bus message format is 32 - bit identifier and up to 8 bytes of data
2024-12-28 16:46:15 +00:00
*
2025-01-01 13:14:23 +00:00
* Due to the CAN - bus nature of many received datagrams you ' ll needs a berry driver with
* class " twai " and functions " config " and " decode " .
* - See example below .
* - When executed by ` preinit . be ` it allows to configure the TWAI driver mode and speed
*
2025-01-03 09:37:18 +00:00
* For more information see https : //tasmota.github.io/docs/TWAI/
*
2025-01-01 13:14:23 +00:00
* Supported command :
* TwaiSend [ < bus > ] < identifier > [ [ [ [ [ [ [ [ < data1 > ] , < data2 > ] , < data3 > ] , < data4 > ] , < data5 > ] , < data6 > ] , < data7 > ] , < data8 > ]
* TwaiSend [ < bus > ] { " ID " : < identifier > , [ " DATA " : [ [ [ [ [ [ [ < data1 > ] , < data2 > ] , < data3 > ] , < data4 > ] , < data5 > ] , < data6 > ] , < data7 > ] , < data8 > ] ] }
* - An < identifier > with bit 31 set ( 0x80000000 ) is a 29 - bit identifier
* - All < data > is optional
*
* Examples :
* TwaiSend1 0x481 , 0x03 , 0x1E , 0xFF , 0xFF , 0xFF , 0x01 , 0x21
* TwaiSend1 { " ID " : 0x481 , " DATA " : [ 0x03 , 0x1E , 0xFF , 0xFF , 0xFF , 0x01 , 0x21 ] }
* TwaiSend2 { " ID " : 0x80000481 , " DATA " : [ 0x03 , 0x1E , 0xFF , 0xFF , 0xFF , 0x01 , 0x21 ] }
2024-12-28 16:46:15 +00:00
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define XDRV_91 91
# define TWAI_POLLING_RATE_MS 100
2024-12-29 16:07:05 +00:00
# include "driver/twai.h"
2024-12-28 16:46:15 +00:00
enum TwaiSpeeds { TWAI_SPEED_25KBITS = 0 ,
TWAI_SPEED_50KBITS ,
TWAI_SPEED_100KBITS ,
TWAI_SPEED_125KBITS ,
TWAI_SPEED_250KBITS ,
TWAI_SPEED_500KBITS ,
TWAI_SPEED_800KBITS ,
TWAI_SPEED_1MBITS ,
TWAI_SPEED_MAX } ;
2024-12-29 16:07:05 +00:00
const char kTwaiSpeeds [ ] PROGMEM = " 25K|50K|100K|125K|250K|500K|800K|1M " ;
const char kTwaiModes [ ] PROGMEM = " Normal|No Ack|Listen Only " ;
2024-12-28 16:46:15 +00:00
struct TWAIs {
2025-01-01 13:14:23 +00:00
twai_handle_t bus [ MAX_TWAI ] ;
twai_mode_t mode [ MAX_TWAI ] ;
uint8_t speed [ MAX_TWAI ] ;
bool installed [ MAX_TWAI ] ;
2024-12-28 16:46:15 +00:00
bool supported ;
} Twai ;
2024-12-29 16:07:05 +00:00
# ifdef USE_BERRY
/*********************************************************************************************\
* Berry example code
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
2025-01-03 09:37:18 +00:00
file twai_minimal . be contents :
2024-12-29 16:07:05 +00:00
class twai_cls
2025-01-03 09:37:18 +00:00
var twai_speed , twai_mode # ( int , int )
2024-12-29 16:07:05 +00:00
def init ( )
2025-01-03 09:37:18 +00:00
self . twai_speed = 4 # 0 = 25 K , 1 = 50 K , 2 = 100 K , 3 = 125 K , 4 = 250 K , 5 = 500 K , 6 = 800 K , 7 = 1 Mbits
2024-12-29 16:07:05 +00:00
self . twai_mode = 2 # 0 = TWAI_MODE_NORMAL , 1 = TWAI_MODE_NO_ACK , 2 = TWAI_MODE_LISTEN_ONLY
end
2025-01-01 14:48:02 +00:00
# ----------------------------------------------------------------------------------------------
Allow TWAI driver configuration on restart ( if this file is installed by preinit . be )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
2025-01-03 09:37:18 +00:00
def config ( bus ) # This function name ( config ) is called by the TWAI driver !
2025-01-01 13:14:23 +00:00
return self . twai_mode < < 3 | self . twai_speed # Initial configure TWAI driver
2024-12-29 16:07:05 +00:00
end
2025-01-01 14:48:02 +00:00
# ----------------------------------------------------------------------------------------------
2025-01-03 09:37:18 +00:00
This example decodes nothing but allows for the driver to show message logging in log level 4
2025-01-01 14:48:02 +00:00
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
2025-01-03 09:37:18 +00:00
def decode ( param , ident , data1 , data2 ) # This function name ( decode ) is called by the TWAI driver !
2025-01-01 14:48:02 +00:00
var bus = param & 0xF # Bus number ( 1. .3 )
var len = param > > 4 & 0xF # Number of data bytes ( 0. .8 )
var extended = ident > > 31 & 0x1 # Extended identifier flag ( 0. .1 )
var id = ident & 0x1fffffff
2024-12-29 16:07:05 +00:00
end
end
2025-01-01 14:48:02 +00:00
2025-01-03 09:37:18 +00:00
twai = twai_cls ( ) # This class name ( twai ) is used by the TWAI driver !
2024-12-29 16:07:05 +00:00
tasmota . add_driver ( twai )
// *******************************************************************************************
file preinit . be contents :
2025-01-03 09:37:18 +00:00
load ( ' twai_minimal . be ' )
2024-12-29 16:07:05 +00:00
*/
2024-12-28 16:46:15 +00:00
/*********************************************************************************************\
2024-12-29 16:07:05 +00:00
* Berry interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2025-01-01 13:14:23 +00:00
bool TWAIBerryDecode ( uint32_t bus , uint32_t identifier , uint32_t data_length_code , uint8_t * data ) {
2024-12-29 16:07:05 +00:00
bvm * vm = berry . vm ;
if ( nullptr = = vm ) { return false ; }
bool handled = false ;
if ( be_getglobal ( vm , " twai " ) ) { // Look for class
if ( be_getmember ( vm , 1 , " decode " ) ) { // and function
be_pushvalue ( vm , - 2 ) ;
2025-01-01 14:48:02 +00:00
uint32_t param = bus + 1 | data_length_code < < 4 ;
uint32_t ident = identifier ;
2024-12-29 16:07:05 +00:00
uint32_t data1 = data [ 3 ] < < 24 | data [ 2 ] < < 16 | data [ 1 ] < < 8 | data [ 0 ] ;
uint32_t data2 = data [ 7 ] < < 24 | data [ 6 ] < < 16 | data [ 5 ] < < 8 | data [ 4 ] ;
2025-01-01 14:48:02 +00:00
AddLog ( LOG_LEVEL_DEBUG_MORE , PSTR ( " TWA: Bus%d param %08X, ident %08X, data1 %08X, data2 %08X " ) , bus + 1 , param , ident , data1 , data2 ) ;
2024-12-29 16:07:05 +00:00
2025-01-01 14:48:02 +00:00
be_pushint ( vm , param ) ; // Bus 1, 2 or 3 | data_length
2024-12-29 16:07:05 +00:00
be_pushint ( vm , ident ) ;
be_pushint ( vm , data1 ) ;
be_pushint ( vm , data2 ) ;
2025-01-01 13:14:23 +00:00
int32_t ret = be_pcall ( vm , 5 ) ; // Number of arguments, self, bus, ident. data1, data2
2024-12-29 16:07:05 +00:00
if ( ret ! = 0 ) {
be_error_pop_all ( vm ) ; // Clear Berry stack
}
handled = true ;
}
}
be_pop ( vm , be_top ( vm ) ) ; // Clean
return handled ;
}
/*********************************************************************************************/
2025-01-01 13:14:23 +00:00
bool TWAIBerryConfig ( uint32_t bus ) {
2024-12-29 16:07:05 +00:00
bvm * vm = berry . vm ;
if ( nullptr = = vm ) { return false ; }
bool handled = false ;
if ( be_getglobal ( vm , " twai " ) ) { // Look for class
if ( be_getmember ( vm , 1 , " config " ) ) { // and function
be_pushvalue ( vm , - 2 ) ;
2025-01-01 13:14:23 +00:00
be_pushint ( vm , bus + 1 ) ; // Bus 1, 2 or 3
int32_t ret = be_pcall ( vm , 2 ) ; // Number of arguments, self, bus
2024-12-29 16:07:05 +00:00
if ( ret ! = 0 ) {
be_error_pop_all ( vm ) ; // Clear Berry stack
}
2025-01-01 13:14:23 +00:00
be_pop ( vm , 2 ) ;
2024-12-29 16:07:05 +00:00
if ( be_isint ( vm , - 1 ) ) {
uint32_t config = be_toint ( vm , - 1 ) ;
2025-01-01 13:14:23 +00:00
Twai . speed [ bus ] = config & 0x7 ; // User input check 0..7
2024-12-29 16:07:05 +00:00
uint32_t mode = config > > 3 & 0x3 ;
if ( mode > 2 ) { mode = 2 ; } // User input check 0..2
2025-01-01 13:14:23 +00:00
Twai . mode [ bus ] = ( twai_mode_t ) mode ;
2024-12-29 16:07:05 +00:00
handled = true ;
}
}
}
be_pop ( vm , be_top ( vm ) ) ; // Clean
return handled ;
}
# endif // USE_BERRY
/*********************************************************************************************\
* TWAI low level
2024-12-28 16:46:15 +00:00
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2025-01-01 13:14:23 +00:00
bool TWAIStart ( int tx , int rx , uint32_t bus = 0 ) ;
bool TWAIStart ( int tx , int rx , uint32_t bus ) {
twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT ( ( gpio_num_t ) tx , ( gpio_num_t ) rx , Twai . mode [ bus ] ) ;
g_config . controller_id = bus ;
2024-12-28 16:46:15 +00:00
g_config . rx_queue_len = 32 ;
twai_timing_config_t t_config ;
2025-01-01 13:14:23 +00:00
switch ( Twai . speed [ bus ] ) {
2024-12-28 16:46:15 +00:00
case 0 :
t_config = TWAI_TIMING_CONFIG_25KBITS ( ) ;
break ;
case 1 :
t_config = TWAI_TIMING_CONFIG_50KBITS ( ) ;
break ;
case 2 :
t_config = TWAI_TIMING_CONFIG_100KBITS ( ) ;
break ;
case 3 :
t_config = TWAI_TIMING_CONFIG_125KBITS ( ) ;
break ;
case 4 :
t_config = TWAI_TIMING_CONFIG_250KBITS ( ) ;
break ;
case 5 :
t_config = TWAI_TIMING_CONFIG_500KBITS ( ) ;
break ;
case 6 :
t_config = TWAI_TIMING_CONFIG_800KBITS ( ) ;
break ;
case 7 :
t_config = TWAI_TIMING_CONFIG_1MBITS ( ) ;
break ;
default :
t_config = TWAI_TIMING_CONFIG_125KBITS ( ) ;
break ;
}
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL ( ) ;
2025-01-01 13:14:23 +00:00
if ( twai_driver_install_v2 ( & g_config , & t_config , & f_config , & Twai . bus [ bus ] ) ! = ESP_OK ) {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TWA: Bus%d Not installed " ) , bus + 1 ) ;
2024-12-28 16:46:15 +00:00
return false ;
}
2025-01-01 13:14:23 +00:00
if ( twai_start_v2 ( Twai . bus [ bus ] ) ! = ESP_OK ) {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TWA: Bus%d Not started " ) , bus + 1 ) ;
2024-12-28 16:46:15 +00:00
return false ;
}
// Reconfigure alerts to detect frame receive, Bus-Off error and RX queue full states
uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_RX_QUEUE_FULL | TWAI_ALERT_TX_IDLE | TWAI_ALERT_TX_SUCCESS | TWAI_ALERT_TX_FAILED | TWAI_ALERT_ERR_PASS | TWAI_ALERT_BUS_ERROR ;
2025-01-01 13:14:23 +00:00
if ( twai_reconfigure_alerts_v2 ( Twai . bus [ bus ] , alerts_to_enable , NULL ) ! = ESP_OK ) {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TWA: Bus%d Failed to reconfigure CAN alerts " ) , bus + 1 ) ;
2024-12-28 16:46:15 +00:00
return false ;
}
2024-12-29 16:07:05 +00:00
char smode [ 16 ] ;
2025-01-01 13:14:23 +00:00
GetTextIndexed ( smode , sizeof ( smode ) , Twai . mode [ bus ] , kTwaiModes ) ;
2024-12-29 16:07:05 +00:00
char sspeed [ 16 ] ;
2025-01-01 13:14:23 +00:00
GetTextIndexed ( sspeed , sizeof ( sspeed ) , Twai . speed [ bus ] , kTwaiSpeeds ) ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TWA: Bus%d using GPIO%02d(Tx) and GPIO%02d(Rx) started in %s Mode and %sbit/s " ) ,
bus + 1 , tx , rx , smode , sspeed ) ;
Twai . installed [ bus ] = true ;
2024-12-28 16:46:15 +00:00
return true ;
}
/*********************************************************************************************/
2025-01-01 13:14:23 +00:00
void TWAIStop ( uint32_t bus ) {
if ( Twai . installed [ bus ] ) {
twai_stop_v2 ( Twai . bus [ bus ] ) ;
twai_driver_uninstall_v2 ( Twai . bus [ bus ] ) ;
Twai . installed [ bus ] = false ;
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TWA: Bus%d stopped " ) , bus + 1 ) ;
2024-12-28 16:46:15 +00:00
}
}
/*********************************************************************************************/
2025-01-01 13:14:23 +00:00
uint32_t TWAICheckAlerts ( uint32_t bus ) {
2024-12-28 16:46:15 +00:00
uint32_t alerts_triggered ;
2025-01-01 13:14:23 +00:00
twai_read_alerts_v2 ( Twai . bus [ bus ] , & alerts_triggered , pdMS_TO_TICKS ( TWAI_POLLING_RATE_MS ) ) ;
2024-12-28 16:46:15 +00:00
twai_status_info_t twaistatus ;
2025-01-01 13:14:23 +00:00
twai_get_status_info_v2 ( Twai . bus [ bus ] , & twaistatus ) ;
2024-12-28 16:46:15 +00:00
// Handle alerts
if ( alerts_triggered & TWAI_ALERT_ERR_PASS ) {
2025-01-01 13:14:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TWA: Bus%d Alert - Controller has become error passive " ) , bus + 1 ) ;
2024-12-28 16:46:15 +00:00
}
if ( alerts_triggered & TWAI_ALERT_BUS_ERROR ) {
2025-01-01 13:14:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TWA: Bus%d Alert - A Bit, Stuff, CRC, Form or ACK error has occurred on the bus. Errors %d " ) , bus + 1 , twaistatus . bus_error_count ) ;
2024-12-28 16:46:15 +00:00
}
if ( alerts_triggered & TWAI_ALERT_RX_QUEUE_FULL ) {
2025-01-01 13:14:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TWA: Bus%d Alert - RX queue is full causing a received frame to be lost. Buffered %d, Missed %d, Overrun %d " ) ,
bus + 1 , twaistatus . msgs_to_rx , twaistatus . rx_missed_count , twaistatus . rx_overrun_count ) ;
2024-12-28 16:46:15 +00:00
}
if ( alerts_triggered & TWAI_ALERT_TX_FAILED ) {
2025-01-01 13:14:23 +00:00
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TWA: Bus%d Alert - Transmission failed. Buffered %d, Error %d, Failed %d " ) ,
bus + 1 , twaistatus . msgs_to_tx , twaistatus . tx_error_counter , twaistatus . tx_failed_count ) ;
2024-12-28 16:46:15 +00:00
}
2025-01-01 13:14:23 +00:00
// if (alerts_triggered & TWAI_ALERT_TX_SUCCESS) {
// AddLog(LOG_LEVEL_DEBUG, PSTR("TWA: Bus%d Transmission successful. Buffered %d"), bus +1, twaistatus.msgs_to_tx);
// }
2024-12-28 16:46:15 +00:00
return alerts_triggered ;
}
/*********************************************************************************************/
2025-01-01 13:14:23 +00:00
void TWAIRead ( uint32_t bus ) {
uint32_t alerts_triggered = TWAICheckAlerts ( bus ) ;
2024-12-28 16:46:15 +00:00
// Check if message is received
if ( alerts_triggered & TWAI_ALERT_RX_DATA ) {
// One or more messages received. Handle all.
twai_message_t message ;
2025-01-01 13:14:23 +00:00
while ( twai_receive_v2 ( Twai . bus [ bus ] , & message , 0 ) = = ESP_OK ) {
2025-01-01 14:48:02 +00:00
uint32_t identifier = message . identifier | message . extd < < 31 ; // Add extended 29-bit flag
2024-12-28 16:46:15 +00:00
# ifdef USE_BERRY
2025-01-01 14:48:02 +00:00
if ( TWAIBerryDecode ( bus , identifier , message . data_length_code , message . data ) ) { continue ; }
2024-12-29 16:07:05 +00:00
# endif // USE_BERRY
// Show log if no berry found (Messages come too fast for supporting MQTT at this time)
2025-01-01 13:14:23 +00:00
AddLog ( LOG_LEVEL_DEBUG_MORE , PSTR ( " TWA: Bus%d Id 0x%08X, Rcvd '%*_H' " ) ,
2025-01-01 14:48:02 +00:00
bus + 1 , identifier , message . data_length_code , message . data ) ;
2024-12-28 16:46:15 +00:00
}
}
}
/*********************************************************************************************\
* Initialization
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void TWAIInit ( void ) {
2025-01-01 13:14:23 +00:00
Twai . supported = false ;
for ( uint32_t bus = 0 ; bus < MAX_TWAI ; bus + + ) {
if ( PinUsed ( GPIO_TWAI_TX , bus ) & & PinUsed ( GPIO_TWAI_RX , bus ) ) {
2025-01-02 11:44:49 +00:00
Twai . speed [ bus ] = TWAI_SPEED_100KBITS ;
Twai . mode [ bus ] = TWAI_MODE_NORMAL ; // 0 = TWAI_MODE_NORMAL, 1 = TWAI_MODE_NO_ACK, 2 = TWAI_MODE_LISTEN_ONLY
2024-12-29 16:07:05 +00:00
# ifdef USE_BERRY
2025-01-01 13:14:23 +00:00
TWAIBerryConfig ( bus ) ;
2024-12-29 16:07:05 +00:00
# endif // USE_BERRY
2025-01-01 13:14:23 +00:00
if ( TWAIStart ( Pin ( GPIO_TWAI_TX , bus ) , Pin ( GPIO_TWAI_RX , bus ) , bus ) ) {
Twai . supported = true ;
}
}
}
}
/*********************************************************************************************\
* Commands
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
const char kTwaiCommands [ ] PROGMEM = " TWAI| " // Prefix
" Send " ;
void ( * const TwaiCommand [ ] ) ( void ) PROGMEM = {
& CmndTWAISend } ;
void CmndTWAISend ( void ) {
// TwaiSend<bus> <identifier>[[[[[[[[<data1>],<data2>],<data3>],<data4>],<data5>],<data6>],<data7>],<data8>]
// TwaiSend<bus> {"ID":<identifier>,"DATA":[[[[[[[[<data1>],<data2>],<data3>],<data4>],<data5>],<data6>],<data7>],<data8>]]}
// An identifier with bit 32 set (0x80000000) is a 29-bit identifier
// TwaiSend1 0x481,0x03,0x1E,0xFF,0xFF,0xFF,0x01,0x21
// TwaiSend1 {"ID":0x481,"DATA":[0x03,0x1E,0xFF,0xFF,0xFF,0x01,0x21]}
// TwaiSend2 {"ID":0x80000481,"DATA":[0x03,0x1E,0xFF,0xFF,0xFF,0x01,0x21]}
if ( ( XdrvMailbox . index > 0 ) & & ( XdrvMailbox . index < = MAX_TWAI ) & & ( XdrvMailbox . data_len > 0 ) ) {
uint32_t bus = XdrvMailbox . index - 1 ;
if ( ! Twai . installed [ bus ] ) { return ; }
uint32_t data [ 9 ] = { 0 } ; // Accomodate identifier and 8 data bytes
uint32_t data_count = 0 ;
if ( XdrvMailbox . data [ 0 ] = = ( ' { ' ) ) {
// parse JSON
JsonParser parser ( XdrvMailbox . data ) ;
JsonParserObject root = parser . getRootObject ( ) ;
if ( ! root ) { return ; } // No valid JSON
JsonParserToken val = root [ PSTR ( " ID " ) ] ;
if ( ! val ) { return ; } // We need at least an identifier
data [ 0 ] = val . getUInt ( ) ;
data_count = 1 ;
JsonParserArray arr = root [ PSTR ( " DATA " ) ] ;
for ( auto value : arr ) { // All data is optional
data [ data_count ] = value . getUInt ( ) ;
data_count + + ;
if ( 9 = = data_count ) {
break ;
}
}
} else {
// parse comma separated values
data_count = ParseParameters ( 9 , data ) ;
}
twai_message_t message ;
message . extd = ( data [ 0 ] & 0x80000000 ) ? 1 : 0 ; // Standard (0) vs extended (1) format
message . rtr = 0 , // Data (0) vs RTR (1) frame
message . ss = 0 , // Whether the message is single shot (1) (i.e., does not repeat on error)
message . self = 0 , // Whether the message is a self reception request (1) (loopback)
message . dlc_non_comp = 0 , // DLC is less than 8 (0)
message . identifier = data [ 0 ] & 0x1FFFFFFF ; // Message ID (11-bits or 29-bits)
message . data_length_code = data_count - 1 ; // Payload length (0..8)
for ( uint8_t i = 0 ; i < message . data_length_code ; i + + ) {
message . data [ i ] = data [ i + 1 ] ; // Payload
}
twai_clear_receive_queue_v2 ( Twai . bus [ bus ] ) ;
//Queue message for transmission
if ( twai_transmit_v2 ( Twai . bus [ bus ] , & message , pdMS_TO_TICKS ( TWAI_POLLING_RATE_MS ) ) = = ESP_OK ) {
AddLog ( LOG_LEVEL_DEBUG_MORE , PSTR ( " TWA: Bus%d Message queued for transmission " ) , bus + 1 ) ;
} else {
AddLog ( LOG_LEVEL_DEBUG , PSTR ( " TWA: Bus%d Alert - Failed to queue message for transmission " ) , bus + 1 ) ;
}
ResponseCmndDone ( ) ;
2024-12-28 16:46:15 +00:00
}
}
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool Xdrv91 ( uint32_t function ) {
bool result = false ;
if ( FUNC_INIT = = function ) {
TWAIInit ( ) ;
}
else if ( Twai . supported ) {
switch ( function ) {
case FUNC_LOOP :
2025-01-01 13:14:23 +00:00
for ( uint32_t bus = 0 ; bus < MAX_TWAI ; bus + + ) {
if ( Twai . installed [ bus ] ) {
TWAIRead ( bus ) ;
}
2024-12-28 16:46:15 +00:00
}
break ;
2025-01-01 13:14:23 +00:00
case FUNC_COMMAND :
result = DecodeCommand ( kTwaiCommands , TwaiCommand ) ;
break ;
2024-12-28 16:46:15 +00:00
}
}
return result ;
}
2025-01-01 13:14:23 +00:00
# endif // SOC_TWAI_SUPPORTED
2024-12-28 16:46:15 +00:00
# endif // USE_ESP32_TWAI
# endif // ESP32