forked from tinygo-org/drivers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
devicecmd.go
126 lines (103 loc) · 2.54 KB
/
devicecmd.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
package tester
// Cmd represents a command sent via I2C to a device.
//
// A command matches when (Command & Mask) == (Data & Mask). If
// a command is recognized, Response bytes is returned.
type Cmd struct {
Command []byte
Mask []byte
Response []byte
Invocations int
}
// I2CDeviceCmd represents a mock I2C device that does not
// have 'registers', but has a command/response model.
//
// Commands and canned responses are pre-loaded into the
// Commands member. For each command the mock receives it
// will lookup the command and return the corresponding
// canned response.
type I2CDeviceCmd struct {
c Failer
// addr is the i2c device address.
addr uint8
// Commands are the commands the device recognizes and responds to.
Commands map[uint8]*Cmd
// Command response that is pending (used with a command is split over)
// two transactions
pendingResponse []byte
// If Err is non-nil, it will be returned as the error from the
// I2C methods.
Err error
}
// NewI2CDeviceCmd returns a new mock I2C device.
func NewI2CDeviceCmd(c Failer, addr uint8) *I2CDeviceCmd {
return &I2CDeviceCmd{
c: c,
addr: addr,
}
}
// Addr returns the Device address.
func (d *I2CDeviceCmd) Addr() uint8 {
return d.addr
}
// ReadRegister implements I2C.ReadRegister.
func (d *I2CDeviceCmd) ReadRegister(r uint8, buf []byte) error {
if d.Err != nil {
return d.Err
}
return nil
}
// WriteRegister implements I2C.WriteRegister.
func (d *I2CDeviceCmd) WriteRegister(r uint8, buf []byte) error {
if d.Err != nil {
return d.Err
}
return nil
}
// Tx implements I2C.Tx.
func (d *I2CDeviceCmd) Tx(w, r []byte) error {
if d.Err != nil {
return d.Err
}
if len(w) == 0 && len(d.pendingResponse) != 0 {
return d.respond(r)
}
cmd := d.FindCommand(w)
if cmd == nil {
d.c.Fatalf("command [%#x] not identified", w)
return nil
}
cmd.Invocations++
d.pendingResponse = cmd.Response
return d.respond(r)
}
func (d *I2CDeviceCmd) FindCommand(command []byte) *Cmd {
for _, c := range d.Commands {
if len(c.Command) > len(command) {
continue
}
match := true
for i := 0; i < len(c.Command); i++ {
mask := c.Mask[i]
if (c.Command[i] & mask) != (command[i] & mask) {
match = false
break
}
}
if match {
return c
}
}
return nil
}
func (d *I2CDeviceCmd) respond(r []byte) error {
if len(r) > len(d.pendingResponse) {
d.c.Fatalf("read too large (expected: <= %#x, got: %#x)",
len(d.pendingResponse), len(r))
}
if len(r) > 0 {
copy(r, d.pendingResponse[:len(r)])
d.pendingResponse = nil
}
return nil
}