package main import ( "fmt" ) const ( CAN_ID_100 = 256 CAN_ID_101 = 257 CAN_ID_102 = 258 DISABLED VehicleChargingEnabled = iota ENABLED PARKING ShiftLeverPosition = iota OTHER NORMAL SystemFault = iota FAULT CONTACTOR_CLOSED ContactorVehicleStatus = iota CONTACTOR_OPEN NO_REQUEST StopRequest = iota STOP_REQUEST ) type VehicleChargingEnabled uint8 type ShiftLeverPosition uint8 type SystemFault uint8 type ContactorVehicleStatus uint8 type StopRequest 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 // ControlProtocolNumber Software version of control protocol to which EV corresponds type ControlProtocolNumber 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 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 <- &ControlProtocolNumber{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} } } }() 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 (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 ControlProtocolNumber) 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 (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") } }