Initial commit
Signed-off-by: didinst <9f6129a2ddff0d0c6d03169eaa75e3fea1c1770f>
This commit is contained in:
Generated
+8
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
@@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type CanFrame struct {
|
||||
canid uint16
|
||||
payload []uint8
|
||||
date string
|
||||
}
|
||||
|
||||
// (2022-07-08 16:54:15.587099) can0 100 [8] 00 00 00 00 00 00 64 00
|
||||
const expr = "\\((.*)\\)\\s+can\\d+\\s+(\\d+)\\s+\\[\\d\\]\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)\\s+([A-F0-9]+)"
|
||||
const length = 11
|
||||
|
||||
var pattern = regexp.MustCompile(expr)
|
||||
|
||||
func FromString(text *string) *CanFrame {
|
||||
submatch := pattern.FindStringSubmatch(*text)
|
||||
if len(submatch) == length {
|
||||
canid, err := strconv.Atoi(submatch[2])
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
payload := make([]uint8, 8)
|
||||
for idx, octet := range submatch[3:] {
|
||||
val, err := strconv.ParseUint(octet, 16, 0)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
payload[idx] = uint8(val)
|
||||
}
|
||||
|
||||
return &CanFrame{
|
||||
date: submatch[1],
|
||||
canid: uint16(canid),
|
||||
payload: payload,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFromString(t *testing.T) {
|
||||
type args struct {
|
||||
text *string
|
||||
}
|
||||
|
||||
var dump = "(2022-07-08 16:54:15.587099) can0 100 [8] 00 00 00 00 00 00 64 00"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *CanFrame
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{
|
||||
name: "Candump parsing test",
|
||||
args: args{text: &dump},
|
||||
want: &CanFrame{
|
||||
canid: 100,
|
||||
date: "2022-07-08 16:54:15.587099",
|
||||
payload: []uint8{0, 0, 0, 0, 0, 0, 0x64, 0},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := FromString(tt.args.text); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("FromString() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
filename := flag.String("f", "", "Candump filename")
|
||||
flag.Parse()
|
||||
|
||||
var frames <-chan *CanFrame
|
||||
|
||||
switch {
|
||||
case len(*filename) > 0:
|
||||
fmt.Printf("Open %v\n", *filename)
|
||||
frames = readfile(filename)
|
||||
default:
|
||||
flag.Usage()
|
||||
}
|
||||
|
||||
if frames == nil {
|
||||
fmt.Println("Get no data")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
events := FromCanFrames(frames)
|
||||
|
||||
fmt.Printf("Value %v", PARKING)
|
||||
|
||||
for event := range events {
|
||||
|
||||
switch msg := event.(type) {
|
||||
default:
|
||||
fmt.Println(msg)
|
||||
}
|
||||
|
||||
fmt.Println(event.GetValue())
|
||||
|
||||
//if msg, isType := event.(MaximumBatteryVoltage); isType {
|
||||
// fmt.Printf("MaximumBatteryVoltage: %v\n", msg.GetMaxBattVoltage())
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
func readfile(filename *string) <-chan *CanFrame {
|
||||
c := make(chan *CanFrame)
|
||||
|
||||
go func() {
|
||||
defer close(c)
|
||||
|
||||
file, err := os.Open(*filename)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
text := scanner.Text()
|
||||
c <- FromString(&text)
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}()
|
||||
|
||||
return c
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
CAN_ID_100 = 100
|
||||
CAN_ID_101 = 101
|
||||
CAN_ID_102 = 102
|
||||
|
||||
DISABLED VehicleCharging = iota
|
||||
ENABLED
|
||||
|
||||
PARKING ShiftLever = iota
|
||||
OTHER
|
||||
|
||||
NORMAL SystemFault = iota
|
||||
FAULT
|
||||
|
||||
CONTACTOR_CLOSED VehicleStatus = iota
|
||||
CONTACTOR_OPEN
|
||||
|
||||
NO_REQUEST StopRequest = iota
|
||||
STOP_REQUEST
|
||||
)
|
||||
|
||||
type VehicleCharging uint8
|
||||
|
||||
type ShiftLever uint8
|
||||
|
||||
type SystemFault uint8
|
||||
|
||||
type VehicleStatus uint8
|
||||
|
||||
type StopRequest uint8
|
||||
|
||||
type ChademoEvent interface {
|
||||
GetValue() interface{}
|
||||
}
|
||||
|
||||
type MaximumBatteryVoltage interface {
|
||||
// GetMaxBattVoltage Maximum battery voltage
|
||||
GetMaxBattVoltage() uint16
|
||||
}
|
||||
|
||||
type ConstChargingRateInd interface {
|
||||
// GetChargingRate Constant of charging rate indication
|
||||
GetChargingRate() uint8
|
||||
}
|
||||
|
||||
type frame100 struct {
|
||||
maxBattVoltage uint16 // The maximum voltage value at the vehicle inlet terminals, at which the station stops charging to protect the vehicle battery
|
||||
chargingRateInd uint8 // Fixed value for charging rate indication, which is the maximum charging rate (100 %) of vehicle battery
|
||||
date string
|
||||
}
|
||||
|
||||
type frame101 struct {
|
||||
batteryCapacity float32 // Rated capacity of battery
|
||||
maxChargingTimeS uint16 // Maximum charging time permitted by EV, set by 10 s
|
||||
maxChargingTimeM uint8 // Maximum charging time permitted by EV, set by minute
|
||||
estChargingTimeM uint8 // Estimated remaining time before the end of charging calculated by EV
|
||||
date string
|
||||
}
|
||||
|
||||
type frame102 struct {
|
||||
controlProtocolNumber uint8 // Software version of control protocol to which EV corresponds
|
||||
targetBatteryVoltage uint16 // Target battery voltage ed charging voltage at the vehicle inlet terminals
|
||||
chargingCurrentReq uint8 // Current value requested by EV during charging
|
||||
chargingRate uint8 // Charging rate of vehicle battery
|
||||
vehicleCharging VehicleCharging // Status flag indicating charge permission status of EV
|
||||
shiftLever ShiftLever // Status flag indicating the shift lever position
|
||||
chargingSystemFault SystemFault // Status flag indicating Charging system fault a malfunction caused by EV or the station, and detected by EV
|
||||
vehicleStatus VehicleStatus // Status flag indicating the EV contactor status
|
||||
normalStopReq StopRequest // Status flag indicating the request of EV to stop charging control
|
||||
battOvervoltage SystemFault // Status flag indicating whether or not the vehicle battery voltage exceeds the maximum limit specified by EV
|
||||
battUndervoltage SystemFault // Status flag indicating whether or not the vehicle battery voltage is less than the lower limit specified by EV
|
||||
battCurrentDeviationErr SystemFault // Status flag indicating whether or not the output current deviates from EV requested current
|
||||
highBattTemperature SystemFault // Status flag indicating whether or not the temperature of vehicle battery exceeds the maximum limit
|
||||
battVoltageDeviationErr SystemFault // Status flag indicating whether or not the vehicle battery voltage deviates from the output voltage measured by the station
|
||||
date string
|
||||
}
|
||||
|
||||
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:
|
||||
event := &frame100{
|
||||
maxBattVoltage: bytesToUint16(frame.payload[4:6]),
|
||||
chargingRateInd: frame.payload[6],
|
||||
date: frame.date,
|
||||
}
|
||||
events <- event
|
||||
case CAN_ID_101:
|
||||
event := &frame101{
|
||||
batteryCapacity: 0.1 * float32(bytesToUint16(frame.payload[5:7])),
|
||||
maxChargingTimeS: 10 * uint16(frame.payload[1]),
|
||||
maxChargingTimeM: frame.payload[2],
|
||||
estChargingTimeM: frame.payload[3],
|
||||
date: frame.date,
|
||||
}
|
||||
fmt.Println(event)
|
||||
//events <- event
|
||||
case CAN_ID_102:
|
||||
event := &frame102{
|
||||
controlProtocolNumber: frame.payload[0],
|
||||
targetBatteryVoltage: bytesToUint16(frame.payload[1:3]),
|
||||
chargingCurrentReq: frame.payload[3],
|
||||
chargingRate: frame.payload[6],
|
||||
vehicleCharging: getVehicleCharging(&frame.payload),
|
||||
shiftLever: getVehicleShiftLever(&frame.payload),
|
||||
chargingSystemFault: getFault(&frame.payload, 5, 2),
|
||||
vehicleStatus: getVehicleStatus(&frame.payload),
|
||||
normalStopReq: getNormalStopReq(&frame.payload),
|
||||
battOvervoltage: getFault(&frame.payload, 4, 0),
|
||||
battUndervoltage: getFault(&frame.payload, 4, 1),
|
||||
battCurrentDeviationErr: getFault(&frame.payload, 4, 2),
|
||||
highBattTemperature: getFault(&frame.payload, 4, 3),
|
||||
battVoltageDeviationErr: getFault(&frame.payload, 4, 4),
|
||||
}
|
||||
fmt.Println(event)
|
||||
//events <- event
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return events
|
||||
}
|
||||
|
||||
func getVehicleShiftLever(bytes *[]byte) ShiftLever {
|
||||
if isBitSet((*bytes)[5], 1) {
|
||||
return OTHER
|
||||
}
|
||||
return PARKING
|
||||
}
|
||||
|
||||
func getVehicleStatus(bytes *[]byte) VehicleStatus {
|
||||
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) VehicleCharging {
|
||||
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 (f frame100) GetMaxBattVoltage() uint16 {
|
||||
return f.maxBattVoltage
|
||||
}
|
||||
|
||||
func (f frame100) GetChargingRate() uint8 {
|
||||
return f.chargingRateInd
|
||||
}
|
||||
|
||||
func (f frame100) GetValue() interface{} {
|
||||
return fmt.Sprintf("%v | MaxBattVoltage = %vV, ChargingRate = %v%%", f.date, f.maxBattVoltage, f.chargingRateInd)
|
||||
}
|
||||
|
||||
func (f frame101) GetValue() interface{} {
|
||||
return fmt.Sprintf("%v | batteryCapacity = %vkWh, maxChargingTime = %vsec, maxChargingTime = %vmin, estChargingTime = %vmin",
|
||||
f.date, f.batteryCapacity, f.maxChargingTimeS, f.maxChargingTimeM, f.estChargingTimeM)
|
||||
}
|
||||
|
||||
func (f frame102) GetValue() interface{} {
|
||||
//TODO implement me
|
||||
return ""
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
(2022-07-08 16:54:15.587099) can0 100 [8] 00 00 00 00 00 00 64 00
|
||||
(2022-07-08 16:54:15.588095) can0 101 [8] 00 FF FF 00 00 00 00 00
|
||||
(2022-07-08 16:54:15.589088) can0 102 [8] 02 00 00 00 00 08 00 00
|
||||
(2022-07-08 16:54:15.690084) can0 100 [8] 00 00 00 00 00 00 64 00
|
||||
(2022-07-08 16:54:15.691087) can0 101 [8] 00 FF FF 00 00 00 00 00
|
||||
(2022-07-08 16:54:15.692083) can0 102 [8] 02 00 00 00 00 08 00 00
|
||||
(2022-07-08 16:54:15.793083) can0 100 [8] 00 00 00 00 00 00 64 00
|
||||
(2022-07-08 16:54:15.794083) can0 101 [8] 00 FF FF 00 00 00 00 00
|
||||
(2022-07-08 16:54:15.795078) can0 102 [8] 02 00 00 00 00 08 00 00
|
||||
(2022-07-08 16:54:15.896072) can0 100 [8] 00 00 00 00 85 01 64 00
|
||||
(2022-07-08 16:54:15.897078) can0 101 [8] 00 FF FF 00 00 00 00 00
|
||||
(2022-07-08 16:54:15.898075) can0 102 [8] 02 00 00 00 00 08 00 00
|
||||
(2022-07-08 16:54:15.999065) can0 100 [8] 00 00 00 00 85 01 64 00
|
||||
(2022-07-08 16:54:16.000089) can0 101 [8] 00 FF FF 00 00 00 00 00
|
||||
(2022-07-08 16:54:16.001111) can0 102 [8] 02 00 00 00 00 08 00 00
|
||||
(2022-07-08 16:54:16.102068) can0 100 [8] 00 00 00 00 85 01 64 00
|
||||
(2022-07-08 16:54:16.103071) can0 101 [8] 00 FF FF 00 00 00 00 00
|
||||
(2022-07-08 16:54:16.104063) can0 102 [8] 02 00 00 00 00 09 00 00
|
||||
(2022-07-08 16:54:16.205070) can0 100 [8] 00 00 00 00 85 01 64 00
|
||||
(2022-07-08 16:54:16.206227) can0 101 [8] 00 FF FF 00 00 00 00 00
|
||||
(2022-07-08 16:54:16.207058) can0 102 [8] 02 00 00 00 00 09 00 00
|
||||
(2022-07-08 16:54:16.308066) can0 100 [8] 00 00 00 00 85 01 64 00
|
||||
(2022-07-08 16:54:16.309066) can0 101 [8] 00 FF FF 00 00 00 00 00
|
||||
(2022-07-08 16:54:16.310070) can0 102 [8] 02 00 00 00 00 09 00 00
|
||||
(2022-07-08 16:54:16.411044) can0 100 [8] 00 00 00 00 85 01 64 00
|
||||
(2022-07-08 16:54:16.412047) can0 101 [8] 00 FF FF 00 00 00 00 00
|
||||
(2022-07-08 16:54:16.413040) can0 102 [8] 02 00 00 00 00 09 00 00
|
||||
(2022-07-08 16:54:16.514038) can0 100 [8] 00 00 00 00 85 01 64 00
|
||||
Reference in New Issue
Block a user