OVMS3/OVMS.V3/components/vehicle/vehicle.h

787 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)
// 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;
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;
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)
short* 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)
short* 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);
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__