mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 18:29:48 +02:00
Use base class for Chademo battery
This commit is contained in:
parent
6b21cc3b07
commit
764fc8cca9
4 changed files with 362 additions and 349 deletions
|
@ -1,233 +0,0 @@
|
||||||
#ifndef CHADEMO_BATTERY_TYPES_H
|
|
||||||
#define CHADEMO_BATTERY_TYPES_H
|
|
||||||
|
|
||||||
#define MAX_EVSE_POWER_CHARGING 3300
|
|
||||||
#define MAX_EVSE_OUTPUT_VOLTAGE 410
|
|
||||||
#define MAX_EVSE_OUTPUT_CURRENT 11
|
|
||||||
|
|
||||||
enum CHADEMO_STATE {
|
|
||||||
CHADEMO_FAULT,
|
|
||||||
CHADEMO_STOP,
|
|
||||||
CHADEMO_IDLE,
|
|
||||||
CHADEMO_CONNECTED,
|
|
||||||
CHADEMO_INIT, // intermediate state indicating CAN from Vehicle not yet received after connection
|
|
||||||
CHADEMO_NEGOTIATE,
|
|
||||||
CHADEMO_EV_ALLOWED,
|
|
||||||
CHADEMO_EVSE_PREPARE,
|
|
||||||
CHADEMO_EVSE_START,
|
|
||||||
CHADEMO_EVSE_CONTACTORS_ENABLED,
|
|
||||||
CHADEMO_POWERFLOW,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Mode { CHADEMO_CHARGE, CHADEMO_DISCHARGE, CHADEMO_BIDIRECTIONAL };
|
|
||||||
|
|
||||||
/* Charge/discharge sequence, indicating applicable V2H guideline
|
|
||||||
* If sequence number is not agreed upon via H201/H209 between EVSE and Vehicle,
|
|
||||||
* V2H 1.1 is assumed, which..is somehow between 0x0 and 0x1 ? TODO: better understanding here
|
|
||||||
* Use CHADEMO_seq to decide whether emitting 209 is necessary
|
|
||||||
* 0x0 1.0 and earlier
|
|
||||||
* 0x1 2.0 appendix A
|
|
||||||
* 0x2 2.0 appendix B
|
|
||||||
* TODO: is this influenced by x109->CHADEMO_protocol_number, or x102->ControlProtocolNumberEV ??
|
|
||||||
* Unused for now.
|
|
||||||
uint8_t CHADEMO_seq = 0x0;
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*----------- CHARGING SUPPORT V2X --------------------------------------------------------------*/
|
|
||||||
/* ---------- VEHICLE Data structures */
|
|
||||||
|
|
||||||
//H100 - Vehicle - Minimum charging expectations
|
|
||||||
//TODO decide whether default values for vehicle-origin frames is even appropriate
|
|
||||||
struct x100_Vehicle_Charging_Limits {
|
|
||||||
uint8_t MinimumChargeCurrent = 0;
|
|
||||||
uint16_t MinimumBatteryVoltage = 300;
|
|
||||||
uint16_t MaximumBatteryVoltage = 402;
|
|
||||||
uint8_t ConstantOfChargingRateIndication = 0;
|
|
||||||
};
|
|
||||||
//H101 - Vehicle - Maximum charging expectations
|
|
||||||
struct x101_Vehicle_Charging_Estimate {
|
|
||||||
uint8_t MaxChargingTime10sBit = 0;
|
|
||||||
uint8_t MaxChargingTime1minBit = 0;
|
|
||||||
uint8_t EstimatedChargingTime = 0;
|
|
||||||
uint16_t RatedBatteryCapacity = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
//H102 - Vehicle - Charging targets and Status
|
|
||||||
// peer to x109 from EVSE
|
|
||||||
// termination triggers in both
|
|
||||||
// TODO see also Table A.26—Charge control termination command patterns
|
|
||||||
struct x102_Vehicle_Charging_Session { //Frame byte
|
|
||||||
uint8_t ControlProtocolNumberEV = 0; // 0
|
|
||||||
uint16_t TargetBatteryVoltage = 0; // 1-2
|
|
||||||
uint8_t ChargingCurrentRequest = 0; // 3 Note: per spec, units for this changed from kWh --> %
|
|
||||||
|
|
||||||
union {
|
|
||||||
uint8_t faults;
|
|
||||||
struct {
|
|
||||||
bool unused_3 : 1;
|
|
||||||
bool unused_2 : 1;
|
|
||||||
bool unused_1 : 1;
|
|
||||||
bool FaultBatteryVoltageDeviation : 1; // 4
|
|
||||||
bool FaultHighBatteryTemperature : 1; // 3
|
|
||||||
bool FaultBatteryCurrentDeviation : 1; // 2
|
|
||||||
bool FaultBatteryUnderVoltage : 1; // 1
|
|
||||||
bool FaultBatteryOverVoltage : 1; // 0
|
|
||||||
} fault;
|
|
||||||
} f;
|
|
||||||
|
|
||||||
union {
|
|
||||||
uint8_t packed;
|
|
||||||
struct {
|
|
||||||
bool StatusVehicleDischargeCompatible : 1; //5.7
|
|
||||||
bool unused_2 : 1; //5.6
|
|
||||||
bool unused_1 : 1; //5.5
|
|
||||||
bool StatusNormalStopRequest : 1; //5.4
|
|
||||||
bool StatusVehicle : 1; //5.3
|
|
||||||
bool StatusChargingError : 1; //5.2
|
|
||||||
bool StatusVehicleShifterPosition : 1; //5.1
|
|
||||||
bool StatusVehicleChargingEnabled : 1; //5.0 - bit zero is TODO. Vehicle charging enabled ==1 *AND* charge
|
|
||||||
// permission signal k needs to be active for charging to be
|
|
||||||
// permitted -- TODO document bits per byte for these flags
|
|
||||||
// and update variables to be more appropriate
|
|
||||||
} status;
|
|
||||||
} s;
|
|
||||||
|
|
||||||
uint8_t StateOfCharge = 0; //6 state of charge?
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ---------- CHARGING: EVSE Data structures */
|
|
||||||
struct x108_EVSE_Capabilities { // Frame byte
|
|
||||||
bool contactor_weld_detection = 1; // 0
|
|
||||||
uint16_t available_output_voltage = MAX_EVSE_OUTPUT_VOLTAGE; // 1,2
|
|
||||||
uint8_t available_output_current = MAX_EVSE_OUTPUT_CURRENT; // 3
|
|
||||||
uint16_t threshold_voltage = 297; // 4,5 voltage that EVSE will stop if car fails to
|
|
||||||
// perhaps vehicle minus 3%, hardcoded initially to 96*2.95
|
|
||||||
// 6,7 = unused
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Does double duty for charging and discharging */
|
|
||||||
struct x109_EVSE_Status { // Frame byte
|
|
||||||
uint8_t CHADEMO_protocol_number = 0x02; // 0
|
|
||||||
uint16_t setpoint_HV_VDC =
|
|
||||||
0; // 1,2 NOTE: charger_setpoint_HV_VDC elsewhere is a float. THIS is protocol-defined as an int. cast float->int and lose some precision for protocol adherence
|
|
||||||
uint8_t setpoint_HV_IDC = 0; // 3
|
|
||||||
//
|
|
||||||
bool discharge_compatible = true; // 4, bit 0. bits
|
|
||||||
// 4, bit 7-6 (?) unused. spec typo? maybe 1-7 unused
|
|
||||||
union {
|
|
||||||
uint8_t packed;
|
|
||||||
struct {
|
|
||||||
bool EVSE_status : 1; // 5, bit 0
|
|
||||||
bool EVSE_error : 1; // 5, bit 1
|
|
||||||
bool connector_locked : 1; // 5, bit 2 //NOTE: treated as connector_lock during discharge, but
|
|
||||||
// seen as 'energizing' during charging mode
|
|
||||||
|
|
||||||
bool battery_incompatible : 1; // 5, bit 3
|
|
||||||
bool ChgDischError : 1; // 5, bit 4
|
|
||||||
|
|
||||||
bool ChgDischStopControl : 1; // 5, bit 5 - set to false for initialization to indicate 'preparing to charge'
|
|
||||||
// set to false when ready to charge/discharge
|
|
||||||
|
|
||||||
} status;
|
|
||||||
} s;
|
|
||||||
|
|
||||||
// Either, or; not both.
|
|
||||||
// seconds field set to 0xFF by default
|
|
||||||
// indicating only the minutes field is used instead
|
|
||||||
// BOTH observed initially set to 0xFF in logs, so use
|
|
||||||
// that as the initialzed value
|
|
||||||
uint8_t remaining_time_10s = 0xFF; // 6
|
|
||||||
uint8_t remaining_time_1m = 0xFF; // 7
|
|
||||||
};
|
|
||||||
|
|
||||||
/*----------- DISCHARGING SUPPORT V2X --------------------------------------------------------------*/
|
|
||||||
/* ---------- VEHICLE Data structures */
|
|
||||||
//H200 - Vehicle - Discharge limits
|
|
||||||
struct x200_Vehicle_Discharge_Limits {
|
|
||||||
uint8_t MaximumDischargeCurrent = 0xFF;
|
|
||||||
uint16_t MinimumDischargeVoltage = 0;
|
|
||||||
uint16_t MinimumBatteryDischargeLevel = 0;
|
|
||||||
uint16_t MaxRemainingCapacityForCharging = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* TODO When charge/discharge sequence control number (ID201/209) is not received, the vehicle or the EVSE
|
|
||||||
should determine that the other is the EVSE or the vehicle of the model before the V2H guideline 1.1. */
|
|
||||||
//H201 - Vehicle - Estimated capacity available
|
|
||||||
// Intended primarily for display purposes.
|
|
||||||
// Peer to H209
|
|
||||||
// NOTE: in available CAN logs from a Leaf, 209 is sent with no 201 reply, so < 1.1 must be the inferred version
|
|
||||||
struct x201_Vehicle_Discharge_Estimate {
|
|
||||||
uint8_t V2HchargeDischargeSequenceNum = 0;
|
|
||||||
uint16_t ApproxDischargeCompletionTime = 0;
|
|
||||||
uint16_t AvailableVehicleEnergy = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ---------- EVSE Data structures */
|
|
||||||
struct x208_EVSE_Discharge_Capability { // Frame byte
|
|
||||||
uint8_t present_discharge_current = 0xFF; // 0
|
|
||||||
uint16_t available_input_voltage = 500; // 1,2 -- poorly named as both 'available' and minimum input voltage
|
|
||||||
uint16_t available_input_current = 250; // 3 -- poorly named as both 'available' and maximum input current
|
|
||||||
// spec idiosyncracy in naming/description
|
|
||||||
// 4,5 = unused
|
|
||||||
uint16_t lower_threshold_voltage = 0; // 6,7
|
|
||||||
};
|
|
||||||
|
|
||||||
// H209 - EVSE - Estimated Discharge Duration
|
|
||||||
// peer to Vehicle's 201 event (Note: 209 seen
|
|
||||||
// in CAN logs even when 201 is not)
|
|
||||||
struct x209_EVSE_Discharge_Estimate { // Frame byte
|
|
||||||
uint8_t sequence_control_number = 0x2; // 0
|
|
||||||
uint16_t remaining_discharge_time = 0x0000; // 0x0000 == unused
|
|
||||||
};
|
|
||||||
|
|
||||||
/*----------- DYNAMIC CONTROL SUPPORT --------------------------------------------------------------*/
|
|
||||||
/* ---------- VEHICLE Data structures */
|
|
||||||
struct x110_Vehicle_Dynamic_Control { //Frame byte
|
|
||||||
union {
|
|
||||||
uint8_t packed;
|
|
||||||
struct {
|
|
||||||
bool PermissionResetMaxChgTime : 1; // bit 5 or 6? is this only x118 not x110?
|
|
||||||
bool unused_3 : 1;
|
|
||||||
bool unused_2 : 1;
|
|
||||||
bool unused_1 : 1;
|
|
||||||
bool HighVoltageControlStatus : 1; // bit 2 = High voltage control support
|
|
||||||
bool HighCurrentControlStatus : 1; // bit 1 = High current control support
|
|
||||||
// rate of change is -20A/s to 20A/s relative to 102.3
|
|
||||||
bool DynamicControlStatus : 1; // bit 0 = Dynamic Control support
|
|
||||||
} status;
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ---------- EVSE Data structures */
|
|
||||||
// TODO 118
|
|
||||||
//H118
|
|
||||||
//see also table a.59 page 104 IEEE
|
|
||||||
struct x118_EVSE_Dynamic_Control { // Frame byte
|
|
||||||
union {
|
|
||||||
uint8_t packed;
|
|
||||||
struct {
|
|
||||||
bool PermissionResetMaxChgTime : 1; // bit 5 or 6?
|
|
||||||
bool unused_3 : 1;
|
|
||||||
bool unused_2 : 1;
|
|
||||||
bool unused_1 : 1;
|
|
||||||
bool HighVoltageControlStatus : 1; // bit 2 = High voltage control support
|
|
||||||
bool HighCurrentControlStatus : 1; // bit 1 = High current control support
|
|
||||||
// rate of change is -20A/s to 20A/s relative to 102.3
|
|
||||||
bool DynamicControlStatus : 1; // bit 0 = Dynamic Control support
|
|
||||||
} status;
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*----------- MANUFACTURER ID SUPPORT --------------------------------------------------------------*/
|
|
||||||
/* ---------- VEHICLE Data structures */
|
|
||||||
//H700 - Vehicle - Manufacturer identification
|
|
||||||
//Peer to H708
|
|
||||||
//Used to adapt to manufacturer-prescribed optional specification
|
|
||||||
struct x700_Vehicle_Vendor_ID {
|
|
||||||
uint8_t AutomakerCode = 0; // 0 = set to 0x0 to indicate incompatibility. Best as a starting place
|
|
||||||
uint8_t OptionalContent = 0; // 1-7, variable per vendor spec
|
|
||||||
};
|
|
||||||
|
|
||||||
void handle_chademo_sequence();
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -2,7 +2,6 @@
|
||||||
#ifdef CHADEMO_BATTERY
|
#ifdef CHADEMO_BATTERY
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "CHADEMO-BATTERY-INTERNAL.h"
|
|
||||||
#include "CHADEMO-BATTERY.h"
|
#include "CHADEMO-BATTERY.h"
|
||||||
#include "CHADEMO-SHUNTS.h"
|
#include "CHADEMO-SHUNTS.h"
|
||||||
|
|
||||||
|
@ -14,101 +13,8 @@
|
||||||
#define CAN_STILL_ALIVE 75
|
#define CAN_STILL_ALIVE 75
|
||||||
//#define CH_CAN_DEBUG
|
//#define CH_CAN_DEBUG
|
||||||
|
|
||||||
static unsigned long setupMillis = 0;
|
|
||||||
static unsigned long handlerBeforeMillis = 0;
|
|
||||||
static unsigned long handlerAfterMillis = 0;
|
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
|
||||||
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
|
||||||
static unsigned long previousMillis5000 =
|
|
||||||
0; // will store last time a 5s threshold was reached for display during debug
|
|
||||||
|
|
||||||
bool plug_inserted = false;
|
|
||||||
bool vehicle_can_initialized = false;
|
|
||||||
bool vehicle_can_received = false;
|
|
||||||
bool vehicle_permission = false;
|
|
||||||
bool evse_permission = false;
|
|
||||||
|
|
||||||
bool precharge_low = false;
|
|
||||||
bool positive_high = false;
|
|
||||||
bool contactors_ready = false;
|
|
||||||
|
|
||||||
uint8_t framecount = 0;
|
|
||||||
|
|
||||||
uint8_t max_discharge_current = 0; //TODO not sure on this one, but really influenced by inverter capability
|
|
||||||
|
|
||||||
bool high_current_control_enabled = false; // set to true when high current control is operating
|
|
||||||
// if true, values from 110.1 and 110.2 should be used instead of 102.3
|
|
||||||
// and 118 should be used for evse responses
|
|
||||||
// permissible rate of change is -20A/s to 20A/s relative to 102.3
|
|
||||||
|
|
||||||
Mode EVSE_mode = CHADEMO_DISCHARGE;
|
|
||||||
CHADEMO_STATE CHADEMO_Status = CHADEMO_IDLE;
|
|
||||||
|
|
||||||
/* Charge/discharge sequence, indicating applicable V2H guideline
|
|
||||||
* If sequence number is not agreed upon via H201/H209 between EVSE and Vehicle,
|
|
||||||
* V2H 1.1 is assumed
|
|
||||||
* Use CHADEMO_seq to decide whether emitting 209 is necessary
|
|
||||||
* 0x0 1.0 and earlier
|
|
||||||
* 0x1 2.0 appendix A
|
|
||||||
* 0x2 2.0 appendix B
|
|
||||||
* Unused for now.
|
|
||||||
uint8_t CHADEMO_seq = 0x0;
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool x201_received = false;
|
|
||||||
bool x209_sent = false;
|
|
||||||
|
|
||||||
struct x100_Vehicle_Charging_Limits x100_chg_lim = {};
|
|
||||||
struct x101_Vehicle_Charging_Estimate x101_chg_est = {};
|
|
||||||
struct x102_Vehicle_Charging_Session x102_chg_session = {};
|
|
||||||
struct x110_Vehicle_Dynamic_Control x110_vehicle_dyn = {};
|
|
||||||
struct x200_Vehicle_Discharge_Limits x200_discharge_limits = {};
|
|
||||||
struct x201_Vehicle_Discharge_Estimate x201_discharge_estimate = {};
|
|
||||||
struct x700_Vehicle_Vendor_ID x700_vendor_id = {};
|
|
||||||
|
|
||||||
struct x209_EVSE_Discharge_Estimate x209_evse_dischg_est;
|
|
||||||
struct x108_EVSE_Capabilities x108_evse_cap;
|
|
||||||
struct x109_EVSE_Status x109_evse_state;
|
|
||||||
struct x118_EVSE_Dynamic_Control x118_evse_dyn;
|
|
||||||
struct x208_EVSE_Discharge_Capability x208_evse_dischg_cap;
|
|
||||||
|
|
||||||
CAN_frame CHADEMO_108 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x108,
|
|
||||||
.data = {0x01, 0xF4, 0x01, 0x0F, 0xB3, 0x01, 0x00, 0x00}};
|
|
||||||
CAN_frame CHADEMO_109 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x109,
|
|
||||||
.data = {0x02, 0x00, 0x00, 0x00, 0x01, 0x20, 0xFF, 0xFF}};
|
|
||||||
//For chademo v2.0 only
|
|
||||||
CAN_frame CHADEMO_118 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x118,
|
|
||||||
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
|
||||||
|
|
||||||
// OLD value from skeleton implementation, indicates dynamic control is possible.
|
|
||||||
// Hardcode above as being incompatible for simplicity in current incarnation.
|
|
||||||
// .data = {0x10, 0x64, 0x00, 0xB0, 0x00, 0x1E, 0x00, 0x8F}};
|
|
||||||
|
|
||||||
// 0x200 : From vehicle-side. A V2X-ready vehicle will send this message to broadcast its “Maximum discharger current”. (It is a similar logic to the limits set in 0x100 or 0x102 during a DC charging session)
|
|
||||||
// 0x208 : From EVSE-side. A V2X EVSE will use this to send the “present discharger current” during the session, and the “available input current”. (uses similar logic to 0x108 and 0x109 during a DC charging session)
|
|
||||||
CAN_frame CHADEMO_208 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x208,
|
|
||||||
.data = {0xFF, 0xF4, 0x01, 0xF0, 0x00, 0x00, 0xFA, 0x00}};
|
|
||||||
CAN_frame CHADEMO_209 = {.FD = false,
|
|
||||||
.ext_ID = false,
|
|
||||||
.DLC = 8,
|
|
||||||
.ID = 0x209,
|
|
||||||
.data = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
|
||||||
|
|
||||||
//This function maps all the values fetched via CAN to the correct parameters used for the inverter
|
//This function maps all the values fetched via CAN to the correct parameters used for the inverter
|
||||||
void update_values_battery() {
|
void ChademoBattery::update_values() {
|
||||||
|
|
||||||
datalayer.battery.status.real_soc = x102_chg_session.StateOfCharge;
|
datalayer.battery.status.real_soc = x102_chg_session.StateOfCharge;
|
||||||
|
|
||||||
|
@ -147,21 +53,21 @@ void update_values_battery() {
|
||||||
//see IEEE Table A.26—Charge control termination command pattern on pg58
|
//see IEEE Table A.26—Charge control termination command pattern on pg58
|
||||||
//for stop conditions
|
//for stop conditions
|
||||||
|
|
||||||
inline void process_vehicle_charging_minimums(CAN_frame rx_frame) {
|
void ChademoBattery::process_vehicle_charging_minimums(CAN_frame rx_frame) {
|
||||||
x100_chg_lim.MinimumChargeCurrent = rx_frame.data.u8[0];
|
x100_chg_lim.MinimumChargeCurrent = rx_frame.data.u8[0];
|
||||||
x100_chg_lim.MinimumBatteryVoltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
|
x100_chg_lim.MinimumBatteryVoltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]);
|
||||||
x100_chg_lim.MaximumBatteryVoltage = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]);
|
x100_chg_lim.MaximumBatteryVoltage = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]);
|
||||||
x100_chg_lim.ConstantOfChargingRateIndication = rx_frame.data.u8[6];
|
x100_chg_lim.ConstantOfChargingRateIndication = rx_frame.data.u8[6];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void process_vehicle_charging_maximums(CAN_frame rx_frame) {
|
void ChademoBattery::process_vehicle_charging_maximums(CAN_frame rx_frame) {
|
||||||
x101_chg_est.MaxChargingTime10sBit = rx_frame.data.u8[1];
|
x101_chg_est.MaxChargingTime10sBit = rx_frame.data.u8[1];
|
||||||
x101_chg_est.MaxChargingTime1minBit = rx_frame.data.u8[2];
|
x101_chg_est.MaxChargingTime1minBit = rx_frame.data.u8[2];
|
||||||
x101_chg_est.EstimatedChargingTime = rx_frame.data.u8[3];
|
x101_chg_est.EstimatedChargingTime = rx_frame.data.u8[3];
|
||||||
x101_chg_est.RatedBatteryCapacity = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[5]);
|
x101_chg_est.RatedBatteryCapacity = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void process_vehicle_charging_session(CAN_frame rx_frame) {
|
void ChademoBattery::process_vehicle_charging_session(CAN_frame rx_frame) {
|
||||||
uint16_t newTargetBatteryVoltage = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[1]);
|
uint16_t newTargetBatteryVoltage = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[1]);
|
||||||
uint16_t priorTargetBatteryVoltage = x102_chg_session.TargetBatteryVoltage;
|
uint16_t priorTargetBatteryVoltage = x102_chg_session.TargetBatteryVoltage;
|
||||||
uint8_t newChargingCurrentRequest = rx_frame.data.u8[3];
|
uint8_t newChargingCurrentRequest = rx_frame.data.u8[3];
|
||||||
|
@ -303,7 +209,7 @@ inline void process_vehicle_charging_session(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* x200 Vehicle, peer to x208 EVSE */
|
/* x200 Vehicle, peer to x208 EVSE */
|
||||||
inline void process_vehicle_charging_limits(CAN_frame rx_frame) {
|
void ChademoBattery::process_vehicle_charging_limits(CAN_frame rx_frame) {
|
||||||
|
|
||||||
x200_discharge_limits.MaximumDischargeCurrent = rx_frame.data.u8[0];
|
x200_discharge_limits.MaximumDischargeCurrent = rx_frame.data.u8[0];
|
||||||
x200_discharge_limits.MinimumDischargeVoltage = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]);
|
x200_discharge_limits.MinimumDischargeVoltage = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]);
|
||||||
|
@ -332,7 +238,7 @@ inline void process_vehicle_charging_limits(CAN_frame rx_frame) {
|
||||||
/* Vehicle 0x201, peer to EVSE 0x209
|
/* Vehicle 0x201, peer to EVSE 0x209
|
||||||
* HOWEVER, 201 isn't even emitted in any of the v2x canlogs available
|
* HOWEVER, 201 isn't even emitted in any of the v2x canlogs available
|
||||||
*/
|
*/
|
||||||
inline void process_vehicle_discharge_estimate(CAN_frame rx_frame) {
|
void ChademoBattery::process_vehicle_discharge_estimate(CAN_frame rx_frame) {
|
||||||
unsigned long currentMillis = millis();
|
unsigned long currentMillis = millis();
|
||||||
|
|
||||||
x201_discharge_estimate.V2HchargeDischargeSequenceNum = rx_frame.data.u8[0];
|
x201_discharge_estimate.V2HchargeDischargeSequenceNum = rx_frame.data.u8[0];
|
||||||
|
@ -350,7 +256,7 @@ inline void process_vehicle_discharge_estimate(CAN_frame rx_frame) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void process_vehicle_dynamic_control(CAN_frame rx_frame) {
|
void ChademoBattery::process_vehicle_dynamic_control(CAN_frame rx_frame) {
|
||||||
//SM Dynamic Control = Charging station can increase of decrease "available output current" during charging.
|
//SM Dynamic Control = Charging station can increase of decrease "available output current" during charging.
|
||||||
//If you set 0x110 byte 0, bit 0 to 1 you say you can do dynamic control.
|
//If you set 0x110 byte 0, bit 0 to 1 you say you can do dynamic control.
|
||||||
//Charging station communicates this in 0x118 byte 0, bit 0
|
//Charging station communicates this in 0x118 byte 0, bit 0
|
||||||
|
@ -359,13 +265,13 @@ inline void process_vehicle_dynamic_control(CAN_frame rx_frame) {
|
||||||
x110_vehicle_dyn.u.status.DynamicControlStatus = bitRead(rx_frame.data.u8[0], 0);
|
x110_vehicle_dyn.u.status.DynamicControlStatus = bitRead(rx_frame.data.u8[0], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void process_vehicle_vendor_ID(CAN_frame rx_frame) {
|
void ChademoBattery::process_vehicle_vendor_ID(CAN_frame rx_frame) {
|
||||||
x700_vendor_id.AutomakerCode = rx_frame.data.u8[0];
|
x700_vendor_id.AutomakerCode = rx_frame.data.u8[0];
|
||||||
x700_vendor_id.OptionalContent =
|
x700_vendor_id.OptionalContent =
|
||||||
((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[1]); //Actually more bytes, but not needed for our purpose
|
((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[1]); //Actually more bytes, but not needed for our purpose
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
void ChademoBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
|
||||||
#ifdef CH_CAN_DEBUG
|
#ifdef CH_CAN_DEBUG
|
||||||
logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D
|
logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D
|
||||||
logging.print(" ");
|
logging.print(" ");
|
||||||
|
@ -438,7 +344,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (re)initialize evse structures to pre-charge/discharge states */
|
/* (re)initialize evse structures to pre-charge/discharge states */
|
||||||
void evse_init() {
|
void ChademoBattery::evse_init() {
|
||||||
// Held at 1 until start of charge when set to 0
|
// Held at 1 until start of charge when set to 0
|
||||||
// returns to 1 when ceasing power flow
|
// returns to 1 when ceasing power flow
|
||||||
// mutually exclusive values
|
// mutually exclusive values
|
||||||
|
@ -457,7 +363,7 @@ void evse_init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* updates for x108 */
|
/* updates for x108 */
|
||||||
void update_evse_capabilities(CAN_frame& f) {
|
void ChademoBattery::update_evse_capabilities(CAN_frame& f) {
|
||||||
|
|
||||||
/* TODO use charger defines/runtime config?
|
/* TODO use charger defines/runtime config?
|
||||||
* for now..leave as a future tweak.
|
* for now..leave as a future tweak.
|
||||||
|
@ -495,7 +401,7 @@ void update_evse_capabilities(CAN_frame& f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* updates for x109 */
|
/* updates for x109 */
|
||||||
void update_evse_status(CAN_frame& f) {
|
void ChademoBattery::update_evse_status(CAN_frame& f) {
|
||||||
|
|
||||||
x109_evse_state.s.status.EVSE_status = 1;
|
x109_evse_state.s.status.EVSE_status = 1;
|
||||||
x109_evse_state.s.status.EVSE_error = 0;
|
x109_evse_state.s.status.EVSE_error = 0;
|
||||||
|
@ -586,7 +492,7 @@ void update_evse_status(CAN_frame& f) {
|
||||||
* NOTE: x209 is emitted in CAN logs when x201 isn't even present
|
* NOTE: x209 is emitted in CAN logs when x201 isn't even present
|
||||||
* it may not be understood by leaf (or ignored unless >= a certain protocol version or v2h sequence number
|
* it may not be understood by leaf (or ignored unless >= a certain protocol version or v2h sequence number
|
||||||
*/
|
*/
|
||||||
void update_evse_discharge_estimate(CAN_frame& f) {
|
void ChademoBattery::update_evse_discharge_estimate(CAN_frame& f) {
|
||||||
|
|
||||||
//x209_evse_dischg_est.remaining_discharge_time_1m = x201_discharge_estimate.ApproxDischargeCompletionTime;
|
//x209_evse_dischg_est.remaining_discharge_time_1m = x201_discharge_estimate.ApproxDischargeCompletionTime;
|
||||||
|
|
||||||
|
@ -605,7 +511,7 @@ void update_evse_discharge_estimate(CAN_frame& f) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* x208 EVSE, peer to 0x200 Vehicle */
|
/* x208 EVSE, peer to 0x200 Vehicle */
|
||||||
void update_evse_discharge_capabilities(CAN_frame& f) {
|
void ChademoBattery::update_evse_discharge_capabilities(CAN_frame& f) {
|
||||||
//present discharge current is a measured value
|
//present discharge current is a measured value
|
||||||
x208_evse_dischg_cap.present_discharge_current = 0xFF - get_measured_current();
|
x208_evse_dischg_cap.present_discharge_current = 0xFF - get_measured_current();
|
||||||
|
|
||||||
|
@ -655,7 +561,7 @@ void update_evse_discharge_capabilities(CAN_frame& f) {
|
||||||
CHADEMO_208.data.u8[7] = highByte(x208_evse_dischg_cap.lower_threshold_voltage);
|
CHADEMO_208.data.u8[7] = highByte(x208_evse_dischg_cap.lower_threshold_voltage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void transmit_can_battery(unsigned long currentMillis) {
|
void ChademoBattery::transmit_can(unsigned long currentMillis) {
|
||||||
|
|
||||||
handlerBeforeMillis = currentMillis;
|
handlerBeforeMillis = currentMillis;
|
||||||
handle_chademo_sequence();
|
handle_chademo_sequence();
|
||||||
|
@ -733,7 +639,7 @@ void transmit_can_battery(unsigned long currentMillis) {
|
||||||
* 5) Emergency stop stage
|
* 5) Emergency stop stage
|
||||||
* CHADEMO_FAULT
|
* CHADEMO_FAULT
|
||||||
*/
|
*/
|
||||||
void handle_chademo_sequence() {
|
void ChademoBattery::handle_chademo_sequence() {
|
||||||
|
|
||||||
precharge_low = digitalRead(PRECHARGE_PIN) == LOW;
|
precharge_low = digitalRead(PRECHARGE_PIN) == LOW;
|
||||||
positive_high = digitalRead(POSITIVE_CONTACTOR_PIN) == HIGH;
|
positive_high = digitalRead(POSITIVE_CONTACTOR_PIN) == HIGH;
|
||||||
|
@ -1020,7 +926,7 @@ void handle_chademo_sequence() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_battery(void) { // Performs one time setup at startup
|
void ChademoBattery::setup(void) { // Performs one time setup at startup
|
||||||
|
|
||||||
pinMode(CHADEMO_PIN_2, OUTPUT);
|
pinMode(CHADEMO_PIN_2, OUTPUT);
|
||||||
digitalWrite(CHADEMO_PIN_2, LOW);
|
digitalWrite(CHADEMO_PIN_2, LOW);
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
#define CHADEMO_BATTERY_H
|
#define CHADEMO_BATTERY_H
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
#include "CanBattery.h"
|
||||||
#define BATTERY_SELECTED
|
|
||||||
|
|
||||||
//Contactor control is required for CHADEMO support
|
//Contactor control is required for CHADEMO support
|
||||||
#define CONTACTOR_CONTROL
|
#define CONTACTOR_CONTROL
|
||||||
|
@ -12,7 +11,349 @@
|
||||||
// other measurement sources may be added in the future
|
// other measurement sources may be added in the future
|
||||||
#define ISA_SHUNT
|
#define ISA_SHUNT
|
||||||
|
|
||||||
void setup_battery(void);
|
#define BATTERY_SELECTED
|
||||||
void transmit_can_frame(CAN_frame* tx_frame, int interface);
|
#define SELECTED_BATTERY_CLASS ChademoBattery
|
||||||
|
|
||||||
|
class ChademoBattery : public CanBattery {
|
||||||
|
public:
|
||||||
|
virtual void setup(void);
|
||||||
|
virtual void handle_incoming_can_frame(CAN_frame rx_frame);
|
||||||
|
virtual void update_values();
|
||||||
|
virtual void transmit_can(unsigned long currentMillis);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void process_vehicle_charging_minimums(CAN_frame rx_frame);
|
||||||
|
void process_vehicle_charging_maximums(CAN_frame rx_frame);
|
||||||
|
void process_vehicle_charging_session(CAN_frame rx_frame);
|
||||||
|
void process_vehicle_charging_limits(CAN_frame rx_frame);
|
||||||
|
void process_vehicle_discharge_estimate(CAN_frame rx_frame);
|
||||||
|
void process_vehicle_dynamic_control(CAN_frame rx_frame);
|
||||||
|
void process_vehicle_vendor_ID(CAN_frame rx_frame);
|
||||||
|
void evse_init();
|
||||||
|
void update_evse_capabilities(CAN_frame& f);
|
||||||
|
void update_evse_status(CAN_frame& f);
|
||||||
|
void update_evse_discharge_estimate(CAN_frame& f);
|
||||||
|
void update_evse_discharge_capabilities(CAN_frame& f);
|
||||||
|
void handle_chademo_sequence();
|
||||||
|
|
||||||
|
static const int MAX_EVSE_POWER_CHARGING = 3300;
|
||||||
|
static const int MAX_EVSE_OUTPUT_VOLTAGE = 410;
|
||||||
|
static const int MAX_EVSE_OUTPUT_CURRENT = 11;
|
||||||
|
|
||||||
|
enum CHADEMO_STATE {
|
||||||
|
CHADEMO_FAULT,
|
||||||
|
CHADEMO_STOP,
|
||||||
|
CHADEMO_IDLE,
|
||||||
|
CHADEMO_CONNECTED,
|
||||||
|
CHADEMO_INIT, // intermediate state indicating CAN from Vehicle not yet received after connection
|
||||||
|
CHADEMO_NEGOTIATE,
|
||||||
|
CHADEMO_EV_ALLOWED,
|
||||||
|
CHADEMO_EVSE_PREPARE,
|
||||||
|
CHADEMO_EVSE_START,
|
||||||
|
CHADEMO_EVSE_CONTACTORS_ENABLED,
|
||||||
|
CHADEMO_POWERFLOW,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Mode { CHADEMO_CHARGE, CHADEMO_DISCHARGE, CHADEMO_BIDIRECTIONAL };
|
||||||
|
|
||||||
|
/* Charge/discharge sequence, indicating applicable V2H guideline
|
||||||
|
* If sequence number is not agreed upon via H201/H209 between EVSE and Vehicle,
|
||||||
|
* V2H 1.1 is assumed, which..is somehow between 0x0 and 0x1 ? TODO: better understanding here
|
||||||
|
* Use CHADEMO_seq to decide whether emitting 209 is necessary
|
||||||
|
* 0x0 1.0 and earlier
|
||||||
|
* 0x1 2.0 appendix A
|
||||||
|
* 0x2 2.0 appendix B
|
||||||
|
* TODO: is this influenced by x109->CHADEMO_protocol_number, or x102->ControlProtocolNumberEV ??
|
||||||
|
* Unused for now.
|
||||||
|
uint8_t CHADEMO_seq = 0x0;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*----------- CHARGING SUPPORT V2X --------------------------------------------------------------*/
|
||||||
|
/* ---------- VEHICLE Data structures */
|
||||||
|
|
||||||
|
//H100 - Vehicle - Minimum charging expectations
|
||||||
|
//TODO decide whether default values for vehicle-origin frames is even appropriate
|
||||||
|
struct x100_Vehicle_Charging_Limits {
|
||||||
|
uint8_t MinimumChargeCurrent = 0;
|
||||||
|
uint16_t MinimumBatteryVoltage = 300;
|
||||||
|
uint16_t MaximumBatteryVoltage = 402;
|
||||||
|
uint8_t ConstantOfChargingRateIndication = 0;
|
||||||
|
};
|
||||||
|
//H101 - Vehicle - Maximum charging expectations
|
||||||
|
struct x101_Vehicle_Charging_Estimate {
|
||||||
|
uint8_t MaxChargingTime10sBit = 0;
|
||||||
|
uint8_t MaxChargingTime1minBit = 0;
|
||||||
|
uint8_t EstimatedChargingTime = 0;
|
||||||
|
uint16_t RatedBatteryCapacity = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//H102 - Vehicle - Charging targets and Status
|
||||||
|
// peer to x109 from EVSE
|
||||||
|
// termination triggers in both
|
||||||
|
// TODO see also Table A.26—Charge control termination command patterns
|
||||||
|
struct x102_Vehicle_Charging_Session { //Frame byte
|
||||||
|
uint8_t ControlProtocolNumberEV = 0; // 0
|
||||||
|
uint16_t TargetBatteryVoltage = 0; // 1-2
|
||||||
|
uint8_t ChargingCurrentRequest = 0; // 3 Note: per spec, units for this changed from kWh --> %
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t faults;
|
||||||
|
struct {
|
||||||
|
bool unused_3 : 1;
|
||||||
|
bool unused_2 : 1;
|
||||||
|
bool unused_1 : 1;
|
||||||
|
bool FaultBatteryVoltageDeviation : 1; // 4
|
||||||
|
bool FaultHighBatteryTemperature : 1; // 3
|
||||||
|
bool FaultBatteryCurrentDeviation : 1; // 2
|
||||||
|
bool FaultBatteryUnderVoltage : 1; // 1
|
||||||
|
bool FaultBatteryOverVoltage : 1; // 0
|
||||||
|
} fault;
|
||||||
|
} f;
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint8_t packed;
|
||||||
|
struct {
|
||||||
|
bool StatusVehicleDischargeCompatible : 1; //5.7
|
||||||
|
bool unused_2 : 1; //5.6
|
||||||
|
bool unused_1 : 1; //5.5
|
||||||
|
bool StatusNormalStopRequest : 1; //5.4
|
||||||
|
bool StatusVehicle : 1; //5.3
|
||||||
|
bool StatusChargingError : 1; //5.2
|
||||||
|
bool StatusVehicleShifterPosition : 1; //5.1
|
||||||
|
bool StatusVehicleChargingEnabled : 1; //5.0 - bit zero is TODO. Vehicle charging enabled ==1 *AND* charge
|
||||||
|
// permission signal k needs to be active for charging to be
|
||||||
|
// permitted -- TODO document bits per byte for these flags
|
||||||
|
// and update variables to be more appropriate
|
||||||
|
} status;
|
||||||
|
} s;
|
||||||
|
|
||||||
|
uint8_t StateOfCharge = 0; //6 state of charge?
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ---------- CHARGING: EVSE Data structures */
|
||||||
|
struct x108_EVSE_Capabilities { // Frame byte
|
||||||
|
bool contactor_weld_detection = 1; // 0
|
||||||
|
uint16_t available_output_voltage = MAX_EVSE_OUTPUT_VOLTAGE; // 1,2
|
||||||
|
uint8_t available_output_current = MAX_EVSE_OUTPUT_CURRENT; // 3
|
||||||
|
uint16_t threshold_voltage = 297; // 4,5 voltage that EVSE will stop if car fails to
|
||||||
|
// perhaps vehicle minus 3%, hardcoded initially to 96*2.95
|
||||||
|
// 6,7 = unused
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Does double duty for charging and discharging */
|
||||||
|
struct x109_EVSE_Status { // Frame byte
|
||||||
|
uint8_t CHADEMO_protocol_number = 0x02; // 0
|
||||||
|
uint16_t setpoint_HV_VDC =
|
||||||
|
0; // 1,2 NOTE: charger_setpoint_HV_VDC elsewhere is a float. THIS is protocol-defined as an int. cast float->int and lose some precision for protocol adherence
|
||||||
|
uint8_t setpoint_HV_IDC = 0; // 3
|
||||||
|
//
|
||||||
|
bool discharge_compatible = true; // 4, bit 0. bits
|
||||||
|
// 4, bit 7-6 (?) unused. spec typo? maybe 1-7 unused
|
||||||
|
union {
|
||||||
|
uint8_t packed;
|
||||||
|
struct {
|
||||||
|
bool EVSE_status : 1; // 5, bit 0
|
||||||
|
bool EVSE_error : 1; // 5, bit 1
|
||||||
|
bool connector_locked : 1; // 5, bit 2 //NOTE: treated as connector_lock during discharge, but
|
||||||
|
// seen as 'energizing' during charging mode
|
||||||
|
|
||||||
|
bool battery_incompatible : 1; // 5, bit 3
|
||||||
|
bool ChgDischError : 1; // 5, bit 4
|
||||||
|
|
||||||
|
bool ChgDischStopControl : 1; // 5, bit 5 - set to false for initialization to indicate 'preparing to charge'
|
||||||
|
// set to false when ready to charge/discharge
|
||||||
|
|
||||||
|
} status;
|
||||||
|
} s;
|
||||||
|
|
||||||
|
// Either, or; not both.
|
||||||
|
// seconds field set to 0xFF by default
|
||||||
|
// indicating only the minutes field is used instead
|
||||||
|
// BOTH observed initially set to 0xFF in logs, so use
|
||||||
|
// that as the initialzed value
|
||||||
|
uint8_t remaining_time_10s = 0xFF; // 6
|
||||||
|
uint8_t remaining_time_1m = 0xFF; // 7
|
||||||
|
};
|
||||||
|
|
||||||
|
/*----------- DISCHARGING SUPPORT V2X --------------------------------------------------------------*/
|
||||||
|
/* ---------- VEHICLE Data structures */
|
||||||
|
//H200 - Vehicle - Discharge limits
|
||||||
|
struct x200_Vehicle_Discharge_Limits {
|
||||||
|
uint8_t MaximumDischargeCurrent = 0xFF;
|
||||||
|
uint16_t MinimumDischargeVoltage = 0;
|
||||||
|
uint16_t MinimumBatteryDischargeLevel = 0;
|
||||||
|
uint16_t MaxRemainingCapacityForCharging = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* TODO When charge/discharge sequence control number (ID201/209) is not received, the vehicle or the EVSE
|
||||||
|
should determine that the other is the EVSE or the vehicle of the model before the V2H guideline 1.1. */
|
||||||
|
//H201 - Vehicle - Estimated capacity available
|
||||||
|
// Intended primarily for display purposes.
|
||||||
|
// Peer to H209
|
||||||
|
// NOTE: in available CAN logs from a Leaf, 209 is sent with no 201 reply, so < 1.1 must be the inferred version
|
||||||
|
struct x201_Vehicle_Discharge_Estimate {
|
||||||
|
uint8_t V2HchargeDischargeSequenceNum = 0;
|
||||||
|
uint16_t ApproxDischargeCompletionTime = 0;
|
||||||
|
uint16_t AvailableVehicleEnergy = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ---------- EVSE Data structures */
|
||||||
|
struct x208_EVSE_Discharge_Capability { // Frame byte
|
||||||
|
uint8_t present_discharge_current = 0xFF; // 0
|
||||||
|
uint16_t available_input_voltage = 500; // 1,2 -- poorly named as both 'available' and minimum input voltage
|
||||||
|
uint16_t available_input_current = 250; // 3 -- poorly named as both 'available' and maximum input current
|
||||||
|
// spec idiosyncracy in naming/description
|
||||||
|
// 4,5 = unused
|
||||||
|
uint16_t lower_threshold_voltage = 0; // 6,7
|
||||||
|
};
|
||||||
|
|
||||||
|
// H209 - EVSE - Estimated Discharge Duration
|
||||||
|
// peer to Vehicle's 201 event (Note: 209 seen
|
||||||
|
// in CAN logs even when 201 is not)
|
||||||
|
struct x209_EVSE_Discharge_Estimate { // Frame byte
|
||||||
|
uint8_t sequence_control_number = 0x2; // 0
|
||||||
|
uint16_t remaining_discharge_time = 0x0000; // 0x0000 == unused
|
||||||
|
};
|
||||||
|
|
||||||
|
/*----------- DYNAMIC CONTROL SUPPORT --------------------------------------------------------------*/
|
||||||
|
/* ---------- VEHICLE Data structures */
|
||||||
|
struct x110_Vehicle_Dynamic_Control { //Frame byte
|
||||||
|
union {
|
||||||
|
uint8_t packed;
|
||||||
|
struct {
|
||||||
|
bool PermissionResetMaxChgTime : 1; // bit 5 or 6? is this only x118 not x110?
|
||||||
|
bool unused_3 : 1;
|
||||||
|
bool unused_2 : 1;
|
||||||
|
bool unused_1 : 1;
|
||||||
|
bool HighVoltageControlStatus : 1; // bit 2 = High voltage control support
|
||||||
|
bool HighCurrentControlStatus : 1; // bit 1 = High current control support
|
||||||
|
// rate of change is -20A/s to 20A/s relative to 102.3
|
||||||
|
bool DynamicControlStatus : 1; // bit 0 = Dynamic Control support
|
||||||
|
} status;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ---------- EVSE Data structures */
|
||||||
|
// TODO 118
|
||||||
|
//H118
|
||||||
|
//see also table a.59 page 104 IEEE
|
||||||
|
struct x118_EVSE_Dynamic_Control { // Frame byte
|
||||||
|
union {
|
||||||
|
uint8_t packed;
|
||||||
|
struct {
|
||||||
|
bool PermissionResetMaxChgTime : 1; // bit 5 or 6?
|
||||||
|
bool unused_3 : 1;
|
||||||
|
bool unused_2 : 1;
|
||||||
|
bool unused_1 : 1;
|
||||||
|
bool HighVoltageControlStatus : 1; // bit 2 = High voltage control support
|
||||||
|
bool HighCurrentControlStatus : 1; // bit 1 = High current control support
|
||||||
|
// rate of change is -20A/s to 20A/s relative to 102.3
|
||||||
|
bool DynamicControlStatus : 1; // bit 0 = Dynamic Control support
|
||||||
|
} status;
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*----------- MANUFACTURER ID SUPPORT --------------------------------------------------------------*/
|
||||||
|
/* ---------- VEHICLE Data structures */
|
||||||
|
//H700 - Vehicle - Manufacturer identification
|
||||||
|
//Peer to H708
|
||||||
|
//Used to adapt to manufacturer-prescribed optional specification
|
||||||
|
struct x700_Vehicle_Vendor_ID {
|
||||||
|
uint8_t AutomakerCode = 0; // 0 = set to 0x0 to indicate incompatibility. Best as a starting place
|
||||||
|
uint8_t OptionalContent = 0; // 1-7, variable per vendor spec
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned long setupMillis = 0;
|
||||||
|
unsigned long handlerBeforeMillis = 0;
|
||||||
|
unsigned long handlerAfterMillis = 0;
|
||||||
|
|
||||||
|
/* Do not change code below unless you are sure what you are doing */
|
||||||
|
unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
||||||
|
unsigned long previousMillis5000 = 0; // will store last time a 5s threshold was reached for display during debug
|
||||||
|
|
||||||
|
bool plug_inserted = false;
|
||||||
|
bool vehicle_can_initialized = false;
|
||||||
|
bool vehicle_can_received = false;
|
||||||
|
bool vehicle_permission = false;
|
||||||
|
bool evse_permission = false;
|
||||||
|
|
||||||
|
bool precharge_low = false;
|
||||||
|
bool positive_high = false;
|
||||||
|
bool contactors_ready = false;
|
||||||
|
|
||||||
|
uint8_t framecount = 0;
|
||||||
|
|
||||||
|
uint8_t max_discharge_current = 0; //TODO not sure on this one, but really influenced by inverter capability
|
||||||
|
|
||||||
|
bool high_current_control_enabled = false; // set to true when high current control is operating
|
||||||
|
// if true, values from 110.1 and 110.2 should be used instead of 102.3
|
||||||
|
// and 118 should be used for evse responses
|
||||||
|
// permissible rate of change is -20A/s to 20A/s relative to 102.3
|
||||||
|
|
||||||
|
Mode EVSE_mode = CHADEMO_DISCHARGE;
|
||||||
|
CHADEMO_STATE CHADEMO_Status = CHADEMO_IDLE;
|
||||||
|
|
||||||
|
/* Charge/discharge sequence, indicating applicable V2H guideline
|
||||||
|
* If sequence number is not agreed upon via H201/H209 between EVSE and Vehicle,
|
||||||
|
* V2H 1.1 is assumed
|
||||||
|
* Use CHADEMO_seq to decide whether emitting 209 is necessary
|
||||||
|
* 0x0 1.0 and earlier
|
||||||
|
* 0x1 2.0 appendix A
|
||||||
|
* 0x2 2.0 appendix B
|
||||||
|
* Unused for now.
|
||||||
|
uint8_t CHADEMO_seq = 0x0;
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool x201_received = false;
|
||||||
|
bool x209_sent = false;
|
||||||
|
|
||||||
|
struct x100_Vehicle_Charging_Limits x100_chg_lim = {};
|
||||||
|
struct x101_Vehicle_Charging_Estimate x101_chg_est = {};
|
||||||
|
struct x102_Vehicle_Charging_Session x102_chg_session = {};
|
||||||
|
struct x110_Vehicle_Dynamic_Control x110_vehicle_dyn = {};
|
||||||
|
struct x200_Vehicle_Discharge_Limits x200_discharge_limits = {};
|
||||||
|
struct x201_Vehicle_Discharge_Estimate x201_discharge_estimate = {};
|
||||||
|
struct x700_Vehicle_Vendor_ID x700_vendor_id = {};
|
||||||
|
|
||||||
|
struct x209_EVSE_Discharge_Estimate x209_evse_dischg_est;
|
||||||
|
struct x108_EVSE_Capabilities x108_evse_cap;
|
||||||
|
struct x109_EVSE_Status x109_evse_state;
|
||||||
|
struct x118_EVSE_Dynamic_Control x118_evse_dyn;
|
||||||
|
struct x208_EVSE_Discharge_Capability x208_evse_dischg_cap;
|
||||||
|
|
||||||
|
CAN_frame CHADEMO_108 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x108,
|
||||||
|
.data = {0x01, 0xF4, 0x01, 0x0F, 0xB3, 0x01, 0x00, 0x00}};
|
||||||
|
CAN_frame CHADEMO_109 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x109,
|
||||||
|
.data = {0x02, 0x00, 0x00, 0x00, 0x01, 0x20, 0xFF, 0xFF}};
|
||||||
|
//For chademo v2.0 only
|
||||||
|
CAN_frame CHADEMO_118 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x118,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
|
||||||
|
// OLD value from skeleton implementation, indicates dynamic control is possible.
|
||||||
|
// Hardcode above as being incompatible for simplicity in current incarnation.
|
||||||
|
// .data = {0x10, 0x64, 0x00, 0xB0, 0x00, 0x1E, 0x00, 0x8F}};
|
||||||
|
|
||||||
|
// 0x200 : From vehicle-side. A V2X-ready vehicle will send this message to broadcast its “Maximum discharger current”. (It is a similar logic to the limits set in 0x100 or 0x102 during a DC charging session)
|
||||||
|
// 0x208 : From EVSE-side. A V2X EVSE will use this to send the “present discharger current” during the session, and the “available input current”. (uses similar logic to 0x108 and 0x109 during a DC charging session)
|
||||||
|
CAN_frame CHADEMO_208 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x208,
|
||||||
|
.data = {0xFF, 0xF4, 0x01, 0xF0, 0x00, 0x00, 0xFA, 0x00}};
|
||||||
|
CAN_frame CHADEMO_209 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 8,
|
||||||
|
.ID = 0x209,
|
||||||
|
.data = {0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
#ifdef CHADEMO_BATTERY
|
#ifdef CHADEMO_BATTERY
|
||||||
#include "../datalayer/datalayer.h"
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
#include "CHADEMO-BATTERY-INTERNAL.h"
|
|
||||||
#include "CHADEMO-BATTERY.h"
|
#include "CHADEMO-BATTERY.h"
|
||||||
#include "CHADEMO-SHUNTS.h"
|
#include "CHADEMO-SHUNTS.h"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue