2023-11-24 05:43:28 +00:00
# include "cmd_can.h"
2023-11-26 05:34:12 +00:00
# include "freertos/portmacro.h"
2023-11-25 08:01:19 +00:00
# include "inttypes.h"
2023-11-24 05:43:28 +00:00
# include "driver/twai.h"
2023-11-24 09:02:17 +00:00
# include "freertos/projdefs.h"
2023-11-24 05:43:28 +00:00
# include "hal/twai_types.h"
2023-11-24 09:02:17 +00:00
# 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"
# include "can.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-24 13:22:22 +00:00
char printf_str [ 50 ] ;
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-24 09:02:17 +00:00
twai_transmit ( & msg , pdMS_TO_TICKS ( 1000 ) ) ;
2023-11-24 12:46:30 +00:00
can_msg_to_str ( & msg , printf_str ) ;
printf ( " sent %s \n " , printf_str ) ;
2023-11-24 15:11:06 +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 ) {
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 ;
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-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-25 07:25:12 +00:00
ESP_ERROR_CHECK ( twai_stop ( ) ) ;
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 ) {
canup_args . speed = arg_str1 ( NULL , NULL , " <25|50|100|125|250|500|800|1000> " , " CAN bus speed, in kbits. " ) ;
canup_args . mode = arg_str0 ( " m " , " mode " , " <normal|no_ack|listen_only " , " Set CAN mode. Normal, No Ack (for self-testing) or Listen Only (to prevent transmitting, for monitoring). " ) ;
canup_args . filters = arg_str0 ( " f " , " filters " , " <filters> " , " CAN filters to receive only selected frames. " ) ;
canup_args . autorecover = arg_str0 ( " r " , " auto-recover " , " <1|0> " , " Set 1 to enable auto-recovery of CAN bus if case of bus-off event. " ) ;
canup_args . end = arg_end ( 2 ) ;
const esp_console_cmd_t cmd = {
. command = " canup " ,
. help = " Install can drivers and start can interface. Used right after board start or during runtime for changing CAN configuration. " ,
. 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 " ,
. help = " Start CAN interface, used after buf recovery, otherwise see canup command. " ,
. 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 ) ) ;
}