#include "Nmea2kTwai.h" #include "driver/gpio.h" #include "driver/twai.h" #include "GwLog.h" #define LOGID(id) ((id >> 8) & 0x1ffff) Nmea2kTwai::Nmea2kTwai(gpio_num_t _TxPin, gpio_num_t _RxPin): tNMEA2000(),RxPin(_RxPin),TxPin(_TxPin) { } bool Nmea2kTwai::CANSendFrame(unsigned long id, unsigned char len, const unsigned char *buf, bool wait_sent) { twai_message_t message; memset(&message,0,sizeof(message)); message.identifier = id; message.extd = 1; message.data_length_code = len; memcpy(message.data,buf,len); esp_err_t rt=twai_transmit(&message,0); if (rt != ESP_OK){ logDebug(LOG_DEBUG,"twai transmit for %ld failed: %x",LOGID(id),(int)rt); return false; } logDebug(LOG_MSG,"twai transmit id %ld, len %d",LOGID(id),(int)len); return true; } bool Nmea2kTwai::CANOpen() { esp_err_t rt=twai_start(); if (rt != ESP_OK){ logDebug(LOG_ERR,"CANOpen failed: %x",(int)rt); return false; } else{ logDebug(LOG_INFO,"CANOpen ok"); } return true; } bool Nmea2kTwai::CANGetFrame(unsigned long &id, unsigned char &len, unsigned char *buf) { twai_message_t message; esp_err_t rt=twai_receive(&message,0); if (rt != ESP_OK){ return false; } if (! message.extd){ return false; } id=message.identifier; len=message.data_length_code; if (len > 8){ logDebug(LOG_DEBUG,"twai: received invalid message %lld, len %d",LOGID(id),len); len=8; } logDebug(LOG_MSG,"twai rcv id=%ld,len=%d, ext=%d",LOGID(message.identifier),message.data_length_code,message.extd); if (! message.rtr){ memcpy(buf,message.data,message.data_length_code); } return true; } void Nmea2kTwai::initDriver(){ twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(TxPin,RxPin, TWAI_MODE_NORMAL); g_config.tx_queue_len=20; twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS(); twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); esp_err_t rt=twai_driver_install(&g_config, &t_config, &f_config); if (rt == ESP_OK) { logDebug(LOG_INFO,"twai driver initialzed, rx=%d,tx=%d",(int)RxPin,(int)TxPin); } else{ logDebug(LOG_ERR,"twai driver init failed: %x",(int)rt); } } // This will be called on Open() before any other initialization. Inherit this, if buffers can be set for the driver // and you want to change size of library send frame buffer size. See e.g. NMEA2000_teensy.cpp. void Nmea2kTwai::InitCANFrameBuffers() { initDriver(); tNMEA2000::InitCANFrameBuffers(); } Nmea2kTwai::Status Nmea2kTwai::getStatus(){ twai_status_info_t state; Status rt; if (twai_get_status_info(&state) != ESP_OK){ return rt; } switch(state.state){ case TWAI_STATE_STOPPED: rt.state=ST_STOPPED; break; case TWAI_STATE_RUNNING: rt.state=ST_RUNNING; break; case TWAI_STATE_BUS_OFF: rt.state=ST_BUS_OFF; break; case TWAI_STATE_RECOVERING: rt.state=ST_RECOVERING; break; } rt.rx_errors=state.rx_error_counter; rt.tx_errors=state.tx_error_counter; rt.tx_failed=state.tx_failed_count; rt.rx_missed=state.rx_missed_count; rt.rx_overrun=state.rx_overrun_count; return rt; } bool Nmea2kTwai::startRecovery(){ esp_err_t rt=twai_driver_uninstall(); if (rt != ESP_OK){ logDebug(LOG_ERR,"twai: deinit for recovery failed with %x",(int)rt); } initDriver(); bool frt=CANOpen(); return frt; } const char * Nmea2kTwai::stateStr(const Nmea2kTwai::STATE &st){ switch (st) { case ST_BUS_OFF: return "BUS_OFF"; case ST_RECOVERING: return "RECOVERING"; case ST_RUNNING: return "RUNNING"; case ST_STOPPED: return "STOPPED"; } return "ERROR"; }