Compare commits
2 Commits
master
...
feature/ev
Author | SHA1 | Date |
---|---|---|
![]() |
349050edb4 | 3 years ago |
![]() |
1a47ad1c7f | 3 years ago |
@ -1,133 +1,48 @@ |
|||||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
|
||||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
|
||||||
|
|
||||||
package main |
package main |
||||||
|
|
||||||
import ( |
import ( |
||||||
"encoding/binary" |
"fmt" |
||||||
"errors" |
"regexp" |
||||||
"io" |
"strconv" |
||||||
"net" |
|
||||||
"time" |
|
||||||
"unsafe" |
|
||||||
|
|
||||||
"golang.org/x/sys/unix" |
|
||||||
) |
) |
||||||
|
|
||||||
// NewCan New returns a new CAN bus socket.
|
type CanFrame struct { |
||||||
func NewCan() (*Socket, error) { |
canid uint16 |
||||||
fd, err := unix.Socket(unix.AF_CAN, unix.SOCK_RAW, unix.CAN_RAW) |
payload []uint8 |
||||||
if err != nil { |
date string |
||||||
return nil, err |
|
||||||
} |
} |
||||||
|
|
||||||
return &Socket{dev: device{fd}}, nil |
// (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 |
||||||
|
|
||||||
// Socket is a high-level representation of a CANBus socket.
|
var pattern = regexp.MustCompile(expr) |
||||||
type Socket struct { |
|
||||||
iface *net.Interface |
|
||||||
addr *unix.SockaddrCAN |
|
||||||
dev device |
|
||||||
} |
|
||||||
|
|
||||||
// Close closes the CAN bus socket.
|
func FromString(text *string) *CanFrame { |
||||||
func (sck *Socket) Close() error { |
submatch := pattern.FindStringSubmatch(*text) |
||||||
return unix.Close(sck.dev.fd) |
if len(submatch) == length { |
||||||
} |
canid, err := strconv.ParseUint(submatch[2], 16, 0) |
||||||
|
|
||||||
func (sck *Socket) Bind(addr string, filter []unix.CanFilter) error { |
|
||||||
iface, err := net.InterfaceByName(addr) |
|
||||||
if err != nil { |
if err != nil { |
||||||
return err |
return nil |
||||||
} |
} |
||||||
|
|
||||||
sck.iface = iface |
payload := make([]uint8, 8) |
||||||
sck.addr = &unix.SockaddrCAN{Ifindex: sck.iface.Index} |
for idx, octet := range submatch[3:] { |
||||||
|
val, err := strconv.ParseUint(octet, 16, 0) |
||||||
//add filter
|
|
||||||
if filter != nil { |
|
||||||
unix.SetsockoptCanRawFilter(sck.dev.fd, unix.SOL_CAN_RAW, unix.CAN_RAW_FILTER, filter) |
|
||||||
} |
|
||||||
|
|
||||||
return unix.Bind(sck.dev.fd, sck.addr) |
|
||||||
} |
|
||||||
|
|
||||||
// Recv receives data from the CAN socket.
|
|
||||||
// id is the CAN_frame id the data was originated from.
|
|
||||||
func (sck *Socket) Recv() (id uint32, data []byte, err error) { |
|
||||||
var buf [frameSize]byte |
|
||||||
n, err := io.ReadFull(sck.dev, buf[:]) |
|
||||||
if err != nil { |
if err != nil { |
||||||
return id, data, err |
fmt.Println(err) |
||||||
} |
continue |
||||||
|
|
||||||
if n != len(buf) { |
|
||||||
return id, data, io.ErrUnexpectedEOF |
|
||||||
} |
|
||||||
|
|
||||||
id = binary.LittleEndian.Uint32(buf[:4]) |
|
||||||
id &= unix.CAN_SFF_MASK |
|
||||||
data = make([]byte, buf[4]) |
|
||||||
copy(data, buf[8:]) |
|
||||||
return id, data, nil |
|
||||||
} |
} |
||||||
|
|
||||||
type device struct { |
payload[idx] = uint8(val) |
||||||
fd int |
|
||||||
} |
} |
||||||
|
|
||||||
func (d device) Read(data []byte) (int, error) { |
return &CanFrame{ |
||||||
return unix.Read(d.fd, data) |
date: submatch[1], |
||||||
|
canid: uint16(canid), |
||||||
|
payload: payload, |
||||||
} |
} |
||||||
|
|
||||||
func (d device) Write(data []byte) (int, error) { |
|
||||||
return unix.Write(d.fd, data) |
|
||||||
} |
} |
||||||
|
|
||||||
const frameSize = unsafe.Sizeof(canframe{}) |
return nil |
||||||
|
|
||||||
// frame is a can_frame.
|
|
||||||
type canframe struct { |
|
||||||
ID uint32 |
|
||||||
Len byte |
|
||||||
_ [3]byte |
|
||||||
Data [8]byte |
|
||||||
} |
|
||||||
|
|
||||||
func StartCan(canbus string) (<-chan *CanFrame, error) { |
|
||||||
|
|
||||||
var filter []unix.CanFilter = []unix.CanFilter{ |
|
||||||
{Id: CAN_ID_100, Mask: 0xFFF}, |
|
||||||
{Id: CAN_ID_101, Mask: 0xFFF}, |
|
||||||
{Id: CAN_ID_102, Mask: 0xFFF}, |
|
||||||
{Id: CAN_ID_108, Mask: 0xFFF}, |
|
||||||
{Id: CAN_ID_109, Mask: 0xFFF}, |
|
||||||
} |
|
||||||
|
|
||||||
if socket, err := NewCan(); err == nil { |
|
||||||
|
|
||||||
if cerr := socket.Bind(canbus, filter); cerr == nil { |
|
||||||
|
|
||||||
canevents := make(chan *CanFrame) |
|
||||||
|
|
||||||
go func() { |
|
||||||
defer close(canevents) |
|
||||||
defer socket.Close() |
|
||||||
|
|
||||||
for { //TODO implement stop
|
|
||||||
if id, data, serr := socket.Recv(); serr == nil { |
|
||||||
canevents <- &CanFrame{ |
|
||||||
date: time.Now().String(), |
|
||||||
canid: id, |
|
||||||
payload: data, |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
}() |
|
||||||
|
|
||||||
return canevents, nil |
|
||||||
} |
|
||||||
} |
|
||||||
return nil, errors.New("can't bind can socket") |
|
||||||
} |
} |
||||||
|
@ -1,15 +0,0 @@ |
|||||||
//go:build windows
|
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package main |
|
||||||
|
|
||||||
func StartCan(canbus string) (<-chan *CanFrame, error) { |
|
||||||
return nil, &NotImplError{} |
|
||||||
} |
|
||||||
|
|
||||||
type NotImplError struct { |
|
||||||
} |
|
||||||
|
|
||||||
func (e *NotImplError) Error() string { |
|
||||||
return "Not implemented for windows platform" |
|
||||||
} |
|
@ -1,71 +0,0 @@ |
|||||||
package main |
|
||||||
|
|
||||||
import ( |
|
||||||
"bufio" |
|
||||||
"fmt" |
|
||||||
"os" |
|
||||||
"regexp" |
|
||||||
"strconv" |
|
||||||
) |
|
||||||
|
|
||||||
// (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 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 |
|
||||||
} |
|
||||||
|
|
||||||
func fromString(text *string) *CanFrame { |
|
||||||
submatch := pattern.FindStringSubmatch(*text) |
|
||||||
if len(submatch) == length { |
|
||||||
canid, err := strconv.ParseUint(submatch[2], 16, 0) |
|
||||||
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: uint32(canid), |
|
||||||
payload: payload, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return nil |
|
||||||
} |
|
@ -1,175 +0,0 @@ |
|||||||
package main |
|
||||||
|
|
||||||
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 CanFrame struct { |
|
||||||
canid uint32 |
|
||||||
payload []uint8 |
|
||||||
date string |
|
||||||
} |
|
||||||
|
|
||||||
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") |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue