forked from hybridgroup/gobot
/
grovepi_driver.go
255 lines (199 loc) · 5.62 KB
/
grovepi_driver.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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
package i2c
import (
"strconv"
"strings"
"sync"
"time"
"gobot.io/x/gobot"
)
const grovePiAddress = 0x04
// Commands format
const (
CommandReadDigital = 1
CommandWriteDigital = 2
CommandReadAnalog = 3
CommandWriteAnalog = 4
CommandPinMode = 5
CommandReadDHT = 40
)
// GrovePiDriver is a driver for the GrovePi+ for I²C bus interface.
// https://www.dexterindustries.com/grovepi/
//
// To use this driver with the GrovePi, it must be running the 1.3.0+ firmware.
// https://forum.dexterindustries.com/t/pre-release-of-grovepis-firmware-v1-3-0-open-to-testers/5119
//
type GrovePiDriver struct {
name string
digitalPins map[int]string
analogPins map[int]string
mutex *sync.Mutex
connector Connector
connection Connection
Config
}
// NewGrovePiDriver creates a new driver with specified i2c interface
// Params:
// conn Connector - the Adaptor to use with this Driver
//
// Optional params:
// i2c.WithBus(int): bus to use with this driver
// i2c.WithAddress(int): address to use with this driver
//
func NewGrovePiDriver(a Connector, options ...func(Config)) *GrovePiDriver {
d := &GrovePiDriver{
name: gobot.DefaultName("GrovePi"),
digitalPins: make(map[int]string),
analogPins: make(map[int]string),
mutex: &sync.Mutex{},
connector: a,
Config: NewConfig(),
}
for _, option := range options {
option(d)
}
// TODO: add commands for API
return d
}
// Name returns the Name for the Driver
func (d *GrovePiDriver) Name() string { return d.name }
// SetName sets the Name for the Driver
func (d *GrovePiDriver) SetName(n string) { d.name = n }
// Connection returns the connection for the Driver
func (d *GrovePiDriver) Connection() gobot.Connection { return d.connector.(gobot.Connection) }
// Start initialized the GrovePi
func (d *GrovePiDriver) Start() (err error) {
bus := d.GetBusOrDefault(d.connector.GetDefaultBus())
address := d.GetAddressOrDefault(grovePiAddress)
d.connection, err = d.connector.GetConnection(address, bus)
if err != nil {
return err
}
return
}
// Halt returns true if devices is halted successfully
func (d *GrovePiDriver) Halt() (err error) { return }
// Connect is here to implement the Adaptor interface.
func (d *GrovePiDriver) Connect() (err error) {
return
}
// Finalize is here to implement the Adaptor interface.
func (d *GrovePiDriver) Finalize() (err error) {
return
}
// AnalogRead returns value from analog pin implementing the AnalogReader interface.
func (d *GrovePiDriver) AnalogRead(pin string) (value int, err error) {
pin = getPin(pin)
var pinNum int
pinNum, err = strconv.Atoi(pin)
if err != nil {
return
}
value, err = d.readAnalog(byte(pinNum))
return
}
// DigitalRead performs a read on a digital pin.
func (d *GrovePiDriver) DigitalRead(pin string) (val int, err error) {
pin = getPin(pin)
var pinNum int
pinNum, err = strconv.Atoi(pin)
if err != nil {
return
}
if dir, ok := d.digitalPins[pinNum]; !ok || dir != "input" {
d.PinMode(byte(pinNum), "input")
d.digitalPins[pinNum] = "input"
}
val, err = d.readDigital(byte(pinNum))
return
}
// DigitalWrite writes a value to a specific digital pin implementing the DigitalWriter interface.
func (d *GrovePiDriver) DigitalWrite(pin string, val byte) (err error) {
pin = getPin(pin)
var pinNum int
pinNum, err = strconv.Atoi(pin)
if err != nil {
return
}
if dir, ok := d.digitalPins[pinNum]; !ok || dir != "output" {
d.PinMode(byte(pinNum), "output")
d.digitalPins[pinNum] = "output"
}
err = d.writeDigital(byte(pinNum), val)
return
}
// WriteAnalog writes PWM aka analog to the GrovePi. Not yet working.
func (d *GrovePiDriver) WriteAnalog(pin byte, val byte) error {
buf := []byte{CommandWriteAnalog, pin, val, 0}
_, err := d.connection.Write(buf)
time.Sleep(2 * time.Millisecond)
data := make([]byte, 1)
_, err = d.connection.Read(data)
return err
}
// PinMode sets the pin mode to input or output.
func (d *GrovePiDriver) PinMode(pin byte, mode string) error {
var b []byte
if mode == "output" {
b = []byte{CommandPinMode, pin, 1, 0}
} else {
b = []byte{CommandPinMode, pin, 0, 0}
}
_, err := d.connection.Write(b)
time.Sleep(2 * time.Millisecond)
_, err = d.connection.ReadByte()
return err
}
func getPin(pin string) string {
if len(pin) > 1 {
if strings.ToUpper(pin[0:1]) == "A" || strings.ToUpper(pin[0:1]) == "D" {
return pin[1:len(pin)]
}
}
return pin
}
// readAnalog reads analog value from the GrovePi.
func (d *GrovePiDriver) readAnalog(pin byte) (int, error) {
d.mutex.Lock()
defer d.mutex.Unlock()
b := []byte{CommandReadAnalog, pin, 0, 0}
_, err := d.connection.Write(b)
if err != nil {
return 0, err
}
time.Sleep(2 * time.Millisecond)
data := make([]byte, 3)
_, err = d.connection.Read(data)
if err != nil || data[0] != CommandReadAnalog {
return -1, err
}
v1 := int(data[1])
v2 := int(data[2])
return ((v1 * 256) + v2), nil
}
// readDigital reads digitally from the GrovePi.
func (d *GrovePiDriver) readDigital(pin byte) (val int, err error) {
d.mutex.Lock()
defer d.mutex.Unlock()
buf := []byte{CommandReadDigital, pin, 0, 0}
_, err = d.connection.Write(buf)
if err != nil {
return
}
time.Sleep(2 * time.Millisecond)
data := make([]byte, 2)
_, err = d.connection.Read(data)
if err != nil || data[0] != CommandReadDigital {
return 0, err
}
return int(data[1]), err
}
// writeDigital writes digitally to the GrovePi.
func (d *GrovePiDriver) writeDigital(pin byte, val byte) error {
d.mutex.Lock()
defer d.mutex.Unlock()
buf := []byte{CommandWriteDigital, pin, val, 0}
_, err := d.connection.Write(buf)
time.Sleep(2 * time.Millisecond)
_, err = d.connection.ReadByte()
return err
}