-
Notifications
You must be signed in to change notification settings - Fork 5
/
gocan.go
144 lines (124 loc) · 3.06 KB
/
gocan.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
package gocan
import (
"context"
"errors"
"sync"
"time"
)
const (
CR = 0x0D
)
type Adapter interface {
Init(context.Context) error
Name() string
Recv() <-chan CANFrame
Send() chan<- CANFrame
Close() error
SetFilter([]uint32) error
}
type AdapterConfig struct {
Debug bool
Port string
PortBaudrate int
CANRate float64
CANFilter []uint32
UseExtendedID bool
PrintVersion bool
OnMessage func(string)
OnError func(error)
}
type Opts func(*Client)
type Client struct {
fh *FrameHandler
adapter Adapter
closeOnce sync.Once
}
func New(ctx context.Context, adapter Adapter) (*Client, error) {
return NewWithOpts(ctx, adapter)
}
func NewWithOpts(ctx context.Context, adapter Adapter, opts ...Opts) (*Client, error) {
if err := adapter.Init(ctx); err != nil {
return nil, err
}
c := &Client{
fh: newFrameHandler(adapter.Recv()),
adapter: adapter,
}
for _, opt := range opts {
opt(c)
}
go c.fh.run(ctx)
return c, nil
}
func (c *Client) Adapter() Adapter {
return c.adapter
}
func (c *Client) SetFilter(filters []uint32) error {
return c.adapter.SetFilter(filters)
}
func (c *Client) Close() (err error) {
c.closeOnce.Do(func() {
c.fh.Close()
err = c.adapter.Close()
})
return err
}
// Send a CAN Frame
func (c *Client) Send(msg CANFrame) error {
select {
case c.adapter.Send() <- msg:
return nil
default:
return errors.New("gocan failed to send frame")
}
}
// Shortcommand to send a standard 11bit frame
func (c *Client) SendFrame(identifier uint32, data []byte, f CANFrameType) error {
var b = make([]byte, len(data))
copy(b, data)
frame := NewFrame(identifier, b, f)
return c.Send(frame)
}
// Send and wait up to <timeout> for a answer on given identifiers
func (c *Client) SendAndPoll(ctx context.Context, frame CANFrame, timeout time.Duration, identifiers ...uint32) (CANFrame, error) {
frame.SetTimeout(timeout)
p := c.newSub(ctx, 1, identifiers...)
c.fh.register <- p
defer func() {
c.fh.unregister <- p
}()
if err := c.Send(frame); err != nil {
return nil, err
}
return p.Wait(ctx, timeout)
}
// Poll for a certain CAN identifier for up to <timeout>
func (c *Client) Poll(ctx context.Context, timeout time.Duration, identifiers ...uint32) (CANFrame, error) {
p := c.newSub(ctx, 1, identifiers...)
c.fh.register <- p
defer func() {
c.fh.unregister <- p
}()
return p.Wait(ctx, timeout)
}
// Subscribe to CAN identifiers and return a message channel
func (c *Client) SubscribeChan(ctx context.Context, identifiers ...uint32) chan CANFrame {
p := c.newSub(ctx, 10, identifiers...)
c.fh.register <- p
return p.callback
}
// Subscribe to CAN identifiers and return a message channel
func (c *Client) Subscribe(ctx context.Context, identifiers ...uint32) *Sub {
p := c.newSub(ctx, 10, identifiers...)
c.fh.register <- p
return p
}
func (c *Client) newSub(ctx context.Context, bufferSize int, identifiers ...uint32) *Sub {
return &Sub{
ctx: ctx,
c: c,
identifiers: identifiers,
filterCount: len(identifiers),
callback: make(chan CANFrame, bufferSize),
}
}