Simple app to transform IEC 61851-24 CAN bus dump to human readable messages.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
chademo-log/chademo.go

575 lines
15 KiB

package main
import (
"fmt"
)
const (
CAN_ID_100 = 0x100
CAN_ID_101 = 0x101
CAN_ID_102 = 0x102
CAN_ID_108 = 0x108
CAN_ID_109 = 0x109
DISABLED VehicleChargingEnabled = iota
ENABLED
PARKING ShiftLeverPosition = iota
OTHER
NORMAL SystemFault = iota
FAULT
CONTACTOR_CLOSED ContactorVehicleStatus = iota
CONTACTOR_OPEN
NO_REQUEST StopRequest = iota
STOP_REQUEST
VEHICLE_WELDING_DETECTION_SUPPORTED SuppVehicleWeldingDetection = iota
VEHICLE_WELDING_DETECTION_NOT_SUPPORTED
STANDBY StationState = iota
CHARGING
CONNECTOR_LOCKED ConnectorLock = iota
CONNECTOR_UNLOCKED
BATTERY_COMPATIBLE BatteryCompatible = iota
BATTERY_INCOMPATIBLE
OPERATING StopControl = iota
SHUTDOWN_STOP
)
type VehicleChargingEnabled uint8
type ShiftLeverPosition uint8
type SystemFault uint8
type ContactorVehicleStatus uint8
type StopRequest uint8
type SuppVehicleWeldingDetection uint8
type StationState uint8
type ConnectorLock uint8
type BatteryCompatible uint8
type StopControl uint8
type ChademoEvent interface {
// GetValue Return processed/calculated value and timestamp string
GetValue() (interface{}, *string)
}
type frame struct {
*CanFrame
}
// MaximumBatteryVoltage The maximum voltage value at the vehicle inlet terminals, at which the station stops charging to protect the vehicle battery
type MaximumBatteryVoltage frame
// ConstChargingRateInd Fixed value for charging rate indication, which is the maximum charging rate (100 %) of vehicle battery
type ConstChargingRateInd frame
// BatteryCapacity Rated capacity of battery
type BatteryCapacity frame
// MaxChargingTimeS Maximum charging time permitted by EV, set by 10 s
type MaxChargingTimeS frame
// MaxChargingTimeM Maximum charging time permitted by EV, set by minute
type MaxChargingTimeM frame
// EstChargingTimeM Estimated remaining time before the end of charging calculated by EV
type EstChargingTimeM frame
// EVControlProtocolNumber Software version of control protocol to which EV corresponds
type EVControlProtocolNumber frame
// TargetBatteryVoltage Target battery voltage ed charging voltage at the vehicle inlet terminals
type TargetBatteryVoltage frame
// ChargingCurrentReq Current value requested by EV during charging
type ChargingCurrentReq frame
// ChargingRate Charging rate of vehicle battery
type ChargingRate frame
// VehicleCharging Status flag indicating charge permission status of EV
type VehicleCharging frame
// ShiftLever Status flag indicating the shift lever position
type ShiftLever frame
// ChargingSystemFault Status flag indicating Charging system fault a malfunction caused by EV or the station, and detected by EV
type ChargingSystemFault frame
// VehicleStatus Status flag indicating the EV contactor status
type VehicleStatus frame
// NormalStopReq Status flag indicating the request of EV to stop charging control
type NormalStopReq frame
// BattOvervoltage Status flag indicating whether or not the vehicle battery voltage exceeds the maximum limit specified by EV
type BattOvervoltage frame
// BattUndervoltage Status flag indicating whether or not the vehicle battery voltage is less than the lower limit specified by EV
type BattUndervoltage frame
// BattCurrentDeviationErr Status flag indicating whether or not the output current deviates from EV requested current
type BattCurrentDeviationErr frame
// HighBattTemperature Status flag indicating whether or not the temperature of vehicle battery exceeds the maximum limit
type HighBattTemperature frame
// BattVoltageDeviationErr Status flag indicating whether or not the vehicle battery voltage deviates from the output voltage measured by the station
type BattVoltageDeviationErr frame
// EVSE entity from here
// EVcontWeldingDetectSupport Identifier indicating whether or not the station deals with EV contactor welding detection
type EVcontWeldingDetectSupport frame
// AvailableOutputVoltage Maximum output voltage value at the vehicle connector terminals
type AvailableOutputVoltage frame
// AvailableOutputCurrent Maximum output current value of the station
type AvailableOutputCurrent frame
// ThresholdVoltage Threshold voltage to stop the charging process in order to protect vehicle battery
type ThresholdVoltage frame
// EVSEControlProtocolNumber Software version number of control protocol or charging sequences that the station deals with
type EVSEControlProtocolNumber frame
// OutputVoltage Supply voltage value of the output circuit in the station
type OutputVoltage frame
// OutputCurrent Supply current value of the output circuit in the station
type OutputCurrent frame
// RemainingChargingTimeS Remaining time before the end of charging (counted by 10 s)
type RemainingChargingTimeS frame
// RemainingChargingTimeM Remaining time before the end of charging (counted by min)
type RemainingChargingTimeM frame
// StationStatus Status flag indicating the energy transfer from the station
type StationStatus frame
// StationMalfunction Status flag indicating whether or not there is a malfunction caused by the station
type StationMalfunction frame
// VehicleConnectorLock Status flag indicating Vehicle connector lock the electromagnetic lock status of vehicle connector
type VehicleConnectorLock frame
// BatteryIncompatibility Status flag indicating the compatibility of vehicle battery with the output voltage of station
type BatteryIncompatibility frame
// ChargingSystemMalfunction Status flag indicating whether or not there is a problem with EV, such as improper connection
type ChargingSystemMalfunction frame
// ChargerStopControl Status flag indicating whether or not the station proceeds with shutdown process
type ChargerStopControl frame
func FromCanFrames(frames <-chan *CanFrame) <-chan ChademoEvent {
events := make(chan ChademoEvent)
go func() {
defer close(events)
for frame := range frames {
switch frame.canid {
case CAN_ID_100:
events <- &MaximumBatteryVoltage{frame}
events <- &ConstChargingRateInd{frame}
case CAN_ID_101:
events <- &BatteryCapacity{frame}
events <- &MaxChargingTimeS{frame}
events <- &MaxChargingTimeM{frame}
events <- &EstChargingTimeM{frame}
case CAN_ID_102:
events <- &EVControlProtocolNumber{frame}
events <- &TargetBatteryVoltage{frame}
events <- &ChargingCurrentReq{frame}
events <- &ChargingRate{frame}
events <- &VehicleCharging{frame}
events <- &ShiftLever{frame}
events <- &ChargingSystemFault{frame}
events <- &VehicleStatus{frame}
events <- &NormalStopReq{frame}
events <- &BattOvervoltage{frame}
events <- &BattUndervoltage{frame}
events <- &BattCurrentDeviationErr{frame}
events <- &HighBattTemperature{frame}
events <- &BattVoltageDeviationErr{frame}
case CAN_ID_108:
events <- &EVcontWeldingDetectSupport{frame}
events <- &AvailableOutputVoltage{frame}
events <- &AvailableOutputCurrent{frame}
events <- &ThresholdVoltage{frame}
case CAN_ID_109:
events <- &EVSEControlProtocolNumber{frame}
events <- &OutputVoltage{frame}
events <- &OutputCurrent{frame}
events <- &RemainingChargingTimeS{frame}
events <- &RemainingChargingTimeM{frame}
events <- &StationStatus{frame}
events <- &StationMalfunction{frame}
events <- &VehicleConnectorLock{frame}
events <- &BatteryIncompatibility{frame}
events <- &ChargingSystemMalfunction{frame}
events <- &ChargerStopControl{frame}
}
}
}()
return events
}
func getVehicleShiftLever(bytes *[]byte) ShiftLeverPosition {
if isBitSet((*bytes)[5], 1) {
return OTHER
}
return PARKING
}
func getVehicleStatus(bytes *[]byte) ContactorVehicleStatus {
if isBitSet((*bytes)[5], 3) {
return CONTACTOR_OPEN
}
return CONTACTOR_CLOSED
}
func getNormalStopReq(bytes *[]byte) StopRequest {
if isBitSet((*bytes)[5], 4) {
return STOP_REQUEST
}
return NO_REQUEST
}
func getFault(bytes *[]byte, octet byte, bit byte) SystemFault {
if isBitSet((*bytes)[octet], bit) {
return FAULT
}
return NORMAL
}
func getVehicleCharging(bytes *[]uint8) VehicleChargingEnabled {
if isBitSet((*bytes)[5], 0) {
return ENABLED
}
return DISABLED
}
func isBitSet(buf uint8, num uint8) bool {
mask := uint8(1) << num
val := buf & mask
if val == mask {
return true
}
return false
}
func bytesToUint16(bytes []uint8) uint16 {
if len(bytes) != 2 {
fmt.Println("Wrong array size in bytesToUint16()")
return 0
}
var result uint16
result = uint16(bytes[1]) << 8
result = result | uint16(bytes[0])
return result
}
func evWeldingDetectionSupport(bytes *[]uint8) SuppVehicleWeldingDetection {
if (*bytes)[0] == 0 {
return VEHICLE_WELDING_DETECTION_NOT_SUPPORTED
}
return VEHICLE_WELDING_DETECTION_SUPPORTED
}
func getStationState(bytes *[]uint8) StationState {
if isBitSet((*bytes)[5], 0) {
return CHARGING
}
return STANDBY
}
func getConnectorLock(bytes *[]byte) ConnectorLock {
if isBitSet((*bytes)[5], 2) {
return CONNECTOR_LOCKED
}
return CONNECTOR_UNLOCKED
}
func getBatteryCompatibility(bytes *[]uint8) BatteryCompatible {
if isBitSet((*bytes)[5], 3) {
return BATTERY_INCOMPATIBLE
}
return BATTERY_COMPATIBLE
}
func getChargerStopControl(bytes *[]uint8) StopControl {
if isBitSet((*bytes)[5], 5) {
return SHUTDOWN_STOP
}
return OPERATING
}
func (m MaximumBatteryVoltage) GetValue() (interface{}, *string) {
return bytesToUint16(m.payload[4:6]), &m.date
}
func (c ConstChargingRateInd) GetValue() (interface{}, *string) {
return c.payload[6], &c.date
}
func (b BatteryCapacity) GetValue() (interface{}, *string) {
return 0.1 * float32(bytesToUint16(b.payload[5:7])), &b.date
}
func (m MaxChargingTimeS) GetValue() (interface{}, *string) {
return 10 * uint16(m.payload[1]), &m.date
}
func (m MaxChargingTimeM) GetValue() (interface{}, *string) {
return m.payload[2], &m.date
}
func (e EstChargingTimeM) GetValue() (interface{}, *string) {
return e.payload[3], &e.date
}
func (c EVControlProtocolNumber) GetValue() (interface{}, *string) {
return c.payload[0], &c.date
}
func (t TargetBatteryVoltage) GetValue() (interface{}, *string) {
return bytesToUint16(t.payload[1:3]), &t.date
}
func (c ChargingCurrentReq) GetValue() (interface{}, *string) {
return c.payload[3], &c.date
}
func (c ChargingRate) GetValue() (interface{}, *string) {
return c.payload[6], &c.date
}
func (s ShiftLever) GetValue() (interface{}, *string) {
return getVehicleShiftLever(&s.payload), &s.date
}
func (v VehicleCharging) GetValue() (interface{}, *string) {
return getVehicleCharging(&v.payload), &v.date
}
func (c ChargingSystemFault) GetValue() (interface{}, *string) {
return getFault(&c.payload, 5, 2), &c.date
}
func (v VehicleStatus) GetValue() (interface{}, *string) {
return getVehicleStatus(&v.payload), &v.date
}
func (n NormalStopReq) GetValue() (interface{}, *string) {
return getNormalStopReq(&n.payload), &n.date
}
func (b BattOvervoltage) GetValue() (interface{}, *string) {
return getFault(&b.payload, 4, 0), &b.date
}
func (b BattUndervoltage) GetValue() (interface{}, *string) {
return getFault(&b.payload, 4, 1), &b.date
}
func (b BattCurrentDeviationErr) GetValue() (interface{}, *string) {
return getFault(&b.payload, 4, 2), &b.date
}
func (h HighBattTemperature) GetValue() (interface{}, *string) {
return getFault(&h.payload, 4, 3), &h.date
}
func (b BattVoltageDeviationErr) GetValue() (interface{}, *string) {
return getFault(&b.payload, 4, 4), &b.date
}
func (e EVcontWeldingDetectSupport) GetValue() (interface{}, *string) {
return evWeldingDetectionSupport(&e.payload), &e.date
}
func (a AvailableOutputVoltage) GetValue() (interface{}, *string) {
return bytesToUint16(a.payload[1:3]), &a.date
}
func (a AvailableOutputCurrent) GetValue() (interface{}, *string) {
return a.payload[3], &a.date
}
func (t ThresholdVoltage) GetValue() (interface{}, *string) {
return bytesToUint16(t.payload[4:6]), &t.date
}
func (e EVSEControlProtocolNumber) GetValue() (interface{}, *string) {
return e.payload[0], &e.date
}
func (o OutputVoltage) GetValue() (interface{}, *string) {
return bytesToUint16(o.payload[1:3]), &o.date
}
func (o OutputCurrent) GetValue() (interface{}, *string) {
return o.payload[3], &o.date
}
func (r RemainingChargingTimeS) GetValue() (interface{}, *string) {
return r.payload[6] * 10, &r.date
}
func (r RemainingChargingTimeM) GetValue() (interface{}, *string) {
return r.payload[7], &r.date
}
func (s StationStatus) GetValue() (interface{}, *string) {
return getStationState(&s.payload), &s.date
}
func (s StationMalfunction) GetValue() (interface{}, *string) {
return getFault(&s.payload, 5, 1), &s.date
}
func (v VehicleConnectorLock) GetValue() (interface{}, *string) {
return getConnectorLock(&v.payload), &v.date
}
func (b BatteryIncompatibility) GetValue() (interface{}, *string) {
return getBatteryCompatibility(&b.payload), &b.date
}
func (c ChargingSystemMalfunction) GetValue() (interface{}, *string) {
return getFault(&c.payload, 5, 4), &c.date
}
func (c ChargerStopControl) GetValue() (interface{}, *string) {
return getChargerStopControl(&c.payload), &c.date
}
func (v VehicleChargingEnabled) String() string {
switch v {
case DISABLED:
return "disabled"
case ENABLED:
return "enabled"
default:
panic("VehicleChargingEnabled not implemented")
}
}
func (s ShiftLeverPosition) String() string {
switch s {
case PARKING:
return "parking"
case OTHER:
return "other"
default:
panic("ShiftLeverPosition not implemented")
}
}
func (s SystemFault) String() string {
switch s {
case NORMAL:
return "normal"
case FAULT:
return "fault"
default:
panic("SystemFault not implemented")
}
}
func (c ContactorVehicleStatus) String() string {
switch c {
case CONTACTOR_CLOSED:
return "contactor closed"
case CONTACTOR_OPEN:
return "contactor open"
default:
panic("ContactorVehicleStatus not implemented")
}
}
func (s StopRequest) String() string {
switch s {
case NO_REQUEST:
return "no request"
case STOP_REQUEST:
return "stop request"
default:
panic("StopRequest not implemented")
}
}
func (s SuppVehicleWeldingDetection) String() string {
switch s {
case VEHICLE_WELDING_DETECTION_NOT_SUPPORTED:
return "not supported"
case VEHICLE_WELDING_DETECTION_SUPPORTED:
return "supported"
default:
panic("SuppVehicleWeldingDetection not implemented")
}
}
func (s StationState) String() string {
switch s {
case CHARGING:
return "charging"
case STANDBY:
return "standby"
default:
panic("StationState not implemented")
}
}
func (c ConnectorLock) String() string {
switch c {
case CONNECTOR_LOCKED:
return "locked"
case CONNECTOR_UNLOCKED:
return "unlocked"
default:
panic("ConnectorLock not implemented")
}
}
func (b BatteryCompatible) String() string {
switch b {
case BATTERY_COMPATIBLE:
return "compatible"
case BATTERY_INCOMPATIBLE:
return "incompatible"
default:
panic("BatteryCompatible not implemented")
}
}
func (s StopControl) String() string {
switch s {
case OPERATING:
return "operating"
case SHUTDOWN_STOP:
return "shutdown or stop charging"
default:
panic("StopControl not implemented")
}
}