434 lines
14 KiB
C
434 lines
14 KiB
C
|
/*
|
||
|
; Project: Open Vehicle Monitor System
|
||
|
; Date: 14th March 2017
|
||
|
;
|
||
|
; Changes:
|
||
|
; 1.0 Initial release
|
||
|
;
|
||
|
; (C) 2011 Michael Stegen / Stegen Electronics
|
||
|
; (C) 2011-2017 Mark Webb-Johnson
|
||
|
; (C) 2011 Sonny Chen @ EPRO/DX
|
||
|
;
|
||
|
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
; of this software and associated documentation files (the "Software"), to deal
|
||
|
; in the Software without restriction, including without limitation the rights
|
||
|
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
; copies of the Software, and to permit persons to whom the Software is
|
||
|
; furnished to do so, subject to the following conditions:
|
||
|
;
|
||
|
; The above copyright notice and this permission notice shall be included in
|
||
|
; all copies or substantial portions of the Software.
|
||
|
;
|
||
|
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
; THE SOFTWARE.
|
||
|
;
|
||
|
; Portions of this are based on the work of Thomas Barth, and licensed
|
||
|
; under MIT license.
|
||
|
; Copyright (c) 2017, Thomas Barth, barth-dev.de
|
||
|
; https://github.com/ThomasBarth/ESP32-CAN-Driver
|
||
|
*/
|
||
|
|
||
|
#ifndef __CAN_H__
|
||
|
#define __CAN_H__
|
||
|
|
||
|
#include "freertos/FreeRTOS.h"
|
||
|
#include "freertos/task.h"
|
||
|
#include "freertos/queue.h"
|
||
|
#include <stdint.h>
|
||
|
#include <functional>
|
||
|
#include <list>
|
||
|
#include "pcp.h"
|
||
|
#include <esp_err.h>
|
||
|
#include "ovms_events.h"
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// Constant ESP_QUEUED to indicate a 'queued' response
|
||
|
// (rather than ESP_OK or ESP_FAIL, for example)
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#ifndef ESP_QUEUED
|
||
|
#define ESP_QUEUED 1 // frame has been queued for later processing
|
||
|
#endif
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// CAN BUS constants and objects
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#define CAN_MAXBUSES 5 // Limit of number of CAN buses supported
|
||
|
|
||
|
class canbus; // Forward definition
|
||
|
|
||
|
// CAN mode
|
||
|
typedef enum
|
||
|
{
|
||
|
CAN_MODE_OFF=0,
|
||
|
CAN_MODE_LISTEN=1,
|
||
|
CAN_MODE_ACTIVE=2
|
||
|
} CAN_mode_t;
|
||
|
|
||
|
// CAN link speed (33.3kbps -> 1MHz)
|
||
|
typedef enum
|
||
|
{
|
||
|
CAN_SPEED_33KBPS=33, // CAN Node runs at 33.333kBit/s
|
||
|
CAN_SPEED_50KBPS=50, // CAN Node runs at 50kBit/s
|
||
|
CAN_SPEED_83KBPS=83, // CAN Node runs at 83.333kBit/s
|
||
|
CAN_SPEED_100KBPS=100, // CAN Node runs at 100kBit/s
|
||
|
CAN_SPEED_125KBPS=125, // CAN Node runs at 125kBit/s
|
||
|
CAN_SPEED_250KBPS=250, // CAN Node runs at 250kBit/s
|
||
|
CAN_SPEED_500KBPS=500, // CAN Node runs at 500kBit/s
|
||
|
CAN_SPEED_1000KBPS=1000 // CAN Node runs at 1000kBit/s
|
||
|
} CAN_speed_t;
|
||
|
|
||
|
/* Map CAN_speed_t to a Bit/s value */
|
||
|
#define MAP_CAN_SPEED(s) \
|
||
|
(((s) == CAN_SPEED_33KBPS || (s) == CAN_SPEED_83KBPS) ? ((((int)(s)) * 1000) + 333) : (((int)(s)) * 1000))
|
||
|
|
||
|
// CAN frame type (standard/extended)
|
||
|
typedef enum
|
||
|
{
|
||
|
CAN_frame_std=0, // Standard frame, using 11 bit identifer
|
||
|
CAN_frame_ext=1 // Extended frame, using 29 bit identifer
|
||
|
} CAN_frame_format_t;
|
||
|
|
||
|
// CAN RTR
|
||
|
typedef enum
|
||
|
{
|
||
|
CAN_no_RTR=0, // No RTR frame
|
||
|
CAN_RTR=1 // RTR frame
|
||
|
} CAN_RTR_t;
|
||
|
|
||
|
// CAN Frame Information Record
|
||
|
typedef union
|
||
|
{
|
||
|
uint32_t U; // Unsigned access
|
||
|
struct
|
||
|
{
|
||
|
uint8_t DLC:4; // [3:0] DLC, Data length container
|
||
|
unsigned int unknown_2:2; // internal unknown
|
||
|
CAN_RTR_t RTR:1; // [6:6] RTR, Remote Transmission Request
|
||
|
CAN_frame_format_t FF:1; // [7:7] Frame Format, see# CAN_frame_format_t
|
||
|
unsigned int reserved_24:24; // internal Reserved
|
||
|
} B;
|
||
|
} CAN_FIR_t;
|
||
|
|
||
|
|
||
|
typedef struct CAN_frame_t CAN_frame_t;
|
||
|
typedef std::function<void(const CAN_frame_t*, bool)> CanFrameCallback;
|
||
|
|
||
|
// CAN Frame
|
||
|
// Note: Take care changing this structure, as it is a union with
|
||
|
// CAN_log_message_t and position of 'origin' is fixed.
|
||
|
struct CAN_frame_t
|
||
|
{
|
||
|
canbus* origin; // Origin of the frame
|
||
|
CanFrameCallback * callback; // Frame-specific callback. Is called when this frame is successfully sent (or sending failed)
|
||
|
CAN_FIR_t FIR; // Frame information record
|
||
|
uint32_t MsgID; // Message ID
|
||
|
union
|
||
|
{
|
||
|
uint8_t u8[8]; // Payload byte access
|
||
|
uint32_t u32[2]; // Payload u32 access (Att: little endian!)
|
||
|
uint64_t u64; // Payload u64 access (Att: little endian!)
|
||
|
} data;
|
||
|
|
||
|
esp_err_t Write(canbus* bus=NULL, TickType_t maxqueuewait=0); // bus: NULL=origin
|
||
|
};
|
||
|
|
||
|
// CAN status
|
||
|
typedef struct
|
||
|
{
|
||
|
uint32_t interrupts; // interrupts
|
||
|
uint32_t packets_rx; // frames reveiced
|
||
|
uint32_t packets_tx; // frames sent successfully
|
||
|
uint32_t txbuf_delay; // frames routed through TX queue
|
||
|
uint16_t rxbuf_overflow; // frames lost due to RX buffers full
|
||
|
uint16_t txbuf_overflow; // TX queue overflows
|
||
|
uint32_t tx_fails; // TX failures/aborts
|
||
|
uint32_t error_flags; // driver specific bitset
|
||
|
uint16_t errors_rx; // RX error counter
|
||
|
uint16_t errors_tx; // TX error counter
|
||
|
uint16_t invalid_rx; // RX invalid frame counter
|
||
|
uint16_t watchdog_resets; // Watchdog reset counter
|
||
|
uint16_t error_resets; // Error resolving reset counter
|
||
|
} CAN_status_t;
|
||
|
|
||
|
// CAN error states
|
||
|
typedef enum
|
||
|
{
|
||
|
CAN_errorstate_none = 0, // normal operation, no errors present
|
||
|
CAN_errorstate_active, // normal operation, some errors present (< 96 rx/tx errors)
|
||
|
CAN_errorstate_warning, // normal operation, many errors present (>= 96 rx/tx errors)
|
||
|
CAN_errorstate_passive, // passive mode, no tx retries until bus recovery (>= 128 rx/tx errors)
|
||
|
CAN_errorstate_busoff // bus-off mode, no tx/rx until bus recovery (> 255 rx/tx errors)
|
||
|
} CAN_errorstate_t;
|
||
|
|
||
|
extern const char* GetCanErrorStateName(CAN_errorstate_t error_state);
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// CAN messages queue
|
||
|
// This queue is between the CAN bus controller MyCAN and tasks that
|
||
|
// inject/receive CAN bus messages (such as MCP2515 and esp32can)
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// CAN message type
|
||
|
typedef enum
|
||
|
{
|
||
|
CAN_frame = 0,
|
||
|
CAN_asyncinterrupthandler, // used for asynchronous handling of rx and other interrupts from MCP2515
|
||
|
CAN_txcallback,
|
||
|
CAN_txfailedcallback,
|
||
|
CAN_logerror,
|
||
|
CAN_logstatus
|
||
|
} CAN_queue_type_t;
|
||
|
|
||
|
// CAN message
|
||
|
typedef struct
|
||
|
{
|
||
|
CAN_queue_type_t type;
|
||
|
union
|
||
|
{
|
||
|
CAN_frame_t frame; // CAN_frame
|
||
|
canbus* bus;
|
||
|
} body;
|
||
|
} CAN_queue_msg_t;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// CAN Filtering (software based filter)
|
||
|
// The canfilter object encapsulates the filtering of CAN frames
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
uint8_t bus;
|
||
|
uint32_t id_from;
|
||
|
uint32_t id_to;
|
||
|
} CAN_filter_t;
|
||
|
|
||
|
typedef std::list<CAN_filter_t*> CAN_filter_list_t;
|
||
|
|
||
|
class canfilter
|
||
|
{
|
||
|
public:
|
||
|
canfilter();
|
||
|
virtual ~canfilter();
|
||
|
|
||
|
public:
|
||
|
void ClearFilters();
|
||
|
void AddFilter(uint8_t bus=0, uint32_t id_from=0, uint32_t id_to=UINT32_MAX);
|
||
|
void AddFilter(const char* filterstring);
|
||
|
bool RemoveFilter(uint8_t bus=0, uint32_t id_from=0, uint32_t id_to=UINT32_MAX);
|
||
|
|
||
|
public:
|
||
|
bool IsFiltered(const CAN_frame_t* p_frame);
|
||
|
bool IsFiltered(canbus* bus);
|
||
|
std::string Info();
|
||
|
|
||
|
protected:
|
||
|
CAN_filter_list_t m_filters;
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// CAN logging and tracing
|
||
|
// These structures are involved in formatting, logging and tracing of
|
||
|
// CAN messages (both frames and status/control messages)
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// Log entry types:
|
||
|
typedef enum
|
||
|
{
|
||
|
CAN_LogNone = 0, // init placeholder
|
||
|
CAN_LogFrame_RX, // frame received
|
||
|
CAN_LogFrame_TX, // frame transmitted
|
||
|
CAN_LogFrame_TX_Queue, // frame delayed
|
||
|
CAN_LogFrame_TX_Fail, // frame transmission failure
|
||
|
CAN_LogStatus_Error, // canbus error status
|
||
|
CAN_LogStatus_Statistics, // canbus packet statistics
|
||
|
CAN_LogInfo_Comment, // general comment
|
||
|
CAN_LogInfo_Config, // logger setup info (type, file, filters, vehicle)
|
||
|
CAN_LogInfo_Event, // system event (i.e. vehicle started)
|
||
|
} CAN_log_type_t;
|
||
|
|
||
|
// Log message:
|
||
|
typedef struct
|
||
|
{
|
||
|
CAN_log_type_t type;
|
||
|
struct timeval timestamp;
|
||
|
union
|
||
|
{
|
||
|
CAN_frame_t frame;
|
||
|
struct
|
||
|
{
|
||
|
canbus* origin;
|
||
|
union
|
||
|
{
|
||
|
CAN_status_t status;
|
||
|
char* text;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
} CAN_log_message_t;
|
||
|
|
||
|
extern const char* GetCanLogTypeName(CAN_log_type_t type);
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// canbus - the definition of a CAN bus
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
class canlog;
|
||
|
class canplay;
|
||
|
class dbcfile;
|
||
|
|
||
|
class canbus : public pcp, public InternalRamAllocated
|
||
|
{
|
||
|
public:
|
||
|
canbus(const char* name);
|
||
|
virtual ~canbus();
|
||
|
|
||
|
public:
|
||
|
virtual esp_err_t Start(CAN_mode_t mode, CAN_speed_t speed);
|
||
|
virtual esp_err_t Start(CAN_mode_t mode, CAN_speed_t speed, dbcfile *dbcfile);
|
||
|
virtual esp_err_t Stop();
|
||
|
virtual void ClearStatus();
|
||
|
virtual esp_err_t ViewRegisters();
|
||
|
virtual esp_err_t WriteReg( uint8_t reg, uint8_t value );
|
||
|
|
||
|
public:
|
||
|
void AttachDBC(dbcfile *dbcfile);
|
||
|
bool AttachDBC(const char *name);
|
||
|
void DetachDBC();
|
||
|
dbcfile* GetDBC();
|
||
|
|
||
|
public:
|
||
|
virtual esp_err_t Write(const CAN_frame_t* p_frame, TickType_t maxqueuewait=0);
|
||
|
virtual esp_err_t WriteExtended(uint32_t id, uint8_t length, uint8_t *data, TickType_t maxqueuewait=0);
|
||
|
virtual esp_err_t WriteStandard(uint16_t id, uint8_t length, uint8_t *data, TickType_t maxqueuewait=0);
|
||
|
virtual bool AsynchronousInterruptHandler(CAN_frame_t* frame, uint32_t* framesReceived);
|
||
|
virtual void TxCallback(CAN_frame_t* frame, bool success);
|
||
|
|
||
|
protected:
|
||
|
virtual esp_err_t QueueWrite(const CAN_frame_t* p_frame, TickType_t maxqueuewait=0);
|
||
|
void BusTicker10(std::string event, void* data);
|
||
|
|
||
|
public:
|
||
|
void LogFrame(CAN_log_type_t type, const CAN_frame_t* p_frame);
|
||
|
void LogStatus(CAN_log_type_t type);
|
||
|
void LogInfo(CAN_log_type_t type, const char* text);
|
||
|
bool StatusChanged();
|
||
|
CAN_errorstate_t GetErrorState();
|
||
|
const char* GetErrorStateName();
|
||
|
|
||
|
public:
|
||
|
CAN_speed_t m_speed;
|
||
|
CAN_mode_t m_mode;
|
||
|
CAN_status_t m_status;
|
||
|
CAN_frame_t m_tx_frame; // saved copy of last TX frame to be used in txcallback
|
||
|
uint32_t m_status_chksum;
|
||
|
uint32_t m_watchdog_timer;
|
||
|
uint32_t m_state; // state bitset
|
||
|
QueueHandle_t m_txqueue;
|
||
|
int m_busnumber;
|
||
|
|
||
|
protected:
|
||
|
dbcfile *m_dbcfile;
|
||
|
};
|
||
|
|
||
|
#define CAN_M_STATE_TX_BUF_OCCUPIED BIT(0) // transmit buffer is in use
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// can - the CAN system controller
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
typedef std::map<QueueHandle_t, bool> CanListenerMap_t;
|
||
|
|
||
|
|
||
|
class CanFrameCallbackEntry
|
||
|
{
|
||
|
public:
|
||
|
CanFrameCallbackEntry(const char* caller, CanFrameCallback callback)
|
||
|
{
|
||
|
m_caller = caller;
|
||
|
m_callback = callback;
|
||
|
}
|
||
|
~CanFrameCallbackEntry() {}
|
||
|
public:
|
||
|
const char *m_caller;
|
||
|
CanFrameCallback m_callback;
|
||
|
};
|
||
|
typedef std::list<CanFrameCallbackEntry*> CanFrameCallbackList_t;
|
||
|
|
||
|
class can : public InternalRamAllocated
|
||
|
{
|
||
|
public:
|
||
|
can();
|
||
|
~can();
|
||
|
|
||
|
private:
|
||
|
static void CAN_rxtask(void *pvParameters);
|
||
|
|
||
|
public:
|
||
|
void IncomingFrame(CAN_frame_t* p_frame);
|
||
|
|
||
|
public:
|
||
|
QueueHandle_t m_rxqueue;
|
||
|
|
||
|
public:
|
||
|
void RegisterListener(QueueHandle_t queue, bool txfeedback=false);
|
||
|
void DeregisterListener(QueueHandle_t queue);
|
||
|
void NotifyListeners(const CAN_frame_t* frame, bool tx);
|
||
|
|
||
|
public:
|
||
|
void RegisterCallback(const char* caller, CanFrameCallback callback, bool txfeedback=false);
|
||
|
void DeregisterCallback(const char* caller);
|
||
|
int ExecuteCallbacks(const CAN_frame_t* frame, bool tx, bool success);
|
||
|
|
||
|
public:
|
||
|
uint32_t AddLogger(canlog* logger, int filterc=0, const char* const* filterv=NULL);
|
||
|
bool HasLogger();
|
||
|
canlog* GetLogger(uint32_t id);
|
||
|
bool RemoveLogger(uint32_t id);
|
||
|
void RemoveLoggers();
|
||
|
|
||
|
public:
|
||
|
uint32_t AddPlayer(canplay* player, int filterc=0, const char* const* filterv=NULL);
|
||
|
bool HasPlayer();
|
||
|
canplay* GetPlayer(uint32_t id);
|
||
|
bool RemovePlayer(uint32_t id);
|
||
|
void RemovePlayers();
|
||
|
|
||
|
public:
|
||
|
void LogFrame(canbus* bus, CAN_log_type_t type, const CAN_frame_t* frame);
|
||
|
void LogStatus(canbus* bus, CAN_log_type_t type, const CAN_status_t* status);
|
||
|
void LogInfo(canbus* bus, CAN_log_type_t type, const char* text);
|
||
|
|
||
|
public:
|
||
|
canbus* GetBus(int busnumber);
|
||
|
|
||
|
public:
|
||
|
typedef std::map<uint32_t, canlog*> canlog_map_t;
|
||
|
canlog_map_t m_loggermap;
|
||
|
OvmsRecMutex m_loggermap_mutex;
|
||
|
uint32_t m_logger_id;
|
||
|
|
||
|
public:
|
||
|
typedef std::map<uint32_t, canplay*> canplay_map_t;
|
||
|
canplay_map_t m_playermap;
|
||
|
OvmsMutex m_playermap_mutex;
|
||
|
uint32_t m_player_id;
|
||
|
|
||
|
private:
|
||
|
canbus* m_buslist[CAN_MAXBUSES];
|
||
|
CanListenerMap_t m_listeners;
|
||
|
CanFrameCallbackList_t m_rxcallbacks;
|
||
|
CanFrameCallbackList_t m_txcallbacks;
|
||
|
TaskHandle_t m_rxtask; // Task to handle reception
|
||
|
};
|
||
|
|
||
|
extern can MyCan;
|
||
|
|
||
|
#endif //#ifndef __CAN_H__
|