Skip to content

Commit 6b58fdc

Browse files
kenbelldeadprogram
authored andcommitted
tester: add a mock for command-oriented i2c devices
1 parent bd2530a commit 6b58fdc

File tree

5 files changed

+142
-2
lines changed

5 files changed

+142
-2
lines changed

tester/device.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ type I2CDevice interface {
1010
// WriteRegister implements I2C.WriteRegister.
1111
WriteRegister(r uint8, buf []byte) error
1212

13+
// Tx implements I2C.Tx
14+
Tx(w, r []byte) error
15+
1316
// Addr returns the Device address.
1417
Addr() uint8
1518
}

tester/device16.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,9 @@ func (d *I2CDevice16) WriteRegister(r uint8, buf []byte) error {
7272

7373
return nil
7474
}
75+
76+
// Tx implements I2C.Tx.
77+
func (bus *I2CDevice16) Tx(w, r []byte) error {
78+
// TODO: implement this
79+
return nil
80+
}

tester/device8.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ func (d *I2CDevice8) WriteRegister(r uint8, buf []byte) error {
5353
return nil
5454
}
5555

56+
// Tx implements I2C.Tx.
57+
func (bus *I2CDevice8) Tx(w, r []byte) error {
58+
// TODO: implement this
59+
return nil
60+
}
61+
5662
// assertRegisterRange asserts that reading or writing the given
5763
// register and subsequent registers is in range of the available registers.
5864
func (d *I2CDevice8) assertRegisterRange(r uint8, buf []byte) {

tester/devicecmd.go

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package tester
2+
3+
// Cmd represents a command sent via I2C to a device.
4+
//
5+
// A command matches when (Command & Mask) == (Data & Mask). If
6+
// a command is recognized, Response bytes is returned.
7+
type Cmd struct {
8+
Command []byte
9+
Mask []byte
10+
Response []byte
11+
Invocations int
12+
}
13+
14+
// I2CDeviceCmd represents a mock I2C device that does not
15+
// have 'registers', but has a command/response model.
16+
//
17+
// Commands and canned responses are pre-loaded into the
18+
// Commands member. For each command the mock receives it
19+
// will lookup the command and return the corresponding
20+
// canned response.
21+
type I2CDeviceCmd struct {
22+
c Failer
23+
24+
// addr is the i2c device address.
25+
addr uint8
26+
27+
// Commands are the commands the device recognizes and responds to.
28+
Commands map[uint8]*Cmd
29+
30+
// Command response that is pending (used with a command is split over)
31+
// two transactions
32+
pendingResponse []byte
33+
34+
// If Err is non-nil, it will be returned as the error from the
35+
// I2C methods.
36+
Err error
37+
}
38+
39+
// NewI2CDeviceCmd returns a new mock I2C device.
40+
func NewI2CDeviceCmd(c Failer, addr uint8) *I2CDeviceCmd {
41+
return &I2CDeviceCmd{
42+
c: c,
43+
addr: addr,
44+
}
45+
}
46+
47+
// Addr returns the Device address.
48+
func (d *I2CDeviceCmd) Addr() uint8 {
49+
return d.addr
50+
}
51+
52+
// ReadRegister implements I2C.ReadRegister.
53+
func (d *I2CDeviceCmd) ReadRegister(r uint8, buf []byte) error {
54+
if d.Err != nil {
55+
return d.Err
56+
}
57+
58+
return nil
59+
}
60+
61+
// WriteRegister implements I2C.WriteRegister.
62+
func (d *I2CDeviceCmd) WriteRegister(r uint8, buf []byte) error {
63+
if d.Err != nil {
64+
return d.Err
65+
}
66+
67+
return nil
68+
}
69+
70+
// Tx implements I2C.Tx.
71+
func (d *I2CDeviceCmd) Tx(w, r []byte) error {
72+
if d.Err != nil {
73+
return d.Err
74+
}
75+
76+
if len(w) == 0 && len(d.pendingResponse) != 0 {
77+
return d.respond(r)
78+
}
79+
80+
cmd := d.FindCommand(w)
81+
if cmd == nil {
82+
d.c.Fatalf("command [%#x] not identified", w)
83+
return nil
84+
}
85+
86+
cmd.Invocations++
87+
d.pendingResponse = cmd.Response
88+
return d.respond(r)
89+
}
90+
91+
func (d *I2CDeviceCmd) FindCommand(command []byte) *Cmd {
92+
for _, c := range d.Commands {
93+
if len(c.Command) > len(command) {
94+
continue
95+
}
96+
97+
match := true
98+
for i := 0; i < len(c.Command); i++ {
99+
mask := c.Mask[i]
100+
if (c.Command[i] & mask) != (command[i] & mask) {
101+
match = false
102+
break
103+
}
104+
}
105+
106+
if match {
107+
return c
108+
}
109+
}
110+
111+
return nil
112+
}
113+
114+
func (d *I2CDeviceCmd) respond(r []byte) error {
115+
if len(r) > len(d.pendingResponse) {
116+
d.c.Fatalf("read too large (expected: <= %#x, got: %#x)",
117+
len(d.pendingResponse), len(r))
118+
}
119+
120+
if len(r) > 0 {
121+
copy(r, d.pendingResponse[:len(r)])
122+
d.pendingResponse = nil
123+
}
124+
125+
return nil
126+
}

tester/i2c.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ func (bus *I2CBus) WriteRegister(addr uint8, r uint8, buf []byte) error {
4848

4949
// Tx implements I2C.Tx.
5050
func (bus *I2CBus) Tx(addr uint16, w, r []byte) error {
51-
// TODO: implement this
52-
return nil
51+
return bus.FindDevice(uint8(addr)).Tx(w, r)
5352
}
5453

5554
// FindDevice returns the device with the given address.

0 commit comments

Comments
 (0)