forked from go-daq/canbus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
socket.go
132 lines (109 loc) · 2.64 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
// 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")
)
// 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_SFF_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[:])
}
// 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])
id &= unix.CAN_SFF_MASK
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
}