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") } }