802 lines
40 KiB
C++
802 lines
40 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.
|
|
*/
|
|
|
|
#ifndef __VEHICLE_H__
|
|
#define __VEHICLE_H__
|
|
|
|
#include <map>
|
|
#include <vector>
|
|
#include <string>
|
|
#include "can.h"
|
|
#include "ovms_events.h"
|
|
#include "ovms_config.h"
|
|
#include "ovms_metrics.h"
|
|
#include "ovms_command.h"
|
|
#include "metrics_standard.h"
|
|
#include "ovms_mutex.h"
|
|
#include "ovms_semaphore.h"
|
|
|
|
using namespace std;
|
|
struct DashboardConfig;
|
|
|
|
|
|
// ISO TP:
|
|
// (see https://en.wikipedia.org/wiki/ISO_15765-2)
|
|
|
|
#define ISOTP_FT_SINGLE 0
|
|
#define ISOTP_FT_FIRST 1
|
|
#define ISOTP_FT_CONSECUTIVE 2
|
|
#define ISOTP_FT_FLOWCTRL 3
|
|
|
|
// Protocol variant:
|
|
#define ISOTP_STD 0 // standard addressing (11 bit IDs)
|
|
#define ISOTP_EXTADR 1 // extended addressing (19 bit IDs)
|
|
#define ISOTP_EXTFRAME 2 // extended frame mode (29 bit IDs)
|
|
#define VWTP_16 16 // VW/VAG Transport Protocol 1.6 (placeholder, unsupported)
|
|
#define VWTP_20 20 // VW/VAG Transport Protocol 2.0
|
|
|
|
// Argument tag:
|
|
#define POLL_TXDATA 0xff // poll_pid_t using xargs for external payload up to 4095 bytes
|
|
|
|
|
|
// OBD2/UDS Polling types supported:
|
|
// (see https://en.wikipedia.org/wiki/OBD-II_PIDs
|
|
// and https://en.wikipedia.org/wiki/Unified_Diagnostic_Services)
|
|
//
|
|
// Depending on the poll type, the response may or may not echo the PID (parameter ID / subtype).
|
|
// If no echo is present, the poller will only validate the type.
|
|
//
|
|
// Depending on the poll type, you may also need to pass additional arguments. These can be set
|
|
// alternatively to the single PID in the poll_pid_t.args field, which extends the pid by a data
|
|
// length and up to 6 data bytes. A common example is reading a DTC info, the service has an
|
|
// 8 bit PID (subtype) and depending on the subtype 1-4 additional parameter bytes:
|
|
// { TXID, RXID, POLLTYPE, {.args={ PID, DATALEN, DATA1, … }}, {…TIMES…}, 0, ISOTP_STD }
|
|
//
|
|
// Since version 3.2.016-140 the poller supports multi-frame requests and adds a more versatile way
|
|
// to pass additional arguments / TX data of up to 4095 bytes using the new 'xargs' union member,
|
|
// which takes a data length and a pointer to an uint8_t array. The xargs.tag member needs to
|
|
// be set to POLL_TXDATA for this.
|
|
//
|
|
// Use the utility macro POLL_PID_DATA (see below) to create poll_pid_t entries like this:
|
|
// { TXID, RXID, POLLTYPE, POLL_PID_DATA(PID, DATASTRING), {…TIMES…}, 0, ISOTP_STD }
|
|
//
|
|
// DATASTRING is a C string for ease of use, the terminating NUL char is excluded by the macro.
|
|
// To pass hexadecimal values, simply define them by '\x..', example:
|
|
// POLL_PID_DATA(0x21D4, "\x0F\x02\0x00\xAB\xCD")
|
|
//
|
|
// The poller automatically uses a single or multi frame request as needed.
|
|
//
|
|
// See OvmsVehicle::PollSingleRequest() on how to send dynamic requests with additional arguments.
|
|
//
|
|
// VWTP_20: this protocol implements the VW (VAG) specific "TP 2.0", which establishes
|
|
// OSI layer 5 communication channels to devices (ECU modules) via a CAN gateway.
|
|
// On VWTP_20 poll entries, simply set the TXID to the gateway base ID (normally 0x200)
|
|
// and the RXID to the logical 8 bit ECU ID you want to address.
|
|
// TP 2.0 transports standard OBD/UDS requests, so everything else works the same way
|
|
// as with ISO-TP.
|
|
//
|
|
// VW TP 2.0 poll entry examples:
|
|
// // TXID, RXID, TYPE, PID, TIMES, BUS, PROT
|
|
// { 0x200, 0x1f, 0x10, 0x89, {…times…}, 0, VWTP_20 }
|
|
// { 0x200, 0x1f, 0x22, 0x04a1, {…times…}, 0 , VWTP_20 }
|
|
//
|
|
// VW gateways currently do not support multiple open channels. To minimize connection
|
|
// overhead for successive polls to an ECU, the VWTP_20 engine keeps an idle connection open
|
|
// until the keepalive timeout occurs. So you should try to arrange your polls in interval
|
|
// blocks/sequences to the same devices if possible.
|
|
//
|
|
// To explicitly close a VWTP_20 channel, send a poll (any type) to RXID 0, that just
|
|
// closes the channel (ECU ID 0 is an invalid destination):
|
|
// { 0x200, 0, 0, 0, {…times…}, 0 , VWTP_20 }
|
|
|
|
|
|
#define VEHICLE_POLL_TYPE_NONE 0x00
|
|
|
|
|
|
// OBD (ISO 15031) service identifiers supported:
|
|
#define VEHICLE_POLL_TYPE_OBDIICURRENT 0x01 // Mode 01 "current data" (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_OBDIIFREEZE 0x02 // Mode 02 "freeze frame data" (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_READ_ERDTC 0x03 // Mode 03 read emission-related DTC (no PID)
|
|
#define VEHICLE_POLL_TYPE_CLEAR_ERDTC 0x04 // Mode 04 clear/reset emission-related DTC (no PID)
|
|
#define VEHICLE_POLL_TYPE_READOXSTEST 0x05 // Mode 05 read oxygen sensor monitoring test results (16 bit PID)
|
|
#define VEHICLE_POLL_TYPE_READOBMTEST 0x06 // Mode 06 read on-board monitoring test results (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_READ_DCERDTC 0x07 // Mode 07 read driving cycle emission-related DTC (no PID)
|
|
#define VEHICLE_POLL_TYPE_REQOBUCTRL 0x08 // Mode 08 request on-board unit control (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_OBDIIVEHICLE 0x09 // Mode 09 "vehicle information" (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_READ_PERMDTC 0x0A // Mode 0A read permanent (cleared) DTC (no PID)
|
|
|
|
// UDS (ISO 14229) service identifiers supported:
|
|
#define VEHICLE_POLL_TYPE_OBDIISESSION 0x10 // UDS: Diagnostic Session Control (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_TESTERPRESENT 0x3E // UDS: TesterPresent (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_SECACCESS 0x27 // UDS: SecurityAccess (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_COMCONTROL 0x28 // UDS: CommunicationControl (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_ECURESET 0x11 // UDS: ECUReset (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_CLEARDTC 0x14 // UDS: ClearDiagnosticInformation (no PID)
|
|
#define VEHICLE_POLL_TYPE_READDTC 0x19 // UDS: ReadDTCInformation (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_OBDIIEXTENDED 0x22 // UDS: ReadDataByIdentifier (16 bit PID) (legacy alias for READDATA)
|
|
#define VEHICLE_POLL_TYPE_READDATA 0x22 // UDS: ReadDataByIdentifier (16 bit PID)
|
|
#define VEHICLE_POLL_TYPE_READMEMORY 0x23 // UDS: ReadMemoryByAddress (no PID)
|
|
#define VEHICLE_POLL_TYPE_READSCALING 0x24 // UDS: ReadScalingDataByIdentifier (16 bit PID)
|
|
#define VEHICLE_POLL_TYPE_WRITEDATA 0x2E // UDS: WriteDataByIdentifier (16 bit PID)
|
|
#define VEHICLE_POLL_TYPE_ROUTINECONTROL 0x31 // UDS: Routine Control (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_WRITEMEMORY 0x3D // UDS: WriteMemoryByAddress (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_IOCONTROL 0x2F // UDS: InputOutputControlByIdentifier (16 bit PID)
|
|
|
|
// Other service identifiers supported:
|
|
#define VEHICLE_POLL_TYPE_OBDII_18 0x18 // Custom: VW request type 18 (no PID)
|
|
#define VEHICLE_POLL_TYPE_OBDII_1A 0x1A // Custom: Mode 1A (8 bit PID)
|
|
#define VEHICLE_POLL_TYPE_OBDIIGROUP 0x21 // Custom: Read data by 8 bit PID
|
|
#define VEHICLE_POLL_TYPE_OBDII_32 0x32 // Custom: VW routine control extension (8 bit PID)
|
|
|
|
#define VEHICLE_OBD_BROADCAST_MODULE_TX 0x7df
|
|
#define VEHICLE_OBD_BROADCAST_MODULE_RX 0x0
|
|
// A note on "PID" and their sizes here:
|
|
// By "PID" for the service types we mean the part of the request parameters
|
|
// after the service type that is reflected in _every_ valid response to the request.
|
|
// That part is used to validate the response by the poller, if it doesn't match,
|
|
// the response won't be forwarded to the application.
|
|
// Some requests require additional parameters as specified in ISO 14229, but implementations
|
|
// may differ. For example, a 31b8 request on a VW ECU does not necessarily copy the routine
|
|
// ID in the response (e.g. with 0000), so the routine ID isn't part of our "PID" here.
|
|
|
|
// Utils:
|
|
#define POLL_TYPE_HAS_16BIT_PID(type) \
|
|
((type) == VEHICLE_POLL_TYPE_READDATA || \
|
|
(type) == VEHICLE_POLL_TYPE_READSCALING || \
|
|
(type) == VEHICLE_POLL_TYPE_WRITEDATA || \
|
|
(type) == VEHICLE_POLL_TYPE_IOCONTROL || \
|
|
(type) == VEHICLE_POLL_TYPE_READOXSTEST)
|
|
#define POLL_TYPE_HAS_NO_PID(type) \
|
|
((type) == VEHICLE_POLL_TYPE_CLEARDTC || \
|
|
(type) == VEHICLE_POLL_TYPE_READMEMORY || \
|
|
(type) == VEHICLE_POLL_TYPE_READ_ERDTC || \
|
|
(type) == VEHICLE_POLL_TYPE_CLEAR_ERDTC || \
|
|
(type) == VEHICLE_POLL_TYPE_READ_DCERDTC || \
|
|
(type) == VEHICLE_POLL_TYPE_READ_PERMDTC || \
|
|
(type) == VEHICLE_POLL_TYPE_OBDII_18)
|
|
#define POLL_TYPE_HAS_8BIT_PID(type) \
|
|
(!POLL_TYPE_HAS_NO_PID(type) && !POLL_TYPE_HAS_16BIT_PID(type))
|
|
|
|
// OBD/UDS Negative Response Code
|
|
#define UDS_RESP_TYPE_NRC 0x7F // see ISO 14229 Annex A.1
|
|
#define UDS_RESP_NRC_RCRRP 0x78 // … requestCorrectlyReceived-ResponsePending
|
|
|
|
// Number of polling states supported
|
|
#define VEHICLE_POLL_NSTATES 4
|
|
|
|
// Macro for poll_pid_t termination
|
|
#define POLL_LIST_END { 0, 0, 0x00, 0x00, { 0, 0, 0 }, 0, 0 }
|
|
|
|
// Poll list PID xargs utility (see info above):
|
|
#define POLL_PID_DATA(pid, datastring) \
|
|
{.xargs={ (pid), POLL_TXDATA, sizeof(datastring)-1, reinterpret_cast<const uint8_t*>(datastring) }}
|
|
|
|
// PollSingleRequest specific result codes:
|
|
#define POLLSINGLE_OK 0
|
|
#define POLLSINGLE_TIMEOUT -1
|
|
#define POLLSINGLE_TXFAILURE -2
|
|
|
|
|
|
// Standard MSG protocol commands:
|
|
|
|
#define CMD_QueryFeatures 1 // ()
|
|
#define CMD_SetFeature 2 // (feature number, value)
|
|
#define CMD_QueryParams 3 // ()
|
|
#define CMD_SetParam 4 // (param number, value)
|
|
#define CMD_Reboot 5 // ()
|
|
#define CMD_Alert 6 // ()
|
|
#define CMD_Execute 7 // (text command with arguments)
|
|
#define CMD_SetChargeMode 10 // (mode)
|
|
#define CMD_StartCharge 11 // ()
|
|
#define CMD_StopCharge 12 // ()
|
|
#define CMD_SetChargeCurrent 15 // (amps)
|
|
#define CMD_SetChargeModeAndCurrent 16 // (mode, amps)
|
|
#define CMD_SetChargeTimer 17 // (mode, start time)
|
|
#define CMD_WakeupCar 18 // ()
|
|
#define CMD_WakeupTempSystem 19 // ()
|
|
#define CMD_Lock 20 // (pin)
|
|
#define CMD_ValetOn 21 // (pin)
|
|
#define CMD_UnLock 22 // (pin)
|
|
#define CMD_ValetOff 23 // (pin)
|
|
#define CMD_Homelink 24 // (button_nr)
|
|
#define CMD_CoolDown 25 // ()
|
|
#define CMD_ClimateControl 26 // (mode)
|
|
// 30-39 reserved for server commands
|
|
#define CMD_SendSMS 40 // (phone number, SMS message)
|
|
#define CMD_SendUSSD 41 // (USSD_CODE)
|
|
#define CMD_SendRawAT 49 // (raw AT command)
|
|
// 200+ reserved for custom commands
|
|
|
|
|
|
// BMS default deviation thresholds:
|
|
#define BMS_DEFTHR_VMAXGRAD 0.010 // [V]
|
|
#define BMS_DEFTHR_VMAXSDDEV 0.010 // [V]
|
|
#define BMS_DEFTHR_VWARN 0.020 // [V]
|
|
#define BMS_DEFTHR_VALERT 0.030 // [V]
|
|
#define BMS_DEFTHR_TWARN 2.00 // [°C]
|
|
#define BMS_DEFTHR_TALERT 3.00 // [°C]
|
|
|
|
|
|
// VWTP_20 channel states:
|
|
typedef enum
|
|
{
|
|
VWTP_Closed = 0, // Channel not connecting/connected
|
|
VWTP_ChannelClose, // Close request has been sent
|
|
VWTP_ChannelSetup, // Setup request has been sent
|
|
VWTP_ChannelParams, // Params request has been sent
|
|
VWTP_Idle, // Connection established, idle
|
|
VWTP_StartPoll, // Transit state: begin request transmission
|
|
VWTP_Transmit, // Request transmission phase
|
|
VWTP_Receive, // Response reception phase
|
|
VWTP_AbortXfer, // Transit state: abort request/response
|
|
} vwtp_channelstate_t;
|
|
|
|
// VWTP_20 channel:
|
|
typedef struct
|
|
{
|
|
vwtp_channelstate_t state; // VWTP channel state
|
|
canbus* bus; // CAN bus
|
|
uint16_t baseid; // Protocol base CAN MsgID (usually 0x200)
|
|
uint8_t moduleid; // Logical address (ID) of destination module
|
|
uint16_t txid; // CAN MsgID we transmit on
|
|
uint16_t rxid; // CAN MsgID we listen to
|
|
uint8_t blocksize; // Number of blocks (data frames) to send between ACKs
|
|
uint32_t acktime; // Max time [us] to wait for ACK (not yet implemented)
|
|
uint32_t septime; // Min separation time [us] between blocks (data frames)
|
|
uint32_t txseqnr; // TX packet sequence number
|
|
uint32_t rxseqnr; // RX packet sequence number
|
|
uint32_t lastused; // Timestamp of last channel access
|
|
} vwtp_channel_t;
|
|
|
|
enum class OvmsStatus : short {
|
|
OK = 0,
|
|
Warn = 1,
|
|
Alert = 2
|
|
};
|
|
inline bool operator<(OvmsStatus lhs, OvmsStatus rhs) {
|
|
return static_cast<short>(lhs) < static_cast<short>(rhs);
|
|
}
|
|
|
|
class OvmsVehicle : public InternalRamAllocated
|
|
{
|
|
friend class OvmsVehicleFactory;
|
|
|
|
public:
|
|
OvmsVehicle();
|
|
virtual ~OvmsVehicle();
|
|
virtual const char* VehicleShortName();
|
|
virtual const char* VehicleType();
|
|
|
|
protected:
|
|
QueueHandle_t m_rxqueue;
|
|
TaskHandle_t m_rxtask;
|
|
bool m_registeredlistener;
|
|
bool m_autonotifications;
|
|
bool m_ready;
|
|
|
|
public:
|
|
canbus* m_can1;
|
|
canbus* m_can2;
|
|
canbus* m_can3;
|
|
canbus* m_can4;
|
|
|
|
private:
|
|
void VehicleTicker1(std::string event, void* data);
|
|
void VehicleConfigChanged(std::string event, void* data);
|
|
void PollerSend(bool fromTicker);
|
|
void PollerReceive(CAN_frame_t* frame, uint32_t msgid);
|
|
|
|
protected:
|
|
virtual void IncomingFrameCan1(CAN_frame_t* p_frame);
|
|
virtual void IncomingFrameCan2(CAN_frame_t* p_frame);
|
|
virtual void IncomingFrameCan3(CAN_frame_t* p_frame);
|
|
virtual void IncomingFrameCan4(CAN_frame_t* p_frame);
|
|
|
|
protected:
|
|
virtual void PollerStateTicker();
|
|
virtual void IncomingPollReply(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t mlremain);
|
|
virtual void IncomingPollError(canbus* bus, uint16_t type, uint16_t pid, uint16_t code);
|
|
|
|
protected:
|
|
int m_minsoc; // The minimum SOC level before alert
|
|
int m_minsoc_triggered; // The triggered minimum SOC level to alert at
|
|
|
|
protected:
|
|
float m_accel_refspeed; // Acceleration calculation: last speed measured (m/s)
|
|
uint32_t m_accel_reftime; // … timestamp for refspeed (ms)
|
|
float m_accel_smoothing; // … smoothing factor (samples, 0 = none, default 2.0)
|
|
void CalculateAcceleration(); // Call after ms_v_pos_speed update to derive acceleration
|
|
|
|
protected:
|
|
float m_batpwr_smoothing; // … smoothing factor (samples, 0 = none, default 2.0) …
|
|
float m_batpwr_smoothed; // … and smoothed value of ms_v_bat_power
|
|
|
|
protected:
|
|
bool m_brakelight_enable; // Regen brake light enable (default no)
|
|
int m_brakelight_port; // … MAX7317 output port number (1, 3…9, default 1 = SW_12V)
|
|
float m_brakelight_on; // … activation threshold (deceleration in m/s², default 1.3)
|
|
float m_brakelight_off; // … deactivation threshold (deceleration in m/s², default 0.7)
|
|
float m_brakelight_basepwr; // … base power area (+/- from 0 in kW, default 0)
|
|
bool m_brakelight_ignftbrk; // … ignore foot brake (default no)
|
|
uint32_t m_brakelight_start; // … activation start time
|
|
virtual void CheckBrakelight(); // … check vehicle metrics for regen braking state (override to customize)
|
|
virtual bool SetBrakelight(int on); // … hardware control method (override for non MAX7317 control)
|
|
|
|
protected:
|
|
virtual void CalculateRangeSpeed(); // Derive momentary range gain/loss speed in kph
|
|
|
|
protected:
|
|
int m_last_drivetime; // duration of current/most recent drive [s]
|
|
int m_last_parktime; // duration of current/most recent parking period [s]
|
|
int m_last_chargetime; // duration of current/most recent charge [s]
|
|
int m_last_gentime; // duration of current/most recent generator run [s]
|
|
|
|
float m_drive_startsoc; // SOC at drive start (vehicle.on)
|
|
float m_drive_startrange; // Range estimation at drive start (vehicle.on)
|
|
float m_drive_startaltitude; // Altitude at drive start (vehicle.on)
|
|
uint32_t m_drive_speedcnt; // Driving speed average data
|
|
double m_drive_speedsum; // Driving speed average data
|
|
uint32_t m_drive_accelcnt; // Driving acceleration average data
|
|
double m_drive_accelsum; // Driving acceleration average data
|
|
uint32_t m_drive_decelcnt; // Driving deceleration average data
|
|
double m_drive_decelsum; // Driving deceleration average data
|
|
double m_inv_energyused; // Driving motor energy sum
|
|
double m_inv_energyrecd; // Driving recupered energy sum
|
|
uint32_t m_inv_reftime; // last time inverter(motor) power was measured
|
|
float m_inv_refpower; // last inverter(motor) power
|
|
|
|
protected:
|
|
uint32_t m_ticker;
|
|
int m_12v_ticker;
|
|
int m_chargestate_ticker;
|
|
int m_vehicleon_ticker;
|
|
int m_vehicleoff_ticker;
|
|
int m_idle_ticker;
|
|
virtual void Ticker1(uint32_t ticker);
|
|
virtual void Ticker10(uint32_t ticker);
|
|
virtual void Ticker60(uint32_t ticker);
|
|
virtual void Ticker300(uint32_t ticker);
|
|
virtual void Ticker600(uint32_t ticker);
|
|
virtual void Ticker3600(uint32_t ticker);
|
|
|
|
protected:
|
|
virtual void NotifyChargeState();
|
|
virtual void NotifyChargeStart();
|
|
virtual void NotifyChargeTopOff();
|
|
virtual void NotifyHeatingStart();
|
|
virtual void NotifyChargeStopped();
|
|
virtual void NotifyChargeDone();
|
|
virtual void NotifyValetEnabled();
|
|
virtual void NotifyValetDisabled();
|
|
virtual void NotifyValetHood();
|
|
virtual void NotifyValetTrunk();
|
|
virtual void NotifyAlarmSounding();
|
|
virtual void NotifyAlarmStopped();
|
|
virtual void Notify12vCritical();
|
|
virtual void Notify12vRecovered();
|
|
virtual void NotifyMinSocCritical();
|
|
virtual void NotifyVehicleIdling();
|
|
virtual void NotifyVehicleOn();
|
|
virtual void NotifyVehicleOff();
|
|
|
|
protected:
|
|
virtual void NotifyGenState();
|
|
|
|
protected:
|
|
virtual void NotifyGridLog();
|
|
virtual void NotifyTripLog();
|
|
virtual void NotifyTripReport();
|
|
|
|
protected:
|
|
virtual int GetNotifyVehicleStateDelay(const std::string& state) { return 3; }
|
|
virtual int GetNotifyChargeStateDelay(const char* state) { return 3; }
|
|
|
|
protected:
|
|
virtual void NotifiedVehicleOn() {}
|
|
virtual void NotifiedVehicleOff() {}
|
|
virtual void NotifiedVehicleAwake() {}
|
|
virtual void NotifiedVehicleAsleep() {}
|
|
virtual void NotifiedVehicleChargeStart() {}
|
|
virtual void NotifiedVehicleChargeStop() {}
|
|
virtual void NotifiedVehicleChargePrepare() {}
|
|
virtual void NotifiedVehicleChargeFinish() {}
|
|
virtual void NotifiedVehicleChargePilotOn() {}
|
|
virtual void NotifiedVehicleChargePilotOff() {}
|
|
virtual void NotifiedVehicleChargeTimermodeOn() {}
|
|
virtual void NotifiedVehicleChargeTimermodeOff() {}
|
|
virtual void NotifiedVehicleAux12vOn() {}
|
|
virtual void NotifiedVehicleAux12vOff() {}
|
|
virtual void NotifiedVehicleCharge12vStart() {}
|
|
virtual void NotifiedVehicleCharge12vStop() {}
|
|
virtual void NotifiedVehicleLocked() {}
|
|
virtual void NotifiedVehicleUnlocked() {}
|
|
virtual void NotifiedVehicleValetOn() {}
|
|
virtual void NotifiedVehicleValetOff() {}
|
|
virtual void NotifiedVehicleHeadlightsOn() {}
|
|
virtual void NotifiedVehicleHeadlightsOff() {}
|
|
virtual void NotifiedVehicleAlarmOn() {}
|
|
virtual void NotifiedVehicleAlarmOff() {}
|
|
virtual void NotifiedVehicleGear(int gear) {}
|
|
virtual void NotifiedVehicleDrivemode(int drivemode) {}
|
|
virtual void NotifiedVehicleChargeMode(const char* m) {}
|
|
virtual void NotifiedVehicleChargeState(const char* s) {}
|
|
virtual void NotifiedVehicleGenState(const std::string& state) {}
|
|
|
|
protected:
|
|
virtual void ConfigChanged(OvmsConfigParam* param);
|
|
virtual void MetricModified(OvmsMetric* metric);
|
|
virtual void CalculateEfficiency();
|
|
|
|
public:
|
|
#ifdef CONFIG_OVMS_COMP_WEBSERVER
|
|
virtual void GetDashboardConfig(DashboardConfig& cfg);
|
|
#endif // #ifdef CONFIG_OVMS_COMP_WEBSERVER
|
|
virtual void Status(int verbosity, OvmsWriter* writer);
|
|
|
|
protected:
|
|
void RegisterCanBus(int bus, CAN_mode_t mode, CAN_speed_t speed, dbcfile* dbcfile = NULL);
|
|
bool PinCheck(char* pin);
|
|
|
|
public:
|
|
virtual void RxTask();
|
|
|
|
public:
|
|
typedef enum
|
|
{
|
|
NotImplemented = 0,
|
|
Success,
|
|
Fail
|
|
} vehicle_command_t;
|
|
typedef enum
|
|
{
|
|
Standard = 0,
|
|
Storage = 1,
|
|
Range = 3,
|
|
Performance = 4
|
|
} vehicle_mode_t;
|
|
enum class vehicle_bms_status_t
|
|
{
|
|
Both,
|
|
Voltage,
|
|
Temperature
|
|
};
|
|
|
|
public:
|
|
vehicle_mode_t VehicleModeKey(const std::string code);
|
|
|
|
public:
|
|
virtual vehicle_command_t CommandSetChargeMode(vehicle_mode_t mode);
|
|
virtual vehicle_command_t CommandSetChargeCurrent(uint16_t limit);
|
|
virtual vehicle_command_t CommandStartCharge();
|
|
virtual vehicle_command_t CommandStopCharge();
|
|
virtual vehicle_command_t CommandSetChargeTimer(bool timeron, uint16_t timerstart);
|
|
virtual vehicle_command_t CommandCooldown(bool cooldownon);
|
|
virtual vehicle_command_t CommandWakeup();
|
|
virtual vehicle_command_t CommandClimateControl(bool enable);
|
|
virtual vehicle_command_t CommandLock(const char* pin);
|
|
virtual vehicle_command_t CommandUnlock(const char* pin);
|
|
virtual vehicle_command_t CommandActivateValet(const char* pin);
|
|
virtual vehicle_command_t CommandDeactivateValet(const char* pin);
|
|
virtual vehicle_command_t CommandHomelink(int button, int durationms=1000);
|
|
|
|
#ifdef CONFIG_OVMS_COMP_TPMS
|
|
public:
|
|
virtual bool TPMSRead(std::vector<uint32_t> *tpms);
|
|
virtual bool TPMSWrite(std::vector<uint32_t> &tpms);
|
|
#endif // #ifdef CONFIG_OVMS_COMP_TPMS
|
|
|
|
public:
|
|
virtual std::vector<std::string> GetTpmsLayout();
|
|
|
|
protected:
|
|
uint32_t m_tpms_lastcheck; // monotonictime of last TPMS alert check
|
|
std::vector<short> m_tpms_laststate; // last TPMS alert state for change detection
|
|
|
|
protected:
|
|
virtual void NotifyTpmsAlerts();
|
|
|
|
public:
|
|
virtual vehicle_command_t CommandStat(int verbosity, OvmsWriter* writer);
|
|
virtual vehicle_command_t CommandStatTrip(int verbosity, OvmsWriter* writer);
|
|
virtual vehicle_command_t ProcessMsgCommand(std::string &result, int command, const char* args);
|
|
|
|
public:
|
|
virtual bool SetFeature(int key, const char* value);
|
|
virtual const std::string GetFeature(int key);
|
|
|
|
public:
|
|
typedef struct
|
|
{
|
|
uint32_t txmoduleid; // transmission CAN ID (address), 0x7df = OBD2 broadcast
|
|
uint32_t rxmoduleid; // expected response CAN ID or 0 for broadcasts
|
|
uint16_t type; // UDS poll type / OBD2 "mode", see VEHICLE_POLL_TYPE_…
|
|
union
|
|
{
|
|
uint16_t pid; // PID (shortcut for requests w/o payload)
|
|
struct
|
|
{
|
|
uint16_t pid; // PID for requests with additional payload
|
|
uint8_t datalen; // payload length (bytes)
|
|
uint8_t data[6]; // inline payload data (single frame request)
|
|
} args;
|
|
struct
|
|
{
|
|
uint16_t pid; // PID for requests with additional payload
|
|
uint8_t tag; // needs to be POLL_TXDATA
|
|
uint16_t datalen; // payload length (bytes, max 4095)
|
|
const uint8_t* data; // pointer to payload data (single/multi frame request)
|
|
} xargs;
|
|
};
|
|
uint16_t polltime[VEHICLE_POLL_NSTATES]; // poll intervals in seconds for used poll states
|
|
uint8_t pollbus; // 0 = default CAN bus from PollSetPidList(), 1…4 = specific
|
|
uint8_t protocol; // ISOTP_STD / ISOTP_EXTADR / ISOTP_EXTFRAME / VWTP_20
|
|
} poll_pid_t;
|
|
|
|
protected:
|
|
OvmsRecMutex m_poll_mutex; // Concurrency protection for recursive calls
|
|
uint8_t m_poll_state; // Current poll state
|
|
canbus* m_poll_bus; // Bus to poll on
|
|
canbus* m_poll_bus_default; // Bus default to poll on
|
|
const poll_pid_t* m_poll_plist; // Head of poll list
|
|
const poll_pid_t* m_poll_plcur; // Poll list loop cursor
|
|
poll_pid_t m_poll_entry; // Currently processed entry of poll list (copy)
|
|
uint32_t m_poll_ticker; // Polling ticker
|
|
uint8_t m_poll_protocol; // ISOTP_STD / ISOTP_EXTADR / ISOTP_EXTFRAME / VWTP_20
|
|
uint32_t m_poll_moduleid_sent; // ModuleID last sent
|
|
uint32_t m_poll_moduleid_low; // Expected response moduleid low mark
|
|
uint32_t m_poll_moduleid_high; // Expected response moduleid high mark
|
|
uint16_t m_poll_type; // Expected type
|
|
uint16_t m_poll_pid; // Expected PID
|
|
const uint8_t* m_poll_tx_data; // Payload data for multi frame request
|
|
uint16_t m_poll_tx_remain; // Payload bytes remaining for multi frame request
|
|
uint16_t m_poll_tx_offset; // Payload offset of multi frame request
|
|
uint16_t m_poll_tx_frame; // Frame number for multi frame request
|
|
uint16_t m_poll_ml_remain; // Bytes remaining for multi frame response
|
|
uint16_t m_poll_ml_offset; // Offset of multi frame response
|
|
uint16_t m_poll_ml_frame; // Frame number for multi frame response
|
|
uint8_t m_poll_wait; // Wait counter for a reply from a sent poll or bytes remaining.
|
|
// Gets set = 2 when a poll is sent OR when bytes are remaining after receiving.
|
|
// Gets set = 0 when a poll is received.
|
|
// Gets decremented with every second/tick in PollerSend().
|
|
// PollerSend() aborts when > 0.
|
|
// Why set = 2: When a poll gets send just before the next ticker occurs
|
|
// PollerSend() decrements to 1 and doesn't send the next poll.
|
|
// Only when the reply doesn't get in until the next ticker occurs
|
|
// PollserSend() decrements to 0 and abandons the outstanding reply (=timeout)
|
|
|
|
private:
|
|
uint8_t m_poll_sequence_max; // Polls allowed to be sent in sequence per time tick (second), default 1, 0 = no limit
|
|
uint8_t m_poll_sequence_cnt; // Polls already sent in the current time tick (second)
|
|
uint8_t m_poll_fc_septime; // Flow control separation time for multi frame responses
|
|
uint16_t m_poll_ch_keepalive; // Seconds to keep an inactive channel (e.g. VWTP) alive (default: 60)
|
|
|
|
private:
|
|
OvmsRecMutex m_poll_single_mutex; // PollSingleRequest() concurrency protection
|
|
std::string* m_poll_single_rxbuf; // … response buffer
|
|
int m_poll_single_rxerr; // … response error code (NRC) / TX failure code
|
|
OvmsSemaphore m_poll_single_rxdone; // … response done (ok/error)
|
|
|
|
protected:
|
|
vwtp_channel_t m_poll_vwtp; // VWTP channel state
|
|
|
|
protected:
|
|
void PollSetPidList(canbus* bus, const poll_pid_t* plist);
|
|
void PollSetState(uint8_t state);
|
|
void PollSetThrottling(uint8_t sequence_max);
|
|
void PollSetResponseSeparationTime(uint8_t septime);
|
|
void PollSetChannelKeepalive(uint16_t keepalive_seconds);
|
|
int PollSingleRequest(canbus* bus, uint32_t txid, uint32_t rxid,
|
|
std::string request, std::string& response,
|
|
int timeout_ms=3000, uint8_t protocol=ISOTP_STD);
|
|
int PollSingleRequest(canbus* bus, uint32_t txid, uint32_t rxid,
|
|
uint8_t polltype, uint16_t pid, std::string& response,
|
|
int timeout_ms=3000, uint8_t protocol=ISOTP_STD);
|
|
const char* PollResultCodeName(int code);
|
|
|
|
private:
|
|
void PollerISOTPStart(bool fromTicker);
|
|
bool PollerISOTPReceive(CAN_frame_t* frame, uint32_t msgid);
|
|
|
|
private:
|
|
void PollerVWTPStart(bool fromTicker);
|
|
bool PollerVWTPReceive(CAN_frame_t* frame, uint32_t msgid);
|
|
void PollerVWTPEnter(vwtp_channelstate_t state);
|
|
void PollerVWTPTicker();
|
|
void PollerVWTPTxCallback(const CAN_frame_t* frame, bool success);
|
|
|
|
private:
|
|
CanFrameCallback m_poll_txcallback; // Poller CAN TxCallback
|
|
uint32_t m_poll_txmsgid; // Poller last TX CAN ID (frame MsgID)
|
|
|
|
private:
|
|
void PollerTxCallback(const CAN_frame_t* frame, bool success);
|
|
protected:
|
|
virtual void IncomingPollTxCallback(canbus* bus, uint32_t txid, uint16_t type, uint16_t pid, bool success);
|
|
|
|
|
|
// BMS helpers
|
|
protected:
|
|
float* m_bms_voltages; // BMS voltages (current value)
|
|
float* m_bms_vmins; // BMS minimum voltages seen (since reset)
|
|
float* m_bms_vmaxs; // BMS maximum voltages seen (since reset)
|
|
float* m_bms_vdevmaxs; // BMS maximum voltage deviations seen (since reset)
|
|
OvmsStatus* m_bms_valerts; // BMS voltage deviation alerts (since reset)
|
|
int m_bms_valerts_new; // BMS new voltage alerts since last notification
|
|
int m_bms_vstddev_cnt; // BMS internal stddev counter
|
|
float m_bms_vstddev_avg; // BMS internal stddev average
|
|
bool m_bms_has_voltages; // True if BMS has a complete set of voltage values
|
|
float* m_bms_temperatures; // BMS temperatures (celcius current value)
|
|
float* m_bms_tmins; // BMS minimum temperatures seen (since reset)
|
|
float* m_bms_tmaxs; // BMS maximum temperatures seen (since reset)
|
|
float* m_bms_tdevmaxs; // BMS maximum temperature deviations seen (since reset)
|
|
OvmsStatus* m_bms_talerts; // BMS temperature deviation alerts (since reset)
|
|
int m_bms_talerts_new; // BMS new temperature alerts since last notification
|
|
bool m_bms_has_temperatures; // True if BMS has a complete set of temperature values
|
|
std::vector<bool> m_bms_bitset_v; // BMS tracking: true if corresponding voltage set
|
|
std::vector<bool> m_bms_bitset_t; // BMS tracking: true if corresponding temperature set
|
|
int m_bms_bitset_cv; // BMS tracking: count of unique voltage values set
|
|
int m_bms_bitset_ct; // BMS tracking: count of unique temperature values set
|
|
int m_bms_readings_v; // Number of BMS voltage readings expected
|
|
int m_bms_readingspermodule_v; // Number of BMS voltage readings per module
|
|
int m_bms_readings_t; // Number of BMS temperature readings expected
|
|
int m_bms_readingspermodule_t; // Number of BMS temperature readings per module
|
|
float m_bms_limit_tmin; // Minimum temperature limit (for sanity checking)
|
|
float m_bms_limit_tmax; // Maximum temperature limit (for sanity checking)
|
|
float m_bms_limit_vmin; // Minimum voltage limit (for sanity checking)
|
|
float m_bms_limit_vmax; // Maximum voltage limit (for sanity checking)
|
|
float m_bms_defthr_vmaxgrad; // Default voltage deviation max valid gradient [V]
|
|
float m_bms_defthr_vmaxsddev; // Default voltage deviation max valid stddev deviation [V]
|
|
float m_bms_defthr_vwarn; // Default voltage deviation warn threshold [V]
|
|
float m_bms_defthr_valert; // Default voltage deviation alert threshold [V]
|
|
float m_bms_defthr_twarn; // Default temperature deviation warn threshold [°C]
|
|
float m_bms_defthr_talert; // Default temperature deviation alert threshold [°C]
|
|
uint32_t m_bms_vlog_last; // Last log time for voltages
|
|
uint32_t m_bms_tlog_last; // Last log time for temperatures
|
|
|
|
protected:
|
|
void BmsSetCellArrangementVoltage(int readings, int readingspermodule);
|
|
void BmsSetCellArrangementTemperature(int readings, int readingspermodule);
|
|
void BmsSetCellDefaultThresholdsVoltage(float warn, float alert, float maxgrad=-1, float maxsddev=-1);
|
|
void BmsSetCellDefaultThresholdsTemperature(float warn, float alert);
|
|
void BmsSetCellLimitsVoltage(float min, float max);
|
|
void BmsSetCellLimitsTemperature(float min, float max);
|
|
void BmsSetCellVoltage(int index, float value);
|
|
void BmsResetCellVoltages(bool full = false);
|
|
void BmsSetCellTemperature(int index, float value);
|
|
void BmsResetCellTemperatures(bool full = false);
|
|
void BmsRestartCellVoltages();
|
|
void BmsRestartCellTemperatures();
|
|
void BmsTicker();
|
|
virtual void NotifyBmsAlerts();
|
|
|
|
public:
|
|
int BmsGetCellArangementVoltage(int* readings=NULL, int* readingspermodule=NULL);
|
|
int BmsGetCellArangementTemperature(int* readings=NULL, int* readingspermodule=NULL);
|
|
void BmsGetCellDefaultThresholdsVoltage(float* warn, float* alert, float* maxgrad=NULL, float* maxsddev=NULL);
|
|
void BmsGetCellDefaultThresholdsTemperature(float* warn, float* alert);
|
|
void BmsResetCellStats();
|
|
virtual void BmsStatus(int verbosity, OvmsWriter* writer, vehicle_bms_status_t statusmode);
|
|
virtual bool FormatBmsAlerts(int verbosity, OvmsWriter* writer, bool show_warnings);
|
|
bool BmsCheckChangeCellArrangementVoltage(int readings, int readingspermodule = 0);
|
|
bool BmsCheckChangeCellArrangementTemperature(int readings, int readingspermodule = 0);
|
|
};
|
|
|
|
template<typename Type> OvmsVehicle* CreateVehicle()
|
|
{
|
|
return new Type;
|
|
}
|
|
|
|
class OvmsVehicleFactory
|
|
{
|
|
public:
|
|
OvmsVehicleFactory();
|
|
~OvmsVehicleFactory();
|
|
|
|
public:
|
|
typedef OvmsVehicle* (*FactoryFuncPtr)();
|
|
typedef struct
|
|
{
|
|
FactoryFuncPtr construct;
|
|
const char* name;
|
|
} vehicle_t;
|
|
typedef CNameMap<vehicle_t> map_vehicle_t;
|
|
|
|
OvmsVehicle *m_currentvehicle;
|
|
std::string m_currentvehicletype;
|
|
map_vehicle_t m_vmap;
|
|
|
|
public:
|
|
template<typename Type>
|
|
short RegisterVehicle(const char* VehicleType, const char* VehicleName = "")
|
|
{
|
|
FactoryFuncPtr function = &CreateVehicle<Type>;
|
|
m_vmap.insert(std::make_pair(VehicleType, (vehicle_t){ function, VehicleName }));
|
|
return 0;
|
|
};
|
|
OvmsVehicle* NewVehicle(const char* VehicleType);
|
|
void ClearVehicle();
|
|
void SetVehicle(const char* type);
|
|
void AutoInit();
|
|
OvmsVehicle* ActiveVehicle();
|
|
const char* ActiveVehicleType();
|
|
const char* ActiveVehicleName();
|
|
const char* ActiveVehicleShortName();
|
|
|
|
// Shell commands:
|
|
protected:
|
|
static int vehicle_validate(OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv, bool complete);
|
|
static void vehicle_module(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_list(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_status(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_wakeup(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_homelink(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_climatecontrol(int verbosity, OvmsWriter* writer, bool on);
|
|
static void vehicle_climatecontrol_on(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_climatecontrol_off(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_lock(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_unlock(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_valet(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_unvalet(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_charge_mode(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_charge_current(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_charge_start(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_charge_stop(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_charge_cooldown(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_stat(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void vehicle_stat_trip(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void bms_status(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void bms_reset(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void bms_alerts(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
static void obdii_request(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
|
|
|
#ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
|
|
protected:
|
|
static duk_ret_t DukOvmsVehicleType(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleWakeup(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleHomelink(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleClimateControl(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleLock(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleUnlock(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleValet(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleUnvalet(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleSetChargeMode(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleSetChargeCurrent(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleSetChargeTimer(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleStartCharge(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleStopCharge(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleStartCooldown(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleStopCooldown(duk_context *ctx);
|
|
static duk_ret_t DukOvmsVehicleObdRequest(duk_context *ctx);
|
|
#endif // CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
|
|
};
|
|
|
|
extern OvmsVehicleFactory MyVehicleFactory;
|
|
|
|
#endif //#ifndef __VEHICLE_H__
|