forked from go-daq/canbus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
socket.go
173 lines (142 loc) · 3.4 KB
/
socket.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
// Copyright 2016 The go-daq Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// package canbus provides high-level access to CAN bus sockets.
//
// A typical usage might look like:
//
// sck, err := canbus.New()
// err = sck.Bind("vcan0")
// for {
// id, data, err := sck.Recv()
// }
//
package canbus
import (
"encoding/binary"
"errors"
"io"
"net"
"unsafe"
"golang.org/x/sys/unix"
)
var (
errDataTooBig = errors.New("canbus: data too big")
errFrame = errors.New("Error frame")
)
// New returns a new CAN bus socket.
func New() (*Socket, error) {
fd, err := unix.Socket(unix.AF_CAN, unix.SOCK_RAW, unix.CAN_RAW)
if err != nil {
return nil, err
}
return &Socket{dev: device{fd}}, nil
}
// Socket is a high-level representation of a CANBus socket.
type Socket struct {
iface *net.Interface
addr *unix.SockaddrCAN
dev device
}
// Name returns the device name the socket is bound to.
func (sck *Socket) Name() string {
if sck.iface == nil {
return "N/A"
}
return sck.iface.Name
}
// Close closes the CAN bus socket.
func (sck *Socket) Close() error {
return unix.Close(sck.dev.fd)
}
// Bind binds the socket on the CAN bus with the given address.
//
// Example:
// err = sck.Bind("vcan0")
func (sck *Socket) Bind(addr string) error {
iface, err := net.InterfaceByName(addr)
if err != nil {
return err
}
sck.iface = iface
sck.addr = &unix.SockaddrCAN{Ifindex: sck.iface.Index}
return unix.Bind(sck.dev.fd, sck.addr)
}
// Send sends data with a CAN_frame id to the CAN bus.
func (sck *Socket) Send(id uint32, data []byte) (int, error) {
if len(data) > 8 {
return 0, errDataTooBig
}
id &= unix.CAN_EFF_MASK
var frame [frameSize]byte
binary.LittleEndian.PutUint32(frame[:4], id)
frame[4] = byte(len(data))
copy(frame[8:], data)
return sck.dev.Write(frame[:])
}
type CANMessage struct {
RawData [frameSize]byte
}
func (msg *CANMessage) GetLen() int {
return int(msg.RawData[4])
}
func getId(id uint32) (uint32, error) {
if (id & unix.CAN_ERR_FLAG) != 0 {
return unix.CAN_ERR_FLAG, errFrame
} else if (id & unix.CAN_EFF_FLAG) == 0 {
id &= unix.CAN_SFF_MASK
} else {
id &= unix.CAN_EFF_MASK
}
return id, nil
}
func (msg *CANMessage) GetID() uint32 {
ID := binary.LittleEndian.Uint32(msg.RawData[:4])
return (ID & unix.CAN_SFF_MASK)
}
func (msg *CANMessage) GetData() []byte {
return msg.RawData[8:]
}
func (sck *Socket) RecvRaw(msg *CANMessage) error {
n, err := io.ReadFull(sck.dev, msg.RawData[:])
if err != nil {
return err
}
if n != int(frameSize) {
return io.ErrUnexpectedEOF
}
return nil
}
// 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 frame [frameSize]byte
n, err := io.ReadFull(sck.dev, frame[:])
if err != nil {
return id, data, err
}
if n != len(frame) {
return id, data, io.ErrUnexpectedEOF
}
id = binary.LittleEndian.Uint32(frame[:4])
data = make([]byte, frame[4])
copy(data, frame[8:])
return id, data, nil
}
type device struct {
fd int
}
func (d device) Read(data []byte) (int, error) {
return unix.Read(d.fd, data)
}
func (d device) Write(data []byte) (int, error) {
return unix.Write(d.fd, data)
}
const frameSize = unsafe.Sizeof(frame{})
// frame is a can_frame.
type frame struct {
ID uint32
Len byte
_ [3]byte
Data [8]byte
}