Skip to content

Commit 09470d7

Browse files
committed
Initial implemenation of i2c firmata
1 parent 12aed92 commit 09470d7

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

firmata/firmata.go

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package firmata
2+
3+
import (
4+
"fmt"
5+
"io"
6+
7+
"github.com/tarm/serial"
8+
9+
"golang.org/x/exp/io/i2c/driver"
10+
)
11+
12+
const (
13+
START_SYSEX = 0xF0
14+
I2C_CONFIG = 0x78
15+
I2C_REQUEST = 0x76
16+
I2C_REPLY = 0x77
17+
END_SYSEX = 0xF7
18+
REPORT_FIRMWARE = 0x79
19+
)
20+
21+
type Firmata struct {
22+
Conn io.ReadWriteCloser
23+
}
24+
25+
type firmataConn struct {
26+
addr int
27+
f io.ReadWriteCloser
28+
}
29+
30+
func New(address string, baud int) *Firmata {
31+
s, err := serial.OpenPort(&serial.Config{Name: address, Baud: baud})
32+
if err != nil {
33+
panic(err)
34+
}
35+
36+
for {
37+
buf := make([]byte, 1)
38+
_, err := s.Read(buf)
39+
if err != nil {
40+
fmt.Println(err)
41+
continue
42+
}
43+
break
44+
}
45+
46+
return &Firmata{Conn: s}
47+
}
48+
49+
func (f *Firmata) Open(addr int, tenbit bool) (driver.Conn, error) {
50+
fc := &firmataConn{addr: addr, f: f.Conn}
51+
fc.addr = addr
52+
53+
payload := []byte{START_SYSEX, I2C_CONFIG, 0x00, 0x00, END_SYSEX}
54+
55+
if _, err := fc.f.Write(payload); err != nil {
56+
return nil, err
57+
}
58+
59+
return fc, nil
60+
}
61+
62+
func (f *firmataConn) Tx(w, r []byte) error {
63+
if w != nil {
64+
payload := []byte{START_SYSEX, I2C_REQUEST, byte(f.addr), 0x00}
65+
66+
for _, b := range w {
67+
payload = append(payload, b&0x7F)
68+
payload = append(payload, byte(int(b>>7)&0x7F))
69+
}
70+
71+
payload = append(payload, END_SYSEX)
72+
73+
if _, err := f.f.Write(payload); err != nil {
74+
return err
75+
}
76+
}
77+
78+
if r != nil {
79+
payload := []byte{START_SYSEX, I2C_REQUEST, byte(f.addr), 0x01 << 3}
80+
81+
for _, b := range w {
82+
payload = append(payload, b&0x7F)
83+
payload = append(payload, byte(int(b>>7)&0x7F))
84+
}
85+
86+
payload = append(payload, END_SYSEX)
87+
88+
if _, err := f.f.Write(payload); err != nil {
89+
return err
90+
}
91+
92+
i2cReply := []byte{}
93+
for {
94+
buf, err := f.readByte()
95+
if err != nil {
96+
return err
97+
}
98+
99+
if buf == START_SYSEX {
100+
for {
101+
b, err := f.readByte()
102+
if err != nil {
103+
return err
104+
}
105+
106+
if b == I2C_REPLY {
107+
for {
108+
irb, err := f.readByte()
109+
if err != nil {
110+
return err
111+
}
112+
if irb == END_SYSEX {
113+
ret := parseI2cReply(i2cReply)
114+
if int(ret.address) == f.addr {
115+
copy(r, ret.data)
116+
}
117+
return nil
118+
}
119+
i2cReply = append(i2cReply, irb)
120+
}
121+
}
122+
}
123+
}
124+
}
125+
}
126+
127+
return nil
128+
}
129+
130+
type i2cReply struct {
131+
address byte
132+
register byte
133+
data []byte
134+
}
135+
136+
func parseI2cReply(b []byte) i2cReply {
137+
r := i2cReply{
138+
address: (b[0] & 0x7F) | ((b[1] & 0x7F) << 7),
139+
register: (b[2] & 0x7F) | ((b[3] & 0x7F) << 7),
140+
}
141+
142+
for i := 4; i < len(b); i += 2 {
143+
r.data = append(r.data, b[i]|b[i+1]<<7)
144+
}
145+
return r
146+
}
147+
148+
func (*firmataConn) Close() error {
149+
panic("not implemented")
150+
}
151+
152+
func (f *firmataConn) readByte() (byte, error) {
153+
buf := make([]byte, 1)
154+
_, err := f.f.Read(buf)
155+
if err != nil {
156+
return 0x00, err
157+
}
158+
159+
return buf[0], nil
160+
}

0 commit comments

Comments
 (0)