2023-11-24 05:43:28 +00:00
# include "cmd_can.h"
2023-11-28 11:40:41 +00:00
# include "can.h"
2023-11-28 12:02:00 +00:00
# include "esp_err.h"
2023-11-28 05:21:04 +00:00
# include "esp_log.h"
2023-11-25 08:01:19 +00:00
# include "inttypes.h"
2023-11-24 09:02:17 +00:00
# include "freertos/projdefs.h"
# include "string.h"
# include "esp_console.h"
2023-11-24 10:13:14 +00:00
# include "argtable3/argtable3.h"
2023-11-24 09:02:17 +00:00
# include "xvprintf.h"
2023-11-24 15:11:06 +00:00
# include <stddef.h>
# include <stdio.h>
# include <ctype.h>
2023-11-24 13:22:22 +00:00
2023-11-25 07:25:12 +00:00
static void register_send_can_frame ( void ) ;
static void register_canup ( void ) ;
static void register_candown ( void ) ;
static void register_canstats ( void ) ;
static void register_canstart ( void ) ;
static void register_canrecover ( void ) ;
2023-11-24 05:43:28 +00:00
void register_can_commands ( void ) {
2023-11-24 09:02:17 +00:00
register_send_can_frame ( ) ;
2023-11-26 05:34:12 +00:00
register_canup ( ) ;
register_candown ( ) ;
register_canstats ( ) ;
register_canstart ( ) ;
register_canrecover ( ) ;
2023-11-24 05:43:28 +00:00
}
2023-11-24 09:02:17 +00:00
2023-11-24 10:13:14 +00:00
static struct {
struct arg_str * message ;
struct arg_end * end ;
} cansend_args ;
2023-11-25 07:25:12 +00:00
static struct {
struct arg_str * speed ;
struct arg_str * filters ;
struct arg_str * autorecover ;
struct arg_str * mode ;
struct arg_end * end ;
} canup_args ;
2023-11-24 09:02:17 +00:00
static int send_can_frame ( int argc , char * * argv ) {
2023-11-24 15:11:06 +00:00
twai_message_t msg = { . extd = 1 } ;
2023-11-28 10:37:17 +00:00
char printf_str [ 70 ] ;
2023-11-24 10:13:14 +00:00
int nerrors = arg_parse ( argc , argv , ( void * * ) & cansend_args ) ;
if ( nerrors ! = 0 ) {
arg_print_errors ( stderr , cansend_args . end , argv [ 0 ] ) ;
return 1 ;
}
2023-11-24 13:22:22 +00:00
const char * can_msg_ptr = cansend_args . message - > sval [ 0 ] ;
2023-11-24 15:11:06 +00:00
char * can_msg_str_buf = strdup ( can_msg_ptr ) ;
char * id_substr = strtok ( can_msg_str_buf , " # " ) ;
char * data_substr = strtok ( NULL , " # " ) ;
if ( ( id_substr = = NULL ) | | ( strtok ( NULL , " # " ) ! = NULL ) ) goto invalid_args ;
int id_l = strlen ( id_substr ) ;
int dt_l = data_substr = = NULL ? 0 : strlen ( data_substr ) ;
if ( ( id_l > 8 ) | | ( dt_l > 16 ) | | ( id_l % 2 ) | | ( dt_l % 2 ) ) goto invalid_args ;
for ( int i = 0 ; i < id_l ; i + + ) if ( ! isxdigit ( ( int ) id_substr [ i ] ) ) goto invalid_args ;
for ( int i = 0 ; i < dt_l ; i + + ) if ( ! isxdigit ( ( int ) data_substr [ i ] ) ) goto invalid_args ;
int msg_id ;
if ( sscanf ( id_substr , " %X " , & msg_id ) < 1 ) goto invalid_args ;
for ( int i = 0 ; i < ( dt_l / 2 ) ; i + + ) {
char * byte_to_parse = malloc ( 3 ) ;
strncpy ( byte_to_parse , data_substr + i * 2 , 2 ) ;
int num ;
int res = sscanf ( byte_to_parse , " %X " , & num ) ;
free ( byte_to_parse ) ;
if ( res < 1 ) goto invalid_args ;
msg . data [ i ] = num ;
}
msg . data_length_code = dt_l / 2 ;
msg . identifier = msg_id ;
2023-11-28 11:45:51 +00:00
esp_err_t res = twai_transmit ( & msg , pdMS_TO_TICKS ( 1000 ) ) ;
switch ( res ) {
case ESP_OK :
can_msg_to_str ( & msg , " sent " , printf_str ) ;
print_w_clr_time ( printf_str , NULL , true ) ;
break ;
case ESP_ERR_TIMEOUT :
print_w_clr_time ( " Timeout! " , LOG_COLOR_RED , false ) ;
break ;
case ESP_ERR_NOT_SUPPORTED :
print_w_clr_time ( " Can't sent in Listen-Only mode! " , LOG_COLOR_RED , false ) ;
break ;
default :
print_w_clr_time ( " Invalid state! " , LOG_COLOR_RED , false ) ;
break ;
}
2023-11-28 10:37:17 +00:00
free ( can_msg_str_buf ) ;
2023-11-24 09:02:17 +00:00
return 0 ;
2023-11-24 15:11:06 +00:00
invalid_args :
2023-11-28 04:04:56 +00:00
printf ( " Invalid arguments! \n " ) ;
2023-11-24 15:11:06 +00:00
free ( can_msg_str_buf ) ;
return 1 ;
2023-11-24 09:02:17 +00:00
}
2023-11-25 07:25:12 +00:00
static int canrecover ( int argc , char * * argv ) {
2023-11-28 11:40:41 +00:00
esp_err_t res = twai_initiate_recovery ( ) ;
if ( res = = ESP_OK ) print_w_clr_time ( " Started CAN recovery. " , LOG_COLOR_GREEN , false ) ;
else if ( curr_can_state . state = = CAN_NOT_INSTALLED ) print_w_clr_time ( " CAN driver is not installed! " , LOG_COLOR_RED , false ) ;
else print_w_clr_time ( " Can't start recovery - not in bus-off state! " , LOG_COLOR_RED , false ) ;
2023-11-25 07:25:12 +00:00
return 0 ;
}
static const char * can_states_str [ ] = {
" not installed " ,
" stopped " ,
" error active " ,
" error passive " ,
" bus off " ,
" recovering "
} ;
static int canstats ( int argc , char * * argv ) {
2023-11-26 10:55:32 +00:00
if ( curr_can_state . state = = CAN_NOT_INSTALLED ) {
2023-11-28 04:04:56 +00:00
printf ( " CAN driver is not installed! \n " ) ;
2023-11-25 07:25:12 +00:00
return 0 ;
} else {
2023-11-26 10:55:32 +00:00
const char * state_str = can_states_str [ curr_can_state . state ] ;
2023-11-25 07:25:12 +00:00
printf ( " status: %s \n " , state_str ) ;
2023-11-26 10:55:32 +00:00
printf ( " TX Err Counter: % " PRIu32 " \n " , curr_can_state . tx_error_counter ) ;
printf ( " RX Err Counter: % " PRIu32 " \n " , curr_can_state . rx_error_counter ) ;
printf ( " Failed transmit: % " PRIu32 " \n " , curr_can_state . tx_failed_count ) ;
printf ( " Arbitration lost times: % " PRIu32 " \n " , curr_can_state . arb_lost_count ) ;
printf ( " Bus-off count: % " PRIu32 " \n " , curr_can_state . bus_error_count ) ;
2023-11-25 07:25:12 +00:00
}
return 0 ;
}
static int canup ( int argc , char * * argv ) {
2023-11-26 05:34:12 +00:00
esp_err_t res ;
2023-11-28 05:21:04 +00:00
esp_log_level_t prev_gpio_lvl = esp_log_level_get ( " gpio " ) ;
esp_log_level_set ( " gpio " , ESP_LOG_ERROR ) ;
2023-11-26 05:34:12 +00:00
xSemaphoreTake ( can_mutex , portMAX_DELAY ) ;
2023-11-25 07:25:12 +00:00
// Install CAN driver
// TODO: add CAN filtering
static twai_filter_config_t f_config = { . acceptance_code = 0 , . acceptance_mask = 0xFFFFFFFF , . single_filter = true } ;
2023-11-26 05:34:12 +00:00
res = twai_driver_install ( & g_config , & t_config , & f_config ) ;
2023-11-25 07:25:12 +00:00
if ( res ! = ESP_OK ) {
printf ( " Couldn't install CAN driver! Rebooting... \n " ) ;
esp_restart ( ) ;
}
printf ( " CAN driver installed \n " ) ;
// Start CAN driver
2023-11-26 05:34:12 +00:00
res = twai_start ( ) ;
2023-11-25 07:25:12 +00:00
printf ( " CAN driver started \n " ) ;
2023-11-26 05:34:12 +00:00
xSemaphoreGive ( can_mutex ) ;
2023-11-28 05:21:04 +00:00
esp_log_level_set ( " gpio " , prev_gpio_lvl ) ;
2023-11-25 07:25:12 +00:00
return 0 ;
}
static int canstart ( int argc , char * * argv ) {
// Start CAN driver
2023-11-26 05:34:12 +00:00
xSemaphoreTake ( can_mutex , portMAX_DELAY ) ;
2023-11-25 07:25:12 +00:00
ESP_ERROR_CHECK ( twai_start ( ) ) ;
printf ( " CAN driver started \n " ) ;
2023-11-26 05:34:12 +00:00
xSemaphoreGive ( can_mutex ) ;
2023-11-25 07:25:12 +00:00
return 0 ;
}
static int candown ( int argc , char * * argv ) {
2023-11-26 05:34:12 +00:00
xSemaphoreTake ( can_mutex , portMAX_DELAY ) ;
2023-11-28 12:02:00 +00:00
if ( curr_can_state . state ! = CAN_BUF_OFF ) {
esp_err_t res = twai_stop ( ) ;
if ( res = = ESP_OK ) print_w_clr_time ( " CAN was stopped. " , LOG_COLOR_GREEN , false ) ;
else {
print_w_clr_time ( " Driver is not in running state, or is not installed. " , LOG_COLOR_RED , false ) ;
xSemaphoreGive ( can_mutex ) ;
return 1 ;
}
}
2023-11-25 07:25:12 +00:00
ESP_ERROR_CHECK ( twai_driver_uninstall ( ) ) ;
2023-11-26 05:34:12 +00:00
xSemaphoreGive ( can_mutex ) ;
2023-11-25 07:25:12 +00:00
return 0 ;
}
2023-11-24 09:02:17 +00:00
static void register_send_can_frame ( void ) {
2023-11-24 10:13:14 +00:00
cansend_args . message = arg_str1 ( NULL , NULL , " ID#data " , " Message to send, ID and data bytes, all in hex. # is the delimiter. " ) ;
cansend_args . end = arg_end ( 2 ) ;
2023-11-24 09:02:17 +00:00
const esp_console_cmd_t cmd = {
. command = " cansend " ,
2023-11-24 10:13:14 +00:00
. help = " Send a can message to the bus, example: cansend 00008C03#02 " ,
2023-11-24 09:02:17 +00:00
. hint = NULL ,
. func = & send_can_frame ,
2023-11-24 10:13:14 +00:00
. argtable = & cansend_args ,
2023-11-24 09:02:17 +00:00
} ;
ESP_ERROR_CHECK ( esp_console_cmd_register ( & cmd ) ) ;
}
2023-11-25 07:25:12 +00:00
static void register_canup ( void ) {
2023-11-28 12:02:00 +00:00
canup_args . speed = arg_str1 ( NULL , NULL , " <speed> " , " CAN bus speed, in bps. See helo for supported speeds. " ) ;
canup_args . mode = arg_str0 ( " m " , " mode " , " <normal|no_ack|listen_only " , " Set CAN mode. Normal (default), No Ack (for self-testing) or Listen Only (to prevent transmitting, for monitoring). " ) ;
2023-11-25 07:25:12 +00:00
canup_args . filters = arg_str0 ( " f " , " filters " , " <filters> " , " CAN filters to receive only selected frames. " ) ;
2023-11-28 12:02:00 +00:00
canup_args . autorecover = arg_str0 ( " r " , " auto-recovery " , " <1|0> " , " Set 1 to enable auto-recovery of CAN bus if case of bus-off event, disabled by default. " ) ;
2023-11-25 07:25:12 +00:00
canup_args . end = arg_end ( 2 ) ;
const esp_console_cmd_t cmd = {
. command = " canup " ,
2023-11-28 12:02:00 +00:00
. help = " Install can drivers and start can interface. Used right after board start or during runtime for changing CAN configuration. Supported speeds: 1mbits, 800kbits, 500kbits, 250kbits, 125kbits, 100kbits, 50kbits, 25kbits, 20kbits, 16kbits, 12.5kbits, 10kbits, 5kbits, 1kbits. " ,
2023-11-25 07:25:12 +00:00
. hint = NULL ,
. func = & canup ,
. argtable = & canup_args ,
} ;
ESP_ERROR_CHECK ( esp_console_cmd_register ( & cmd ) ) ;
}
static void register_candown ( void ) {
const esp_console_cmd_t cmd = {
. command = " candown " ,
. help = " Stop CAN interface and uninstall CAN driver, for example, to install and start with different parameters/filters. " ,
. hint = NULL ,
. func = & candown ,
} ;
ESP_ERROR_CHECK ( esp_console_cmd_register ( & cmd ) ) ;
}
static void register_canstats ( void ) {
const esp_console_cmd_t cmd = {
. command = " canstats " ,
. help = " Print CAN statistics. " ,
. hint = NULL ,
. func = & canstats ,
} ;
ESP_ERROR_CHECK ( esp_console_cmd_register ( & cmd ) ) ;
}
static void register_canstart ( void ) {
const esp_console_cmd_t cmd = {
. command = " canstart " ,
2023-11-28 12:02:00 +00:00
. help = " Start CAN interface, used after bus recovery, otherwise see canup command. " ,
2023-11-25 07:25:12 +00:00
. hint = NULL ,
. func = & canstart ,
} ;
ESP_ERROR_CHECK ( esp_console_cmd_register ( & cmd ) ) ;
}
static void register_canrecover ( void ) {
const esp_console_cmd_t cmd = {
. command = " canrecover " ,
. help = " Recover CAN after buf-off. Used when auto-recovery is turned off. " ,
. hint = NULL ,
. func = & canrecover ,
} ;
ESP_ERROR_CHECK ( esp_console_cmd_register ( & cmd ) ) ;
}