2014-04-27 19:56:18 -07:00
|
|
|
package firmata
|
2014-04-26 03:11:51 -07:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2014-11-19 11:18:48 -08:00
|
|
|
"errors"
|
2014-04-26 03:11:51 -07:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"math"
|
|
|
|
"time"
|
2014-07-13 13:54:41 -07:00
|
|
|
|
|
|
|
"github.com/hybridgroup/gobot"
|
2014-04-26 03:11:51 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2014-07-13 13:54:41 -07:00
|
|
|
open byte = 1
|
|
|
|
close byte = 0
|
|
|
|
input byte = 0x00
|
|
|
|
output byte = 0x01
|
|
|
|
analog byte = 0x02
|
|
|
|
pwm byte = 0x03
|
|
|
|
servo byte = 0x04
|
|
|
|
low byte = 0
|
|
|
|
high byte = 1
|
|
|
|
reportVersion byte = 0xF9
|
|
|
|
systemReset byte = 0xFF
|
|
|
|
digitalMessage byte = 0x90
|
|
|
|
digitalMessageRangeStart byte = 0x90
|
|
|
|
digitalMessageRangeEnd byte = 0x9F
|
|
|
|
analogMessage byte = 0xE0
|
|
|
|
analogMessageRangeStart byte = 0xE0
|
|
|
|
analogMessageRangeEnd byte = 0xEF
|
|
|
|
reportAnalog byte = 0xC0
|
|
|
|
reportDigital byte = 0xD0
|
|
|
|
pinMode byte = 0xF4
|
|
|
|
startSysex byte = 0xF0
|
|
|
|
endSysex byte = 0xF7
|
|
|
|
capabilityQuery byte = 0x6B
|
|
|
|
capabilityResponse byte = 0x6C
|
|
|
|
pinStateQuery byte = 0x6D
|
|
|
|
pinStateResponse byte = 0x6E
|
|
|
|
analogMappingQuery byte = 0x69
|
|
|
|
analogMappingResponse byte = 0x6A
|
|
|
|
stringData byte = 0x71
|
|
|
|
i2CRequest byte = 0x76
|
|
|
|
i2CReply byte = 0x77
|
|
|
|
i2CConfig byte = 0x78
|
|
|
|
firmwareQuery byte = 0x79
|
|
|
|
i2CModeWrite byte = 0x00
|
|
|
|
i2CModeRead byte = 0x01
|
|
|
|
i2CmodeContinuousRead byte = 0x02
|
|
|
|
i2CModeStopReading byte = 0x03
|
2014-04-26 03:11:51 -07:00
|
|
|
)
|
|
|
|
|
2014-12-19 12:58:55 -08:00
|
|
|
var defaultInitTimeInterval time.Duration = 1 * time.Second
|
|
|
|
|
2014-04-26 03:11:51 -07:00
|
|
|
type board struct {
|
2014-07-14 14:10:04 -07:00
|
|
|
serial io.ReadWriteCloser
|
|
|
|
pins []pin
|
|
|
|
analogPins []byte
|
|
|
|
firmwareName string
|
|
|
|
majorVersion byte
|
|
|
|
minorVersion byte
|
|
|
|
connected bool
|
|
|
|
events map[string]*gobot.Event
|
|
|
|
initTimeInterval time.Duration
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
type pin struct {
|
2014-07-13 13:54:41 -07:00
|
|
|
supportedModes []byte
|
|
|
|
mode byte
|
|
|
|
value int
|
|
|
|
analogChannel byte
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// newBoard creates a new board connected in specified serial port.
|
|
|
|
// Adds following events: "firmware_query", "capability_query",
|
|
|
|
// "analog_mapping_query", "report_version", "i2c_reply",
|
|
|
|
// "string_data", "firmware_query"
|
2014-04-26 03:11:51 -07:00
|
|
|
func newBoard(sp io.ReadWriteCloser) *board {
|
2014-07-13 13:54:41 -07:00
|
|
|
board := &board{
|
2014-07-14 14:10:04 -07:00
|
|
|
majorVersion: 0,
|
|
|
|
minorVersion: 0,
|
|
|
|
serial: sp,
|
|
|
|
firmwareName: "",
|
|
|
|
pins: []pin{},
|
|
|
|
analogPins: []byte{},
|
|
|
|
connected: false,
|
|
|
|
events: make(map[string]*gobot.Event),
|
2014-12-19 12:58:55 -08:00
|
|
|
initTimeInterval: defaultInitTimeInterval,
|
2014-07-13 13:54:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, s := range []string{
|
|
|
|
"firmware_query",
|
|
|
|
"capability_query",
|
|
|
|
"analog_mapping_query",
|
|
|
|
"report_version",
|
|
|
|
"i2c_reply",
|
|
|
|
"string_data",
|
|
|
|
"firmware_query",
|
|
|
|
} {
|
|
|
|
board.events[s] = gobot.NewEvent()
|
|
|
|
}
|
|
|
|
|
2014-04-26 03:11:51 -07:00
|
|
|
return board
|
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// connect starts connection to board.
|
|
|
|
// Queries report version until connected
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) connect() (err error) {
|
2014-07-13 13:54:41 -07:00
|
|
|
if b.connected == false {
|
2014-11-19 11:18:48 -08:00
|
|
|
if err = b.reset(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-04-26 03:11:51 -07:00
|
|
|
b.initBoard()
|
2014-07-13 13:54:41 -07:00
|
|
|
for {
|
2014-11-19 11:18:48 -08:00
|
|
|
if err = b.queryReportVersion(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-07-14 14:10:04 -07:00
|
|
|
<-time.After(b.initTimeInterval)
|
2014-11-19 11:18:48 -08:00
|
|
|
if err = b.readAndProcess(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-07-13 13:54:41 -07:00
|
|
|
if b.connected == true {
|
|
|
|
break
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
2014-07-13 13:54:41 -07:00
|
|
|
}
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
2014-11-19 11:18:48 -08:00
|
|
|
return
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// initBoard initializes board by listening for "firware_query", "capability_query"
|
|
|
|
// and "analog_mapping_query" events
|
2014-04-26 03:11:51 -07:00
|
|
|
func (b *board) initBoard() {
|
2014-07-13 20:27:38 -07:00
|
|
|
gobot.Once(b.events["firmware_query"], func(data interface{}) {
|
2014-04-26 03:11:51 -07:00
|
|
|
b.queryCapabilities()
|
2014-07-13 13:54:41 -07:00
|
|
|
})
|
2014-04-26 03:11:51 -07:00
|
|
|
|
2014-07-13 20:27:38 -07:00
|
|
|
gobot.Once(b.events["capability_query"], func(data interface{}) {
|
2014-07-13 13:54:41 -07:00
|
|
|
b.queryAnalogMapping()
|
|
|
|
})
|
|
|
|
|
2014-07-13 20:27:38 -07:00
|
|
|
gobot.Once(b.events["analog_mapping_query"], func(data interface{}) {
|
2014-07-13 13:54:41 -07:00
|
|
|
b.togglePinReporting(0, high, reportDigital)
|
|
|
|
b.togglePinReporting(1, high, reportDigital)
|
|
|
|
b.connected = true
|
|
|
|
})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// readAndProcess reads from serial port and parses data.
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) readAndProcess() error {
|
|
|
|
buf, err := b.read()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return b.process(buf)
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// reset writes system reset bytes.
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) reset() error {
|
|
|
|
return b.write([]byte{systemReset})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// setPinMode writes pin mode bytes for specified pin.
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) setPinMode(pin byte, mode byte) error {
|
2014-07-13 13:54:41 -07:00
|
|
|
b.pins[pin].mode = mode
|
2014-11-19 11:18:48 -08:00
|
|
|
return b.write([]byte{pinMode, pin, mode})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// digitalWrite is used to send a digital value to a specified pin.
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) digitalWrite(pin byte, value byte) error {
|
2014-04-26 03:11:51 -07:00
|
|
|
port := byte(math.Floor(float64(pin) / 8))
|
|
|
|
portValue := byte(0)
|
|
|
|
|
2014-07-13 13:54:41 -07:00
|
|
|
b.pins[pin].value = int(value)
|
2014-04-26 03:11:51 -07:00
|
|
|
|
|
|
|
for i := byte(0); i < 8; i++ {
|
2014-07-13 13:54:41 -07:00
|
|
|
if b.pins[8*port+i].value != 0 {
|
2014-04-26 03:11:51 -07:00
|
|
|
portValue = portValue | (1 << i)
|
|
|
|
}
|
|
|
|
}
|
2014-11-19 11:18:48 -08:00
|
|
|
return b.write([]byte{digitalMessage | port, portValue & 0x7F, (portValue >> 7) & 0x7F})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// analogWrite writes value to specified pin
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) analogWrite(pin byte, value byte) error {
|
2014-07-13 13:54:41 -07:00
|
|
|
b.pins[pin].value = int(value)
|
2014-11-19 11:18:48 -08:00
|
|
|
return b.write([]byte{analogMessage | pin, value & 0x7F, (value >> 7) & 0x7F})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// version returns board version following MAYOR.minor convention.
|
2014-04-26 03:11:51 -07:00
|
|
|
func (b *board) version() string {
|
2014-07-13 13:54:41 -07:00
|
|
|
return fmt.Sprintf("%v.%v", b.majorVersion, b.minorVersion)
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// queryFirmware writes bytes to query firmware from board.
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) queryFirmware() error {
|
|
|
|
return b.write([]byte{startSysex, firmwareQuery, endSysex})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// queryPinState writes bytes to retrieve pin state
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) queryPinState(pin byte) error {
|
|
|
|
return b.write([]byte{startSysex, pinStateQuery, pin, endSysex})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// queryReportVersion sends query for report version
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) queryReportVersion() error {
|
|
|
|
return b.write([]byte{reportVersion})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// queryCapabilities is used to retrieve board capabilities.
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) queryCapabilities() error {
|
|
|
|
return b.write([]byte{startSysex, capabilityQuery, endSysex})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// queryAnalogMapping returns analog mapping for board.
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) queryAnalogMapping() error {
|
|
|
|
return b.write([]byte{startSysex, analogMappingQuery, endSysex})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// togglePinReporting is used to change pin reporting mode.
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) togglePinReporting(pin byte, state byte, mode byte) error {
|
|
|
|
return b.write([]byte{mode | pin, state})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// i2cReadRequest reads from slaveAddress.
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) i2cReadRequest(slaveAddress byte, numBytes uint) error {
|
|
|
|
return b.write([]byte{startSysex, i2CRequest, slaveAddress, (i2CModeRead << 3),
|
2014-07-13 13:54:41 -07:00
|
|
|
byte(numBytes & 0x7F), byte(((numBytes >> 7) & 0x7F)), endSysex})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// i2cWriteRequest writes to slaveAddress.
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) i2cWriteRequest(slaveAddress byte, data []byte) error {
|
2014-07-13 13:54:41 -07:00
|
|
|
ret := []byte{startSysex, i2CRequest, slaveAddress, (i2CModeWrite << 3)}
|
2014-04-26 03:11:51 -07:00
|
|
|
for _, val := range data {
|
|
|
|
ret = append(ret, byte(val&0x7F))
|
|
|
|
ret = append(ret, byte((val>>7)&0x7F))
|
|
|
|
}
|
2014-07-13 13:54:41 -07:00
|
|
|
ret = append(ret, endSysex)
|
2014-11-19 11:18:48 -08:00
|
|
|
return b.write(ret)
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// i2xConfig returns i2c configuration.
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) i2cConfig(data []byte) error {
|
2014-07-13 13:54:41 -07:00
|
|
|
ret := []byte{startSysex, i2CConfig}
|
2014-04-26 03:11:51 -07:00
|
|
|
for _, val := range data {
|
|
|
|
ret = append(ret, byte(val&0xFF))
|
|
|
|
ret = append(ret, byte((val>>8)&0xFF))
|
|
|
|
}
|
2014-07-13 13:54:41 -07:00
|
|
|
ret = append(ret, endSysex)
|
2014-11-19 11:18:48 -08:00
|
|
|
return b.write(ret)
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// write is used to send commands to serial port
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) write(commands []byte) (err error) {
|
|
|
|
_, err = b.serial.Write(commands[:])
|
|
|
|
return
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// read returns buffer reading from serial port (1024 bytes)
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) read() (buf []byte, err error) {
|
|
|
|
buf = make([]byte, 1024)
|
|
|
|
_, err = b.serial.Read(buf)
|
|
|
|
return
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-10-17 12:42:07 -05:00
|
|
|
// process uses incoming data and executes actions depending on what is received.
|
|
|
|
// The following messages are processed: reportVersion, AnalogMessageRangeStart,
|
|
|
|
// digitalMessageRangeStart.
|
|
|
|
// And the following responses: capability, analog mapping, pin state,
|
|
|
|
// i2c, firmwareQuery, string data.
|
|
|
|
// If neither of those messages is received, then data is treated as "bad_byte"
|
2014-11-19 11:18:48 -08:00
|
|
|
func (b *board) process(data []byte) (err error) {
|
2014-04-26 03:11:51 -07:00
|
|
|
buf := bytes.NewBuffer(data)
|
|
|
|
for {
|
2014-06-10 15:16:11 -07:00
|
|
|
messageType, err := buf.ReadByte()
|
2014-04-26 03:11:51 -07:00
|
|
|
if err != nil {
|
2014-11-19 11:18:48 -08:00
|
|
|
// we ran out of bytes so we break out of the process loop
|
2014-04-26 03:11:51 -07:00
|
|
|
break
|
|
|
|
}
|
2014-06-28 17:03:55 -07:00
|
|
|
switch {
|
2014-07-13 13:54:41 -07:00
|
|
|
case reportVersion == messageType:
|
2014-11-19 11:18:48 -08:00
|
|
|
if b.majorVersion, err = buf.ReadByte(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if b.minorVersion, err = buf.ReadByte(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-07-13 13:54:41 -07:00
|
|
|
gobot.Publish(b.events["report_version"], b.version())
|
2014-07-16 11:49:06 -07:00
|
|
|
case analogMessageRangeStart <= messageType &&
|
|
|
|
analogMessageRangeEnd >= messageType:
|
|
|
|
|
2014-11-19 11:18:48 -08:00
|
|
|
leastSignificantByte, err := buf.ReadByte()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
mostSignificantByte, err := buf.ReadByte()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-06-10 15:16:11 -07:00
|
|
|
|
|
|
|
value := uint(leastSignificantByte) | uint(mostSignificantByte)<<7
|
|
|
|
pin := (messageType & 0x0F)
|
|
|
|
|
2014-07-13 13:54:41 -07:00
|
|
|
b.pins[b.analogPins[pin]].value = int(value)
|
|
|
|
gobot.Publish(b.events[fmt.Sprintf("analog_read_%v", pin)],
|
|
|
|
[]byte{
|
|
|
|
byte(value >> 24),
|
|
|
|
byte(value >> 16),
|
|
|
|
byte(value >> 8),
|
|
|
|
byte(value & 0xff),
|
2014-07-10 13:42:18 -07:00
|
|
|
},
|
|
|
|
)
|
2014-07-16 11:49:06 -07:00
|
|
|
case digitalMessageRangeStart <= messageType &&
|
|
|
|
digitalMessageRangeEnd >= messageType:
|
|
|
|
|
2014-06-10 15:16:11 -07:00
|
|
|
port := messageType & 0x0F
|
2014-11-19 11:18:48 -08:00
|
|
|
firstBitmask, err := buf.ReadByte()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
secondBitmask, err := buf.ReadByte()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-06-10 15:16:11 -07:00
|
|
|
portValue := firstBitmask | (secondBitmask << 7)
|
2014-04-26 03:11:51 -07:00
|
|
|
|
|
|
|
for i := 0; i < 8; i++ {
|
2014-06-10 15:16:11 -07:00
|
|
|
pinNumber := (8*byte(port) + byte(i))
|
2014-07-13 13:54:41 -07:00
|
|
|
pin := b.pins[pinNumber]
|
|
|
|
if byte(pin.mode) == input {
|
|
|
|
pin.value = int((portValue >> (byte(i) & 0x07)) & 0x01)
|
2014-07-13 20:27:38 -07:00
|
|
|
gobot.Publish(b.events[fmt.Sprintf("digital_read_%v", pinNumber)],
|
2014-07-13 13:54:41 -07:00
|
|
|
[]byte{byte(pin.value & 0xff)})
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
}
|
2014-07-13 13:54:41 -07:00
|
|
|
case startSysex == messageType:
|
2014-06-10 15:16:11 -07:00
|
|
|
currentBuffer := []byte{messageType}
|
2014-04-26 03:11:51 -07:00
|
|
|
for {
|
|
|
|
b, err := buf.ReadByte()
|
|
|
|
if err != nil {
|
2014-11-19 11:18:48 -08:00
|
|
|
// we ran out of bytes before we reached the endSysex so we break
|
2014-04-26 03:11:51 -07:00
|
|
|
break
|
|
|
|
}
|
2014-06-10 15:16:11 -07:00
|
|
|
currentBuffer = append(currentBuffer, b)
|
2014-07-13 13:54:41 -07:00
|
|
|
if currentBuffer[len(currentBuffer)-1] == endSysex {
|
2014-04-26 03:11:51 -07:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2014-06-10 15:16:11 -07:00
|
|
|
command := currentBuffer[1]
|
2014-04-26 03:11:51 -07:00
|
|
|
switch command {
|
2014-07-13 13:54:41 -07:00
|
|
|
case capabilityResponse:
|
2014-06-10 15:16:11 -07:00
|
|
|
supportedModes := 0
|
2014-04-26 03:11:51 -07:00
|
|
|
n := 0
|
|
|
|
|
2014-06-10 15:16:11 -07:00
|
|
|
for _, val := range currentBuffer[2:(len(currentBuffer) - 5)] {
|
2014-04-26 03:11:51 -07:00
|
|
|
if val == 127 {
|
2014-06-10 15:16:11 -07:00
|
|
|
modes := []byte{}
|
2014-07-13 13:54:41 -07:00
|
|
|
for _, mode := range []byte{input, output, analog, pwm, servo} {
|
2014-06-10 15:16:11 -07:00
|
|
|
if (supportedModes & (1 << mode)) != 0 {
|
2014-04-26 03:11:51 -07:00
|
|
|
modes = append(modes, mode)
|
|
|
|
}
|
|
|
|
}
|
2014-07-13 13:54:41 -07:00
|
|
|
b.pins = append(b.pins, pin{modes, output, 0, 0})
|
2014-07-13 20:27:38 -07:00
|
|
|
b.events[fmt.Sprintf("digital_read_%v", len(b.pins)-1)] = gobot.NewEvent()
|
2014-07-16 11:49:06 -07:00
|
|
|
b.events[fmt.Sprintf("pin_%v_state", len(b.pins)-1)] = gobot.NewEvent()
|
2014-06-10 15:16:11 -07:00
|
|
|
supportedModes = 0
|
2014-04-26 03:11:51 -07:00
|
|
|
n = 0
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if n == 0 {
|
2014-06-10 15:16:11 -07:00
|
|
|
supportedModes = supportedModes | (1 << val)
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
n ^= 1
|
|
|
|
}
|
2014-07-13 13:54:41 -07:00
|
|
|
gobot.Publish(b.events["capability_query"], nil)
|
|
|
|
case analogMappingResponse:
|
2014-06-10 15:16:11 -07:00
|
|
|
pinIndex := byte(0)
|
2014-04-26 03:11:51 -07:00
|
|
|
|
2014-07-13 13:54:41 -07:00
|
|
|
for _, val := range currentBuffer[2 : len(b.pins)-1] {
|
2014-04-26 03:11:51 -07:00
|
|
|
|
2014-07-13 13:54:41 -07:00
|
|
|
b.pins[pinIndex].analogChannel = val
|
2014-04-26 03:11:51 -07:00
|
|
|
|
|
|
|
if val != 127 {
|
2014-07-13 13:54:41 -07:00
|
|
|
b.analogPins = append(b.analogPins, pinIndex)
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
2014-07-13 13:54:41 -07:00
|
|
|
b.events[fmt.Sprintf("analog_read_%v", pinIndex)] = gobot.NewEvent()
|
2014-06-10 15:16:11 -07:00
|
|
|
pinIndex++
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-07-13 13:54:41 -07:00
|
|
|
gobot.Publish(b.events["analog_mapping_query"], nil)
|
|
|
|
case pinStateResponse:
|
|
|
|
pin := b.pins[currentBuffer[2]]
|
|
|
|
pin.mode = currentBuffer[3]
|
|
|
|
pin.value = int(currentBuffer[4])
|
2014-04-26 03:11:51 -07:00
|
|
|
|
2014-06-10 15:16:11 -07:00
|
|
|
if len(currentBuffer) > 6 {
|
2014-07-13 13:54:41 -07:00
|
|
|
pin.value = int(uint(pin.value) | uint(currentBuffer[5])<<7)
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
2014-06-10 15:16:11 -07:00
|
|
|
if len(currentBuffer) > 7 {
|
2014-07-13 13:54:41 -07:00
|
|
|
pin.value = int(uint(pin.value) | uint(currentBuffer[6])<<14)
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
|
2014-07-13 13:54:41 -07:00
|
|
|
gobot.Publish(b.events[fmt.Sprintf("pin_%v_state", currentBuffer[2])],
|
2014-07-16 11:49:06 -07:00
|
|
|
map[string]int{
|
|
|
|
"pin": int(currentBuffer[2]),
|
|
|
|
"mode": int(pin.mode),
|
|
|
|
"value": int(pin.value),
|
|
|
|
},
|
2014-07-10 13:42:18 -07:00
|
|
|
)
|
2014-07-13 13:54:41 -07:00
|
|
|
case i2CReply:
|
2014-06-10 15:16:11 -07:00
|
|
|
i2cReply := map[string][]byte{
|
|
|
|
"slave_address": []byte{byte(currentBuffer[2]) | byte(currentBuffer[3])<<7},
|
|
|
|
"register": []byte{byte(currentBuffer[4]) | byte(currentBuffer[5])<<7},
|
|
|
|
"data": []byte{byte(currentBuffer[6]) | byte(currentBuffer[7])<<7},
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
2014-06-10 15:16:11 -07:00
|
|
|
for i := 8; i < len(currentBuffer); i = i + 2 {
|
|
|
|
if currentBuffer[i] == byte(0xF7) {
|
2014-04-26 03:11:51 -07:00
|
|
|
break
|
|
|
|
}
|
2014-06-10 15:16:11 -07:00
|
|
|
if i+2 > len(currentBuffer) {
|
2014-04-26 03:11:51 -07:00
|
|
|
break
|
|
|
|
}
|
2014-07-10 13:42:18 -07:00
|
|
|
i2cReply["data"] = append(i2cReply["data"],
|
|
|
|
byte(currentBuffer[i])|byte(currentBuffer[i+1])<<7,
|
|
|
|
)
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
2014-07-13 20:27:38 -07:00
|
|
|
gobot.Publish(b.events["i2c_reply"], i2cReply)
|
2014-07-13 13:54:41 -07:00
|
|
|
case firmwareQuery:
|
2014-06-10 15:16:11 -07:00
|
|
|
name := []byte{}
|
|
|
|
for _, val := range currentBuffer[4:(len(currentBuffer) - 1)] {
|
2014-04-26 03:11:51 -07:00
|
|
|
if val != 0 {
|
|
|
|
name = append(name, val)
|
|
|
|
}
|
|
|
|
}
|
2014-07-13 13:54:41 -07:00
|
|
|
b.firmwareName = string(name[:])
|
|
|
|
gobot.Publish(b.events["firmware_query"], b.firmwareName)
|
|
|
|
case stringData:
|
2014-07-15 14:52:11 -07:00
|
|
|
str := currentBuffer[2:len(currentBuffer)]
|
|
|
|
gobot.Publish(b.events["string_data"], string(str[:len(str)]))
|
2014-04-26 03:11:51 -07:00
|
|
|
default:
|
2014-11-19 11:18:48 -08:00
|
|
|
return errors.New(fmt.Sprintf("bad byte: 0x%x", command))
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-19 11:18:48 -08:00
|
|
|
return
|
2014-04-26 03:11:51 -07:00
|
|
|
}
|