mirror of
https://github.com/hybridgroup/gobot.git
synced 2025-04-27 13:48:56 +08:00
Adding godocs to firmata package
This commit is contained in:
parent
bf7bc97c3a
commit
58c15eb116
47
platforms/firmata/doc.go
Normal file
47
platforms/firmata/doc.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
This package provides the adaptor for microcontrollers such as Arduino that support the [Firmata](http://firmata.org/wiki/Main_Page) protocol
|
||||||
|
|
||||||
|
Installing:
|
||||||
|
|
||||||
|
go get github.com/hybridgroup/gobot && go install github.com/hybridgroup/gobot/platforms/firmata
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hybridgroup/gobot"
|
||||||
|
"github.com/hybridgroup/gobot/platforms/firmata"
|
||||||
|
"github.com/hybridgroup/gobot/platforms/gpio"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
gbot := gobot.NewGobot()
|
||||||
|
|
||||||
|
firmataAdaptor := firmata.NewFirmataAdaptor("arduino", "/dev/ttyACM0")
|
||||||
|
led := gpio.NewLedDriver(firmataAdaptor, "led", "13")
|
||||||
|
|
||||||
|
work := func() {
|
||||||
|
gobot.Every(1*time.Second, func() {
|
||||||
|
led.Toggle()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
robot := gobot.NewRobot("bot",
|
||||||
|
[]gobot.Connection{firmataAdaptor},
|
||||||
|
[]gobot.Device{led},
|
||||||
|
work,
|
||||||
|
)
|
||||||
|
|
||||||
|
gbot.AddRobot(robot)
|
||||||
|
|
||||||
|
gbot.Start()
|
||||||
|
}
|
||||||
|
|
||||||
|
For further information refer to firmata readme:
|
||||||
|
https://github.com/hybridgroup/gobot/blob/master/platforms/firmata/README.md
|
||||||
|
*/
|
||||||
|
package firmata
|
@ -69,6 +69,10 @@ type pin struct {
|
|||||||
analogChannel byte
|
analogChannel byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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"
|
||||||
func newBoard(sp io.ReadWriteCloser) *board {
|
func newBoard(sp io.ReadWriteCloser) *board {
|
||||||
board := &board{
|
board := &board{
|
||||||
majorVersion: 0,
|
majorVersion: 0,
|
||||||
@ -88,7 +92,6 @@ func newBoard(sp io.ReadWriteCloser) *board {
|
|||||||
"analog_mapping_query",
|
"analog_mapping_query",
|
||||||
"report_version",
|
"report_version",
|
||||||
"i2c_reply",
|
"i2c_reply",
|
||||||
"analog_mapping_query",
|
|
||||||
"string_data",
|
"string_data",
|
||||||
"firmware_query",
|
"firmware_query",
|
||||||
} {
|
} {
|
||||||
@ -98,6 +101,8 @@ func newBoard(sp io.ReadWriteCloser) *board {
|
|||||||
return board
|
return board
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// connect starts connection to board.
|
||||||
|
// Queries report version until connected
|
||||||
func (b *board) connect() {
|
func (b *board) connect() {
|
||||||
if b.connected == false {
|
if b.connected == false {
|
||||||
b.reset()
|
b.reset()
|
||||||
@ -114,6 +119,8 @@ func (b *board) connect() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initBoard initializes board by listening for "firware_query", "capability_query"
|
||||||
|
// and "analog_mapping_query" events
|
||||||
func (b *board) initBoard() {
|
func (b *board) initBoard() {
|
||||||
gobot.Once(b.events["firmware_query"], func(data interface{}) {
|
gobot.Once(b.events["firmware_query"], func(data interface{}) {
|
||||||
b.queryCapabilities()
|
b.queryCapabilities()
|
||||||
@ -130,19 +137,23 @@ func (b *board) initBoard() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// readAndProcess reads from serial port and parses data.
|
||||||
func (b *board) readAndProcess() {
|
func (b *board) readAndProcess() {
|
||||||
b.process(b.read())
|
b.process(b.read())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset writes system reset bytes.
|
||||||
func (b *board) reset() {
|
func (b *board) reset() {
|
||||||
b.write([]byte{systemReset})
|
b.write([]byte{systemReset})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setPinMode writes pin mode bytes for specified pin.
|
||||||
func (b *board) setPinMode(pin byte, mode byte) {
|
func (b *board) setPinMode(pin byte, mode byte) {
|
||||||
b.pins[pin].mode = mode
|
b.pins[pin].mode = mode
|
||||||
b.write([]byte{pinMode, pin, mode})
|
b.write([]byte{pinMode, pin, mode})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// digitalWrite is used to send a digital value to a specified pin.
|
||||||
func (b *board) digitalWrite(pin byte, value byte) {
|
func (b *board) digitalWrite(pin byte, value byte) {
|
||||||
port := byte(math.Floor(float64(pin) / 8))
|
port := byte(math.Floor(float64(pin) / 8))
|
||||||
portValue := byte(0)
|
portValue := byte(0)
|
||||||
@ -157,48 +168,54 @@ func (b *board) digitalWrite(pin byte, value byte) {
|
|||||||
b.write([]byte{digitalMessage | port, portValue & 0x7F, (portValue >> 7) & 0x7F})
|
b.write([]byte{digitalMessage | port, portValue & 0x7F, (portValue >> 7) & 0x7F})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// analogWrite writes value to specified pin
|
||||||
func (b *board) analogWrite(pin byte, value byte) {
|
func (b *board) analogWrite(pin byte, value byte) {
|
||||||
b.pins[pin].value = int(value)
|
b.pins[pin].value = int(value)
|
||||||
b.write([]byte{analogMessage | pin, value & 0x7F, (value >> 7) & 0x7F})
|
b.write([]byte{analogMessage | pin, value & 0x7F, (value >> 7) & 0x7F})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// version returns board version following MAYOR.minor convention.
|
||||||
func (b *board) version() string {
|
func (b *board) version() string {
|
||||||
return fmt.Sprintf("%v.%v", b.majorVersion, b.minorVersion)
|
return fmt.Sprintf("%v.%v", b.majorVersion, b.minorVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *board) reportVersion() {
|
// queryFirmware writes bytes to query firmware from board.
|
||||||
b.write([]byte{reportVersion})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *board) queryFirmware() {
|
func (b *board) queryFirmware() {
|
||||||
b.write([]byte{startSysex, firmwareQuery, endSysex})
|
b.write([]byte{startSysex, firmwareQuery, endSysex})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// queryPinState writes bytes to retrieve pin state
|
||||||
func (b *board) queryPinState(pin byte) {
|
func (b *board) queryPinState(pin byte) {
|
||||||
b.write([]byte{startSysex, pinStateQuery, pin, endSysex})
|
b.write([]byte{startSysex, pinStateQuery, pin, endSysex})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// queryReportVersion sends query for report version
|
||||||
func (b *board) queryReportVersion() {
|
func (b *board) queryReportVersion() {
|
||||||
b.write([]byte{reportVersion})
|
b.write([]byte{reportVersion})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// queryCapabilities is used to retrieve board capabilities.
|
||||||
func (b *board) queryCapabilities() {
|
func (b *board) queryCapabilities() {
|
||||||
b.write([]byte{startSysex, capabilityQuery, endSysex})
|
b.write([]byte{startSysex, capabilityQuery, endSysex})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// queryAnalogMapping returns analog mapping for board.
|
||||||
func (b *board) queryAnalogMapping() {
|
func (b *board) queryAnalogMapping() {
|
||||||
b.write([]byte{startSysex, analogMappingQuery, endSysex})
|
b.write([]byte{startSysex, analogMappingQuery, endSysex})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// togglePinReporting is used to change pin reporting mode.
|
||||||
func (b *board) togglePinReporting(pin byte, state byte, mode byte) {
|
func (b *board) togglePinReporting(pin byte, state byte, mode byte) {
|
||||||
b.write([]byte{mode | pin, state})
|
b.write([]byte{mode | pin, state})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// i2cReadRequest reads from slaveAddress.
|
||||||
func (b *board) i2cReadRequest(slaveAddress byte, numBytes uint) {
|
func (b *board) i2cReadRequest(slaveAddress byte, numBytes uint) {
|
||||||
b.write([]byte{startSysex, i2CRequest, slaveAddress, (i2CModeRead << 3),
|
b.write([]byte{startSysex, i2CRequest, slaveAddress, (i2CModeRead << 3),
|
||||||
byte(numBytes & 0x7F), byte(((numBytes >> 7) & 0x7F)), endSysex})
|
byte(numBytes & 0x7F), byte(((numBytes >> 7) & 0x7F)), endSysex})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// i2cWriteRequest writes to slaveAddress.
|
||||||
func (b *board) i2cWriteRequest(slaveAddress byte, data []byte) {
|
func (b *board) i2cWriteRequest(slaveAddress byte, data []byte) {
|
||||||
ret := []byte{startSysex, i2CRequest, slaveAddress, (i2CModeWrite << 3)}
|
ret := []byte{startSysex, i2CRequest, slaveAddress, (i2CModeWrite << 3)}
|
||||||
for _, val := range data {
|
for _, val := range data {
|
||||||
@ -209,6 +226,7 @@ func (b *board) i2cWriteRequest(slaveAddress byte, data []byte) {
|
|||||||
b.write(ret)
|
b.write(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// i2xConfig returns i2c configuration.
|
||||||
func (b *board) i2cConfig(data []byte) {
|
func (b *board) i2cConfig(data []byte) {
|
||||||
ret := []byte{startSysex, i2CConfig}
|
ret := []byte{startSysex, i2CConfig}
|
||||||
for _, val := range data {
|
for _, val := range data {
|
||||||
@ -219,16 +237,24 @@ func (b *board) i2cConfig(data []byte) {
|
|||||||
b.write(ret)
|
b.write(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write is used to send commands to serial port
|
||||||
func (b *board) write(commands []byte) {
|
func (b *board) write(commands []byte) {
|
||||||
b.serial.Write(commands[:])
|
b.serial.Write(commands[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read returns buffer reading from serial port (1024 bytes)
|
||||||
func (b *board) read() []byte {
|
func (b *board) read() []byte {
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
b.serial.Read(buf)
|
b.serial.Read(buf)
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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"
|
||||||
func (b *board) process(data []byte) {
|
func (b *board) process(data []byte) {
|
||||||
buf := bytes.NewBuffer(data)
|
buf := bytes.NewBuffer(data)
|
||||||
for {
|
for {
|
||||||
|
@ -16,6 +16,8 @@ type FirmataAdaptor struct {
|
|||||||
connect func(*FirmataAdaptor)
|
connect func(*FirmataAdaptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewFirmataAdaptor returns a new firmata adaptor with specified name
|
||||||
|
// Generates a connect function that opens serial communication in specified port
|
||||||
func NewFirmataAdaptor(name, port string) *FirmataAdaptor {
|
func NewFirmataAdaptor(name, port string) *FirmataAdaptor {
|
||||||
return &FirmataAdaptor{
|
return &FirmataAdaptor{
|
||||||
Adaptor: *gobot.NewAdaptor(
|
Adaptor: *gobot.NewAdaptor(
|
||||||
@ -33,6 +35,7 @@ func NewFirmataAdaptor(name, port string) *FirmataAdaptor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Connect returns true if connection to board is succesfull
|
||||||
func (f *FirmataAdaptor) Connect() bool {
|
func (f *FirmataAdaptor) Connect() bool {
|
||||||
f.connect(f)
|
f.connect(f)
|
||||||
f.board.connect()
|
f.board.connect()
|
||||||
@ -40,6 +43,8 @@ func (f *FirmataAdaptor) Connect() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// close finishes connection to serial port
|
||||||
|
// Prints error message on error
|
||||||
func (f *FirmataAdaptor) Disconnect() bool {
|
func (f *FirmataAdaptor) Disconnect() bool {
|
||||||
err := f.board.serial.Close()
|
err := f.board.serial.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -47,9 +52,14 @@ func (f *FirmataAdaptor) Disconnect() bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finalize disconnects firmata adaptor
|
||||||
func (f *FirmataAdaptor) Finalize() bool { return f.Disconnect() }
|
func (f *FirmataAdaptor) Finalize() bool { return f.Disconnect() }
|
||||||
|
|
||||||
|
// InitServo (not yet implemented)
|
||||||
func (f *FirmataAdaptor) InitServo() {}
|
func (f *FirmataAdaptor) InitServo() {}
|
||||||
|
|
||||||
|
// ServoWrite sets angle form 0 to 360 to specified servo pin
|
||||||
func (f *FirmataAdaptor) ServoWrite(pin string, angle byte) {
|
func (f *FirmataAdaptor) ServoWrite(pin string, angle byte) {
|
||||||
p, _ := strconv.Atoi(pin)
|
p, _ := strconv.Atoi(pin)
|
||||||
|
|
||||||
@ -57,6 +67,7 @@ func (f *FirmataAdaptor) ServoWrite(pin string, angle byte) {
|
|||||||
f.board.analogWrite(byte(p), angle)
|
f.board.analogWrite(byte(p), angle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PwmWrite writes analog value to specified pin
|
||||||
func (f *FirmataAdaptor) PwmWrite(pin string, level byte) {
|
func (f *FirmataAdaptor) PwmWrite(pin string, level byte) {
|
||||||
p, _ := strconv.Atoi(pin)
|
p, _ := strconv.Atoi(pin)
|
||||||
|
|
||||||
@ -64,6 +75,7 @@ func (f *FirmataAdaptor) PwmWrite(pin string, level byte) {
|
|||||||
f.board.analogWrite(byte(p), level)
|
f.board.analogWrite(byte(p), level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DigitalWrite writes digital values to specified pin
|
||||||
func (f *FirmataAdaptor) DigitalWrite(pin string, level byte) {
|
func (f *FirmataAdaptor) DigitalWrite(pin string, level byte) {
|
||||||
p, _ := strconv.Atoi(pin)
|
p, _ := strconv.Atoi(pin)
|
||||||
|
|
||||||
@ -71,6 +83,8 @@ func (f *FirmataAdaptor) DigitalWrite(pin string, level byte) {
|
|||||||
f.board.digitalWrite(byte(p), level)
|
f.board.digitalWrite(byte(p), level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DigitalRead retrieves digital value from specified pin
|
||||||
|
// Returns -1 if response from board is timed out
|
||||||
func (f *FirmataAdaptor) DigitalRead(pin string) int {
|
func (f *FirmataAdaptor) DigitalRead(pin string) int {
|
||||||
ret := make(chan int)
|
ret := make(chan int)
|
||||||
|
|
||||||
@ -91,6 +105,7 @@ func (f *FirmataAdaptor) DigitalRead(pin string) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AnalogRead retrieves value from analog pin.
|
||||||
// NOTE pins are numbered A0-A5, which translate to digital pins 14-19
|
// NOTE pins are numbered A0-A5, which translate to digital pins 14-19
|
||||||
func (f *FirmataAdaptor) AnalogRead(pin string) int {
|
func (f *FirmataAdaptor) AnalogRead(pin string) int {
|
||||||
ret := make(chan int)
|
ret := make(chan int)
|
||||||
@ -114,19 +129,24 @@ func (f *FirmataAdaptor) AnalogRead(pin string) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AnalogWrite writes value to ananlog pin
|
||||||
func (f *FirmataAdaptor) AnalogWrite(pin string, level byte) {
|
func (f *FirmataAdaptor) AnalogWrite(pin string, level byte) {
|
||||||
f.PwmWrite(pin, level)
|
f.PwmWrite(pin, level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// digitalPin converts pin number to digital mapping
|
||||||
func (f *FirmataAdaptor) digitalPin(pin int) int {
|
func (f *FirmataAdaptor) digitalPin(pin int) int {
|
||||||
return pin + 14
|
return pin + 14
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// I2cStart initializes board with i2c configuration
|
||||||
func (f *FirmataAdaptor) I2cStart(address byte) {
|
func (f *FirmataAdaptor) I2cStart(address byte) {
|
||||||
f.i2cAddress = address
|
f.i2cAddress = address
|
||||||
f.board.i2cConfig([]byte{0})
|
f.board.i2cConfig([]byte{0})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// I2cRead reads from I2c specified size
|
||||||
|
// Returns empty byte array if response is timed out
|
||||||
func (f *FirmataAdaptor) I2cRead(size uint) []byte {
|
func (f *FirmataAdaptor) I2cRead(size uint) []byte {
|
||||||
ret := make(chan []byte)
|
ret := make(chan []byte)
|
||||||
f.board.i2cReadRequest(f.i2cAddress, size)
|
f.board.i2cReadRequest(f.i2cAddress, size)
|
||||||
@ -145,6 +165,7 @@ func (f *FirmataAdaptor) I2cRead(size uint) []byte {
|
|||||||
return []byte{}
|
return []byte{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// I2cWrite retrieves i2c data
|
||||||
func (f *FirmataAdaptor) I2cWrite(data []byte) {
|
func (f *FirmataAdaptor) I2cWrite(data []byte) {
|
||||||
f.board.i2cWriteRequest(f.i2cAddress, data)
|
f.board.i2cWriteRequest(f.i2cAddress, data)
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ func initTestFirmata() *board {
|
|||||||
func TestReportVersion(t *testing.T) {
|
func TestReportVersion(t *testing.T) {
|
||||||
b := initTestFirmata()
|
b := initTestFirmata()
|
||||||
//test if functions executes
|
//test if functions executes
|
||||||
b.reportVersion()
|
b.queryReportVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestQueryFirmware(t *testing.T) {
|
func TestQueryFirmware(t *testing.T) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user