improve status handling for twai, add n2k state to UI
This commit is contained in:
parent
ec95007d9d
commit
9fd25ab6a8
|
@ -37,9 +37,12 @@ void GwLog::logString(const char *fmt,...){
|
||||||
xSemaphoreGive(locker);
|
xSemaphoreGive(locker);
|
||||||
}
|
}
|
||||||
void GwLog::logDebug(int level,const char *fmt,...){
|
void GwLog::logDebug(int level,const char *fmt,...){
|
||||||
if (level > logLevel) return;
|
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args,fmt);
|
va_start(args,fmt);
|
||||||
|
logDebug(level,fmt,args);
|
||||||
|
}
|
||||||
|
void GwLog::logDebug(int level,const char *fmt,va_list args){
|
||||||
|
if (level > logLevel) return;
|
||||||
xSemaphoreTake(locker, portMAX_DELAY);
|
xSemaphoreTake(locker, portMAX_DELAY);
|
||||||
recordCounter++;
|
recordCounter++;
|
||||||
vsnprintf(buffer,bufferSize-1,fmt,args);
|
vsnprintf(buffer,bufferSize-1,fmt,args);
|
||||||
|
|
|
@ -27,6 +27,7 @@ class GwLog{
|
||||||
void setWriter(GwLogWriter *writer);
|
void setWriter(GwLogWriter *writer);
|
||||||
void logString(const char *fmt,...);
|
void logString(const char *fmt,...);
|
||||||
void logDebug(int level, const char *fmt,...);
|
void logDebug(int level, const char *fmt,...);
|
||||||
|
void logDebug(int level, const char *fmt,va_list ap);
|
||||||
int isActive(int level){return level <= logLevel;};
|
int isActive(int level){return level <= logLevel;};
|
||||||
void flush();
|
void flush();
|
||||||
void setLevel(int level){this->logLevel=level;}
|
void setLevel(int level){this->logLevel=level;}
|
||||||
|
|
|
@ -3,22 +3,10 @@
|
||||||
#include "driver/twai.h"
|
#include "driver/twai.h"
|
||||||
#include "GwLog.h"
|
#include "GwLog.h"
|
||||||
|
|
||||||
#define TWAI_DEBUG 0
|
#define LOGID(id) ((id >> 8) & 0x1ffff)
|
||||||
#if TWAI_DEBUG == 1
|
|
||||||
#define TWAI_LOG(...) LOG_DEBUG(__VA_ARGS__)
|
|
||||||
#define TWAI_LDEBUG(...)
|
|
||||||
#else
|
|
||||||
#if TWAI_DEBUG == 2
|
|
||||||
#define TWAI_LOG(...) LOG_DEBUG(__VA_ARGS__)
|
|
||||||
#define TWA_LDEBUG(...) LOG_DEBUG(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define TWAI_LOG(...)
|
|
||||||
#define TWAI_LDEBUG(...)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Nmea2kTwai::Nmea2kTwai(gpio_num_t _TxPin, gpio_num_t _RxPin,GwLog *l):
|
Nmea2kTwai::Nmea2kTwai(gpio_num_t _TxPin, gpio_num_t _RxPin):
|
||||||
tNMEA2000(),RxPin(_RxPin),TxPin(_TxPin),logger(l)
|
tNMEA2000(),RxPin(_RxPin),TxPin(_TxPin)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,21 +20,21 @@ bool Nmea2kTwai::CANSendFrame(unsigned long id, unsigned char len, const unsigne
|
||||||
memcpy(message.data,buf,len);
|
memcpy(message.data,buf,len);
|
||||||
esp_err_t rt=twai_transmit(&message,0);
|
esp_err_t rt=twai_transmit(&message,0);
|
||||||
if (rt != ESP_OK){
|
if (rt != ESP_OK){
|
||||||
TWAI_LOG(GwLog::DEBUG,"twai transmit for %ld failed: %x",(id & 0x1ffff),(int)rt);
|
logDebug(LOG_DEBUG,"twai transmit for %ld failed: %x",LOGID(id),(int)rt);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TWAI_LDEBUG(GwLog::DEBUG,"twai transmit id %ld, len %d",(id & 0x1ffff),(int)len);
|
logDebug(LOG_MSG,"twai transmit id %ld, len %d",LOGID(id),(int)len);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool Nmea2kTwai::CANOpen()
|
bool Nmea2kTwai::CANOpen()
|
||||||
{
|
{
|
||||||
esp_err_t rt=twai_start();
|
esp_err_t rt=twai_start();
|
||||||
if (rt != ESP_OK){
|
if (rt != ESP_OK){
|
||||||
LOG_DEBUG(GwLog::ERROR,"CANOpen failed: %x",(int)rt);
|
logDebug(LOG_ERR,"CANOpen failed: %x",(int)rt);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
LOG_DEBUG(GwLog::LOG,"CANOpen ok");
|
logDebug(LOG_INFO,"CANOpen ok");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -63,10 +51,10 @@ bool Nmea2kTwai::CANGetFrame(unsigned long &id, unsigned char &len, unsigned cha
|
||||||
id=message.identifier;
|
id=message.identifier;
|
||||||
len=message.data_length_code;
|
len=message.data_length_code;
|
||||||
if (len > 8){
|
if (len > 8){
|
||||||
TWAI_LOG(GwLog::ERROR,"twai: received invalid message %lld, len %d",id,len);
|
logDebug(LOG_DEBUG,"twai: received invalid message %lld, len %d",LOGID(id),len);
|
||||||
len=8;
|
len=8;
|
||||||
}
|
}
|
||||||
TWAI_LDEBUG(GwLog::DEBUG,"twai rcv id=%ld,len=%d, ext=%d",message.identifier,message.data_length_code,message.extd);
|
logDebug(LOG_MSG,"twai rcv id=%ld,len=%d, ext=%d",LOGID(message.identifier),message.data_length_code,message.extd);
|
||||||
if (! message.rtr){
|
if (! message.rtr){
|
||||||
memcpy(buf,message.data,message.data_length_code);
|
memcpy(buf,message.data,message.data_length_code);
|
||||||
}
|
}
|
||||||
|
@ -79,10 +67,10 @@ void Nmea2kTwai::initDriver(){
|
||||||
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||||
esp_err_t rt=twai_driver_install(&g_config, &t_config, &f_config);
|
esp_err_t rt=twai_driver_install(&g_config, &t_config, &f_config);
|
||||||
if (rt == ESP_OK) {
|
if (rt == ESP_OK) {
|
||||||
LOG_DEBUG(GwLog::LOG,"twai driver initialzed, rx=%d,tx=%d",(int)RxPin,(int)TxPin);
|
logDebug(LOG_INFO,"twai driver initialzed, rx=%d,tx=%d",(int)RxPin,(int)TxPin);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
LOG_DEBUG(GwLog::ERROR,"twai driver init failed: %x",(int)rt);
|
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
|
// This will be called on Open() before any other initialization. Inherit this, if buffers can be set for the driver
|
||||||
|
@ -93,38 +81,38 @@ void Nmea2kTwai::InitCANFrameBuffers()
|
||||||
tNMEA2000::InitCANFrameBuffers();
|
tNMEA2000::InitCANFrameBuffers();
|
||||||
|
|
||||||
}
|
}
|
||||||
Nmea2kTwai::STATE Nmea2kTwai::getState(){
|
Nmea2kTwai::Status Nmea2kTwai::getStatus(){
|
||||||
twai_status_info_t state;
|
twai_status_info_t state;
|
||||||
|
Status rt;
|
||||||
if (twai_get_status_info(&state) != ESP_OK){
|
if (twai_get_status_info(&state) != ESP_OK){
|
||||||
return ST_ERROR;
|
return rt;
|
||||||
}
|
}
|
||||||
switch(state.state){
|
switch(state.state){
|
||||||
case TWAI_STATE_STOPPED:
|
case TWAI_STATE_STOPPED:
|
||||||
return ST_STOPPED;
|
rt.state=ST_STOPPED;
|
||||||
|
break;
|
||||||
case TWAI_STATE_RUNNING:
|
case TWAI_STATE_RUNNING:
|
||||||
return ST_RUNNING;
|
rt.state=ST_RUNNING;
|
||||||
|
break;
|
||||||
case TWAI_STATE_BUS_OFF:
|
case TWAI_STATE_BUS_OFF:
|
||||||
return ST_BUS_OFF;
|
rt.state=ST_BUS_OFF;
|
||||||
|
break;
|
||||||
case TWAI_STATE_RECOVERING:
|
case TWAI_STATE_RECOVERING:
|
||||||
return ST_RECOVERING;
|
rt.state=ST_RECOVERING;
|
||||||
}
|
break;
|
||||||
return ST_ERROR;
|
|
||||||
}
|
|
||||||
Nmea2kTwai::ERRORS Nmea2kTwai::getErrors(){
|
|
||||||
ERRORS rt;
|
|
||||||
twai_status_info_t state;
|
|
||||||
if (twai_get_status_info(&state) != ESP_OK){
|
|
||||||
return rt;
|
|
||||||
}
|
}
|
||||||
rt.rx_errors=state.rx_error_counter;
|
rt.rx_errors=state.rx_error_counter;
|
||||||
rt.tx_errors=state.tx_error_counter;
|
rt.tx_errors=state.tx_error_counter;
|
||||||
rt.tx_failed=state.tx_failed_count;
|
rt.tx_failed=state.tx_failed_count;
|
||||||
|
rt.rx_missed=state.rx_missed_count;
|
||||||
|
rt.rx_overrun=state.rx_overrun_count;
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Nmea2kTwai::startRecovery(){
|
bool Nmea2kTwai::startRecovery(){
|
||||||
esp_err_t rt=twai_driver_uninstall();
|
esp_err_t rt=twai_driver_uninstall();
|
||||||
if (rt != ESP_OK){
|
if (rt != ESP_OK){
|
||||||
LOG_DEBUG(GwLog::ERROR,"twai: deinit for recovery failed with %x",(int)rt);
|
logDebug(LOG_ERR,"twai: deinit for recovery failed with %x",(int)rt);
|
||||||
}
|
}
|
||||||
initDriver();
|
initDriver();
|
||||||
bool frt=CANOpen();
|
bool frt=CANOpen();
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
class Nmea2kTwai : public tNMEA2000{
|
class Nmea2kTwai : public tNMEA2000{
|
||||||
public:
|
public:
|
||||||
Nmea2kTwai(gpio_num_t _TxPin, gpio_num_t _RxPin,GwLog *logger);
|
Nmea2kTwai(gpio_num_t _TxPin, gpio_num_t _RxPin);
|
||||||
typedef enum{
|
typedef enum{
|
||||||
ST_STOPPED,
|
ST_STOPPED,
|
||||||
ST_RUNNING,
|
ST_RUNNING,
|
||||||
|
@ -14,15 +14,23 @@ class Nmea2kTwai : public tNMEA2000{
|
||||||
ST_ERROR
|
ST_ERROR
|
||||||
} STATE;
|
} STATE;
|
||||||
typedef struct{
|
typedef struct{
|
||||||
|
//see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/twai.html#_CPPv418twai_status_info_t
|
||||||
uint32_t rx_errors=0;
|
uint32_t rx_errors=0;
|
||||||
uint32_t tx_errors=0;
|
uint32_t tx_errors=0;
|
||||||
uint32_t tx_failed=0;
|
uint32_t tx_failed=0;
|
||||||
} ERRORS;
|
uint32_t rx_missed=0;
|
||||||
STATE getState();
|
uint32_t rx_overrun=0;
|
||||||
ERRORS getErrors();
|
STATE state=ST_ERROR;
|
||||||
|
} Status;
|
||||||
|
Status getStatus();
|
||||||
bool startRecovery();
|
bool startRecovery();
|
||||||
static const char * stateStr(const STATE &st);
|
static const char * stateStr(const STATE &st);
|
||||||
virtual bool CANOpen();
|
virtual bool CANOpen();
|
||||||
|
virtual ~Nmea2kTwai(){};
|
||||||
|
static const int LOG_ERR=0;
|
||||||
|
static const int LOG_INFO=1;
|
||||||
|
static const int LOG_DEBUG=2;
|
||||||
|
static const int LOG_MSG=3;
|
||||||
protected:
|
protected:
|
||||||
// Virtual functions for different interfaces. Currently there are own classes
|
// Virtual functions for different interfaces. Currently there are own classes
|
||||||
// for Arduino due internal CAN (NMEA2000_due), external MCP2515 SPI CAN bus controller (NMEA2000_mcp),
|
// for Arduino due internal CAN (NMEA2000_due), external MCP2515 SPI CAN bus controller (NMEA2000_mcp),
|
||||||
|
@ -32,14 +40,13 @@ class Nmea2kTwai : public tNMEA2000{
|
||||||
// This will be called on Open() before any other initialization. Inherit this, if buffers can be set for the driver
|
// 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.
|
// and you want to change size of library send frame buffer size. See e.g. NMEA2000_teensy.cpp.
|
||||||
virtual void InitCANFrameBuffers();
|
virtual void InitCANFrameBuffers();
|
||||||
|
virtual void logDebug(int level,const char *fmt,...){}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initDriver();
|
void initDriver();
|
||||||
gpio_num_t TxPin;
|
gpio_num_t TxPin;
|
||||||
gpio_num_t RxPin;
|
gpio_num_t RxPin;
|
||||||
GwLog *logger;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
38
src/main.cpp
38
src/main.cpp
|
@ -110,7 +110,22 @@ GwLog logger(LOGLEVEL,NULL);
|
||||||
GwConfigHandler config(&logger);
|
GwConfigHandler config(&logger);
|
||||||
|
|
||||||
#include "Nmea2kTwai.h"
|
#include "Nmea2kTwai.h"
|
||||||
Nmea2kTwai &NMEA2000=*(new Nmea2kTwai(ESP32_CAN_TX_PIN,ESP32_CAN_RX_PIN,&logger));
|
class Nmea2kTwaiLog : public Nmea2kTwai{
|
||||||
|
private:
|
||||||
|
GwLog* logger;
|
||||||
|
public:
|
||||||
|
Nmea2kTwaiLog(gpio_num_t _TxPin, gpio_num_t _RxPin, GwLog *l):
|
||||||
|
Nmea2kTwai(_TxPin,_RxPin),logger(l){}
|
||||||
|
virtual void logDebug(int level, const char *fmt,...){
|
||||||
|
va_list args;
|
||||||
|
va_start(args,fmt);
|
||||||
|
if (level > 2) level++; //error+info+debug are similar, map msg to 4
|
||||||
|
logger->logDebug(level,fmt,args);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Nmea2kTwai &NMEA2000=*(new Nmea2kTwaiLog(ESP32_CAN_TX_PIN,ESP32_CAN_RX_PIN,&logger));
|
||||||
|
|
||||||
#ifdef GWBUTTON_PIN
|
#ifdef GWBUTTON_PIN
|
||||||
bool fixedApPass=false;
|
bool fixedApPass=false;
|
||||||
|
@ -354,7 +369,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
virtual void processRequest()
|
virtual void processRequest()
|
||||||
{
|
{
|
||||||
GwJsonDocument status(256 +
|
GwJsonDocument status(290 +
|
||||||
countNMEA2KIn.getJsonSize()+
|
countNMEA2KIn.getJsonSize()+
|
||||||
countNMEA2KOut.getJsonSize() +
|
countNMEA2KOut.getJsonSize() +
|
||||||
channels.getJsonSize()
|
channels.getJsonSize()
|
||||||
|
@ -370,6 +385,8 @@ protected:
|
||||||
status["salt"] = buffer;
|
status["salt"] = buffer;
|
||||||
status["fwtype"]= firmwareType;
|
status["fwtype"]= firmwareType;
|
||||||
status["heap"]=(long)xPortGetFreeHeapSize();
|
status["heap"]=(long)xPortGetFreeHeapSize();
|
||||||
|
Nmea2kTwai::Status n2kState=NMEA2000.getStatus();
|
||||||
|
status["n2kstate"]=NMEA2000.stateStr(n2kState.state);
|
||||||
//nmea0183Converter->toJson(status);
|
//nmea0183Converter->toJson(status);
|
||||||
countNMEA2KIn.toJson(status);
|
countNMEA2KIn.toJson(status);
|
||||||
countNMEA2KOut.toJson(status);
|
countNMEA2KOut.toJson(status);
|
||||||
|
@ -843,15 +860,20 @@ void loop() {
|
||||||
}
|
}
|
||||||
if (now > (lastCanRecovery + CAN_RECOVERY_PERIOD)){
|
if (now > (lastCanRecovery + CAN_RECOVERY_PERIOD)){
|
||||||
lastCanRecovery=now;
|
lastCanRecovery=now;
|
||||||
Nmea2kTwai::STATE canState=NMEA2000.getState();
|
Nmea2kTwai::Status canState=NMEA2000.getStatus();
|
||||||
Nmea2kTwai::ERRORS canErrors=NMEA2000.getErrors();
|
logger.logDebug(GwLog::DEBUG,"can state %s, rxerr %d, txerr %d, txfail %d, rxmiss %d, rxoverrun %d",
|
||||||
logger.logDebug(GwLog::DEBUG,"can state %s, rxerr %d, txerr %d, txfail %d",NMEA2000.stateStr(canState),canErrors.rx_errors,canErrors.tx_errors,canErrors.tx_failed);
|
NMEA2000.stateStr(canState.state),
|
||||||
if (canState != Nmea2kTwai::ST_RUNNING){
|
canState.rx_errors,
|
||||||
if (canState == Nmea2kTwai::ST_BUS_OFF){
|
canState.tx_errors,
|
||||||
|
canState.tx_failed,
|
||||||
|
canState.rx_missed,
|
||||||
|
canState.rx_overrun);
|
||||||
|
if (canState.state != Nmea2kTwai::ST_RUNNING){
|
||||||
|
if (canState.state == Nmea2kTwai::ST_BUS_OFF){
|
||||||
bool rt=NMEA2000.startRecovery();
|
bool rt=NMEA2000.startRecovery();
|
||||||
logger.logDebug(GwLog::LOG,"start can recovery - result %d",(int)rt);
|
logger.logDebug(GwLog::LOG,"start can recovery - result %d",(int)rt);
|
||||||
}
|
}
|
||||||
if (canState == Nmea2kTwai::ST_STOPPED){
|
if (canState.state == Nmea2kTwai::ST_STOPPED){
|
||||||
bool rt=NMEA2000.CANOpen();
|
bool rt=NMEA2000.CANOpen();
|
||||||
logger.logDebug(GwLog::LOG,"restart can driver - result %d",(int)rt);
|
logger.logDebug(GwLog::LOG,"restart can driver - result %d",(int)rt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,11 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="label">Free heap</span>
|
<span class="label">Free heap</span>
|
||||||
<span class="value" id="heap">---</span>
|
<span class="value" id="heap">---</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">N2K State</span>
|
||||||
|
<span class="value" id="n2kstate">UNKNOWN</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button id="reset">Reset</button>
|
<button id="reset">Reset</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue