-
Notifications
You must be signed in to change notification settings - Fork 14
/
socket.go
151 lines (126 loc) · 3.16 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
// 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
import (
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"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
}
// SetFilters sets the CAN_RAW_FILTER option and applies the provided
// filters to the underlying socket.
func (sck *Socket) SetFilters(filters []unix.CanFilter) error {
err := unix.SetsockoptCanRawFilter(sck.dev.fd, unix.SOL_CAN_RAW, unix.CAN_RAW_FILTER, filters)
if err != nil {
return fmt.Errorf("could not set CAN filters: %w", err)
}
return nil
}
// 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 the provided frame on the CAN bus.
func (sck *Socket) Send(msg Frame) (int, error) {
if len(msg.Data) > 8 {
return 0, errDataTooBig
}
switch msg.Kind {
case SFF:
msg.ID &= unix.CAN_SFF_MASK
case EFF:
msg.ID &= unix.CAN_EFF_MASK
msg.ID |= unix.CAN_EFF_FLAG
case RTR:
msg.ID &= unix.CAN_EFF_MASK
msg.ID |= unix.CAN_RTR_FLAG
case ERR:
msg.ID &= unix.CAN_ERR_MASK
msg.ID |= unix.CAN_ERR_FLAG
}
var frame [frameSize]byte
binary.LittleEndian.PutUint32(frame[:4], msg.ID)
frame[4] = byte(len(msg.Data))
copy(frame[8:], msg.Data)
return sck.dev.Write(frame[:])
}
// Recv receives data from the CAN socket.
func (sck *Socket) Recv() (msg Frame, err error) {
var frame [frameSize]byte
n, err := io.ReadFull(sck.dev, frame[:])
if err != nil {
return msg, err
}
if n != len(frame) {
return msg, io.ErrUnexpectedEOF
}
msg.ID = binary.LittleEndian.Uint32(frame[:4])
switch {
case msg.ID&unix.CAN_EFF_FLAG != 0:
msg.Kind = EFF
msg.ID &= unix.CAN_EFF_MASK
case msg.ID&unix.CAN_ERR_FLAG != 0:
msg.Kind = ERR
msg.ID &= unix.CAN_ERR_MASK
case msg.ID&unix.CAN_RTR_FLAG != 0:
msg.Kind = RTR
// FIXME(sbinet): are we sure using the EFF mask makes sense ?
msg.ID &= unix.CAN_EFF_MASK
default:
msg.Kind = SFF
msg.ID &= unix.CAN_SFF_MASK
}
msg.Data = make([]byte, frame[4])
copy(msg.Data, frame[8:])
return msg, 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)
}