From 2e6bd46354a851f46de6efd5b587182c703819d4 Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sat, 29 Aug 2015 00:42:44 -0400 Subject: [PATCH 01/27] i2c: added ReadBytes to I2CBus --- host/generic/i2cbus.go | 22 ++++++++++++++++++++++ i2c.go | 2 ++ 2 files changed, 24 insertions(+) diff --git a/host/generic/i2cbus.go b/host/generic/i2cbus.go index dc8e74c..45c5870 100644 --- a/host/generic/i2cbus.go +++ b/host/generic/i2cbus.go @@ -101,6 +101,28 @@ func (b *i2cBus) ReadByte(addr byte) (byte, error) { return bytes[0], nil } +func (b *i2cBus) ReadBytes(addr byte, num int) ([]byte, error) { + b.mu.Lock() + defer b.mu.Unlock() + + if err := b.init(); err != nil { + return []byte{0}, err + } + + if err := b.setAddress(addr); err != nil { + return []byte{0}, err + } + + bytes := make([]byte, num) + n, _ := b.file.Read(bytes) + + if n != num { + return []byte{0}, fmt.Errorf("i2c: Unexpected number (%v) of bytes read", n) + } + + return bytes, nil +} + func (b *i2cBus) WriteByte(addr, value byte) error { b.mu.Lock() defer b.mu.Unlock() diff --git a/i2c.go b/i2c.go index 8bdb876..d9922ed 100644 --- a/i2c.go +++ b/i2c.go @@ -4,6 +4,8 @@ package embd // I2CBus interface is used to interact with the I2C bus. type I2CBus interface { + // ReadByte reads a byte from the given address. + ReadBytes(addr byte, num int) (value []byte, err error) // ReadByte reads a byte from the given address. ReadByte(addr byte) (value byte, err error) // WriteByte writes a byte to the given address. From afa49bb2bc5488863b3b97944eb51c602ac6398d Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sat, 29 Aug 2015 00:53:34 -0400 Subject: [PATCH 02/27] build: fixed broken tests --- controller/hd44780/hd44780_test.go | 1 + i2c.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/controller/hd44780/hd44780_test.go b/controller/hd44780/hd44780_test.go index b05dddc..40b3e2a 100644 --- a/controller/hd44780/hd44780_test.go +++ b/controller/hd44780/hd44780_test.go @@ -131,6 +131,7 @@ type mockI2CBus struct { closed bool } +func (bus *mockI2CBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0x00}, nil } func (bus *mockI2CBus) ReadByte(addr byte) (byte, error) { return 0x00, nil } func (bus *mockI2CBus) WriteBytes(addr byte, value []byte) error { return nil } func (bus *mockI2CBus) ReadFromReg(addr, reg byte, value []byte) error { return nil } diff --git a/i2c.go b/i2c.go index d9922ed..41244ea 100644 --- a/i2c.go +++ b/i2c.go @@ -6,7 +6,7 @@ package embd type I2CBus interface { // ReadByte reads a byte from the given address. ReadBytes(addr byte, num int) (value []byte, err error) - // ReadByte reads a byte from the given address. + // ReadByte reads a slice of bytes from the given address. ReadByte(addr byte) (value byte, err error) // WriteByte writes a byte to the given address. WriteByte(addr, value byte) error From db5c9abb2a12eca86ba44f2d1690a62ffe476d7f Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sat, 29 Aug 2015 00:57:25 -0400 Subject: [PATCH 03/27] ran gofmt --- controller/hd44780/hd44780_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/hd44780/hd44780_test.go b/controller/hd44780/hd44780_test.go index 40b3e2a..eee375d 100644 --- a/controller/hd44780/hd44780_test.go +++ b/controller/hd44780/hd44780_test.go @@ -131,7 +131,7 @@ type mockI2CBus struct { closed bool } -func (bus *mockI2CBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0x00}, nil } +func (bus *mockI2CBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0x00}, nil } func (bus *mockI2CBus) ReadByte(addr byte) (byte, error) { return 0x00, nil } func (bus *mockI2CBus) WriteBytes(addr byte, value []byte) error { return nil } func (bus *mockI2CBus) ReadFromReg(addr, reg byte, value []byte) error { return nil } From 48c26358bdbce029d3e614635bd435d9dbd439c9 Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sun, 30 Aug 2015 09:48:43 -0400 Subject: [PATCH 04/27] doc: fixed mixed up comments --- i2c.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i2c.go b/i2c.go index 41244ea..6a5d1ec 100644 --- a/i2c.go +++ b/i2c.go @@ -5,9 +5,9 @@ package embd // I2CBus interface is used to interact with the I2C bus. type I2CBus interface { // ReadByte reads a byte from the given address. - ReadBytes(addr byte, num int) (value []byte, err error) - // ReadByte reads a slice of bytes from the given address. ReadByte(addr byte) (value byte, err error) + // ReadBytes reads a slice of bytes from the given address. + ReadBytes(addr byte, num int) (value []byte, err error) // WriteByte writes a byte to the given address. WriteByte(addr, value byte) error // WriteBytes writes a slice bytes to the given address. From 9d8285ca0169f361264fd951cb137227b06989d9 Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sat, 10 Oct 2015 23:23:40 -0400 Subject: [PATCH 05/27] changed ReadBytes to get file size from stat --- controller/hd44780/hd44780_test.go | 2 +- host/generic/i2cbus.go | 12 +++++++++--- i2c.go | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/controller/hd44780/hd44780_test.go b/controller/hd44780/hd44780_test.go index eee375d..9542bf7 100644 --- a/controller/hd44780/hd44780_test.go +++ b/controller/hd44780/hd44780_test.go @@ -131,7 +131,7 @@ type mockI2CBus struct { closed bool } -func (bus *mockI2CBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0x00}, nil } +func (bus *mockI2CBus) ReadBytes(addr byte) ([]byte, error) { return []byte{0x00}, nil } func (bus *mockI2CBus) ReadByte(addr byte) (byte, error) { return 0x00, nil } func (bus *mockI2CBus) WriteBytes(addr byte, value []byte) error { return nil } func (bus *mockI2CBus) ReadFromReg(addr, reg byte, value []byte) error { return nil } diff --git a/host/generic/i2cbus.go b/host/generic/i2cbus.go index 45c5870..63b6eb1 100644 --- a/host/generic/i2cbus.go +++ b/host/generic/i2cbus.go @@ -101,7 +101,7 @@ func (b *i2cBus) ReadByte(addr byte) (byte, error) { return bytes[0], nil } -func (b *i2cBus) ReadBytes(addr byte, num int) ([]byte, error) { +func (b *i2cBus) ReadBytes(addr byte) ([]byte, error) { b.mu.Lock() defer b.mu.Unlock() @@ -113,10 +113,16 @@ func (b *i2cBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0}, err } - bytes := make([]byte, num) + info, err := b.file.Stat() + if err != nil { + return []byte{0}, err + } + + size := int(info.Size()) + bytes := make([]byte, size) n, _ := b.file.Read(bytes) - if n != num { + if n != size { return []byte{0}, fmt.Errorf("i2c: Unexpected number (%v) of bytes read", n) } diff --git a/i2c.go b/i2c.go index 6a5d1ec..f0c79da 100644 --- a/i2c.go +++ b/i2c.go @@ -4,6 +4,8 @@ package embd // I2CBus interface is used to interact with the I2C bus. type I2CBus interface { + // ReadBytes reads a slice of bytes from the given address. + ReadBytes(addr byte) (value []byte, err error) // ReadByte reads a byte from the given address. ReadByte(addr byte) (value byte, err error) // ReadBytes reads a slice of bytes from the given address. From b296368a0557615cbc3ba19bd21965d364d44dba Mon Sep 17 00:00:00 2001 From: Gavin Cabbage Date: Sat, 10 Oct 2015 23:58:24 -0400 Subject: [PATCH 06/27] removing failed Stat use --- controller/hd44780/hd44780_test.go | 2 +- host/generic/i2cbus.go | 12 +++--------- i2c.go | 2 -- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/controller/hd44780/hd44780_test.go b/controller/hd44780/hd44780_test.go index 9542bf7..eee375d 100644 --- a/controller/hd44780/hd44780_test.go +++ b/controller/hd44780/hd44780_test.go @@ -131,7 +131,7 @@ type mockI2CBus struct { closed bool } -func (bus *mockI2CBus) ReadBytes(addr byte) ([]byte, error) { return []byte{0x00}, nil } +func (bus *mockI2CBus) ReadBytes(addr byte, num int) ([]byte, error) { return []byte{0x00}, nil } func (bus *mockI2CBus) ReadByte(addr byte) (byte, error) { return 0x00, nil } func (bus *mockI2CBus) WriteBytes(addr byte, value []byte) error { return nil } func (bus *mockI2CBus) ReadFromReg(addr, reg byte, value []byte) error { return nil } diff --git a/host/generic/i2cbus.go b/host/generic/i2cbus.go index 63b6eb1..45c5870 100644 --- a/host/generic/i2cbus.go +++ b/host/generic/i2cbus.go @@ -101,7 +101,7 @@ func (b *i2cBus) ReadByte(addr byte) (byte, error) { return bytes[0], nil } -func (b *i2cBus) ReadBytes(addr byte) ([]byte, error) { +func (b *i2cBus) ReadBytes(addr byte, num int) ([]byte, error) { b.mu.Lock() defer b.mu.Unlock() @@ -113,16 +113,10 @@ func (b *i2cBus) ReadBytes(addr byte) ([]byte, error) { return []byte{0}, err } - info, err := b.file.Stat() - if err != nil { - return []byte{0}, err - } - - size := int(info.Size()) - bytes := make([]byte, size) + bytes := make([]byte, num) n, _ := b.file.Read(bytes) - if n != size { + if n != num { return []byte{0}, fmt.Errorf("i2c: Unexpected number (%v) of bytes read", n) } diff --git a/i2c.go b/i2c.go index f0c79da..6a5d1ec 100644 --- a/i2c.go +++ b/i2c.go @@ -4,8 +4,6 @@ package embd // I2CBus interface is used to interact with the I2C bus. type I2CBus interface { - // ReadBytes reads a slice of bytes from the given address. - ReadBytes(addr byte) (value []byte, err error) // ReadByte reads a byte from the given address. ReadByte(addr byte) (value byte, err error) // ReadBytes reads a slice of bytes from the given address. From c1886eb5bf22bf655793ce7c50491175de95923f Mon Sep 17 00:00:00 2001 From: ssk Date: Tue, 3 Nov 2015 19:24:27 +0530 Subject: [PATCH 07/27] Fixed SPIController issue with missing fields --- host/generic/spibus.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/host/generic/spibus.go b/host/generic/spibus.go index f682daa..e2f7513 100644 --- a/host/generic/spibus.go +++ b/host/generic/spibus.go @@ -36,6 +36,8 @@ type spiIOCTransfer struct { speedHz uint32 delayus uint16 bitsPerWord uint8 + csChange uint8 + pad uint32 } type spiBus struct { From 1b48067d77c31a74d6ce2d5b1f9734a03487f9ec Mon Sep 17 00:00:00 2001 From: Wu Jiang Date: Tue, 22 Dec 2015 17:05:28 -0500 Subject: [PATCH 08/27] Println doesn't accept formatting. It looks like this is caused by confusion between `fmt.Println` and `fmt.Printf`. --- samples/spi.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/spi.go b/samples/spi.go index 298acc4..20d606c 100644 --- a/samples/spi.go +++ b/samples/spi.go @@ -24,25 +24,25 @@ func main() { panic(err) } - fmt.Println("received data is: %v", dataBuf) + fmt.Println("received data is:", dataBuf) dataReceived, err := spiBus.ReceiveData(3) if err != nil { panic(err) } - fmt.Println("received data is: %v", dataReceived) + fmt.Println("received data is:", dataReceived) dataByte := byte(1) receivedByte, err := spiBus.TransferAndReceiveByte(dataByte) if err != nil { panic(err) } - fmt.Println("received byte is: %v", receivedByte) + fmt.Println("received byte is:", receivedByte) receivedByte, err = spiBus.ReceiveByte() if err != nil { panic(err) } - fmt.Println("received byte is: %v", receivedByte) + fmt.Println("received byte is:", receivedByte) } From 60218147312c0f5550bfca018a579639cae41b51 Mon Sep 17 00:00:00 2001 From: gotang Date: Sat, 20 Aug 2016 14:10:49 +0800 Subject: [PATCH 09/27] fix fatal error: concurrent map read and map write --- host/generic/interrupt.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/host/generic/interrupt.go b/host/generic/interrupt.go index 4052283..7f9b766 100644 --- a/host/generic/interrupt.go +++ b/host/generic/interrupt.go @@ -61,11 +61,13 @@ func initEpollListener() *epollListener { if err != nil { panic(fmt.Sprintf("EpollWait error: %v", err)) } + listener.mu.Lock() for i := 0; i < n; i++ { if irq, ok := listener.interruptablePins[int(epollEvents[i].Fd)]; ok { irq.Signal() } } + listener.mu.Unlock() } }() return listener From d9dd4b51a95dc57aa8b740b402806de957706b13 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 26 Aug 2016 23:00:39 -0700 Subject: [PATCH 10/27] add minimal support for NextThing CHIP --- detect.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/detect.go b/detect.go index a92ff4e..93f4500 100644 --- a/detect.go +++ b/detect.go @@ -31,6 +31,9 @@ const ( // HostRadxa represents the Radxa board. HostRadxa = "Radxa" + + // HostCHIP represents the NextThing C.H.I.P. + HostCHIP = "CHIP" ) func execOutput(name string, arg ...string) (output string, err error) { @@ -92,7 +95,7 @@ func cpuInfo() (model, hardware string, revision int, err error) { } revision = int(rev) case strings.HasPrefix(fields[0], "Hardware"): - hardware = fields[1] + hardware = strings.TrimSpace(fields[1]) case strings.HasPrefix(fields[0], "model name"): model = fields[1] } @@ -108,7 +111,9 @@ func DetectHost() (host Host, rev int, err error) { } if major < 3 || (major == 3 && minor < 8) { - return HostNull, 0, fmt.Errorf("embd: linux kernel versions lower than 3.8 are not supported. you have %v.%v.%v", major, minor, patch) + return HostNull, 0, fmt.Errorf( + "embd: linux kernel versions lower than 3.8 are not supported, "+ + "you have %v.%v.%v", major, minor, patch) } model, hardware, rev, err := cpuInfo() @@ -121,6 +126,13 @@ func DetectHost() (host Host, rev int, err error) { return HostBBB, rev, nil case strings.Contains(hardware, "BCM2708") || strings.Contains(hardware, "BCM2709"): return HostRPi, rev, nil + case hardware == "Allwinner sun4i/sun5i Families": + if major < 4 || (major == 4 && minor < 4) { + return HostNull, 0, fmt.Errorf( + "embd: linux kernel version 4.4+ required, you have %v.%v", + major, minor) + } + return HostCHIP, rev, nil default: return HostNull, 0, fmt.Errorf(`embd: your host "%v:%v" is not supported at this moment. request support at https://github.com/kidoman/embd/issues`, host, model) } From 938a071c1ad1f5a4eb5a0cfa06cf8ab3831aecac Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 26 Aug 2016 23:02:11 -0700 Subject: [PATCH 11/27] add minimal support for NextThing CHIP, part 2 --- host/chip/chip.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 host/chip/chip.go diff --git a/host/chip/chip.go b/host/chip/chip.go new file mode 100644 index 0000000..e7b541a --- /dev/null +++ b/host/chip/chip.go @@ -0,0 +1,68 @@ +// Copyright 2016 by Thorsten von Eicken + +// Package chip provides NextThing C.H.I.P. support. +// References: +// http://docs.getchip.com/chip.html#chip-hardware +// http://www.chip-community.org/index.php/Hardware_Information +// +// The following features are supported on Linux kernel 4.4+ +// GPIO (digital (rw)) +// I²C +// SPI +// Could add LED support by following https://bbs.nextthing.co/t/pwr-and-stat-leds/748/5 + +package chip + +import ( + "github.com/kidoman/embd" + "github.com/kidoman/embd/host/generic" +) + +var spiDeviceMinor = byte(0) + +var chipPins = embd.PinMap{ + &embd.PinDesc{"XIO-P0", []string{"1016", "0", "gpio0"}, embd.CapDigital, 1016, 0}, + &embd.PinDesc{"XIO-P6", []string{"1022", "6", "gpio6"}, embd.CapDigital, 1022, 0}, + /* + &embd.PinDesc{ID: "P1_3", Aliases: []string{"0", "GPIO_0", "SDA", "I2C0_SDA"}, Caps: embd.CapDigital | embd.CapI2C, DigitalLogical: 0}, + &embd.PinDesc{ID: "P1_5", Aliases: []string{"1", "GPIO_1", "SCL", "I2C0_SCL"}, Caps: embd.CapDigital | embd.CapI2C, DigitalLogical: 1}, + &embd.PinDesc{ID: "P1_7", Aliases: []string{"4", "GPIO_4", "GPCLK0"}, Caps: embd.CapDigital, DigitalLogical: 4}, + &embd.PinDesc{ID: "P1_8", Aliases: []string{"14", "GPIO_14", "TXD", "UART0_TXD"}, Caps: embd.CapDigital | embd.CapUART, DigitalLogical: 14}, + &embd.PinDesc{ID: "P1_10", Aliases: []string{"15", "GPIO_15", "RXD", "UART0_RXD"}, Caps: embd.CapDigital | embd.CapUART, DigitalLogical: 15}, + &embd.PinDesc{ID: "P1_11", Aliases: []string{"17", "GPIO_17"}, Caps: embd.CapDigital, DigitalLogical: 17}, + &embd.PinDesc{ID: "P1_12", Aliases: []string{"18", "GPIO_18", "PCM_CLK"}, Caps: embd.CapDigital, DigitalLogical: 18}, + &embd.PinDesc{ID: "P1_13", Aliases: []string{"21", "GPIO_21"}, Caps: embd.CapDigital, DigitalLogical: 21}, + &embd.PinDesc{ID: "P1_15", Aliases: []string{"22", "GPIO_22"}, Caps: embd.CapDigital, DigitalLogical: 22}, + &embd.PinDesc{ID: "P1_16", Aliases: []string{"23", "GPIO_23"}, Caps: embd.CapDigital, DigitalLogical: 23}, + &embd.PinDesc{ID: "P1_18", Aliases: []string{"24", "GPIO_24"}, Caps: embd.CapDigital, DigitalLogical: 24}, + &embd.PinDesc{ID: "P1_19", Aliases: []string{"10", "GPIO_10", "MOSI", "SPI0_MOSI"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 10}, + &embd.PinDesc{ID: "P1_21", Aliases: []string{"9", "GPIO_9", "MISO", "SPI0_MISO"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 9}, + &embd.PinDesc{ID: "P1_22", Aliases: []string{"25", "GPIO_25"}, Caps: embd.CapDigital, DigitalLogical: 25}, + &embd.PinDesc{ID: "P1_23", Aliases: []string{"11", "GPIO_11", "SCLK", "SPI0_SCLK"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 11}, + &embd.PinDesc{ID: "P1_24", Aliases: []string{"8", "GPIO_8", "CE0", "SPI0_CE0_N"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 8}, + &embd.PinDesc{ID: "P1_26", Aliases: []string{"7", "GPIO_7", "CE1", "SPI0_CE1_N"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 7}, + */ +} + +var ledMap = embd.LEDMap{ + "led0": []string{"0", "led0", "LED0"}, +} + +func init() { + embd.Register(embd.HostCHIP, func(rev int) *embd.Descriptor { + return &embd.Descriptor{ + GPIODriver: func() embd.GPIODriver { + return embd.NewGPIODriver(chipPins, generic.NewDigitalPin, nil, nil) + }, + I2CDriver: func() embd.I2CDriver { + return embd.NewI2CDriver(generic.NewI2CBus) + }, + LEDDriver: func() embd.LEDDriver { + return embd.NewLEDDriver(ledMap, generic.NewLED) + }, + SPIDriver: func() embd.SPIDriver { + return embd.NewSPIDriver(spiDeviceMinor, generic.NewSPIBus, nil) + }, + } + }) +} From 091d6f558821db718702f1dd9636637d2c429d6f Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 26 Aug 2016 23:02:41 -0700 Subject: [PATCH 12/27] gpio: don't fail if pin is already exported --- host/generic/digitalpin.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/host/generic/digitalpin.go b/host/generic/digitalpin.go index 80a81ea..525eeb4 100644 --- a/host/generic/digitalpin.go +++ b/host/generic/digitalpin.go @@ -10,6 +10,7 @@ import ( "os" "path" "strconv" + "syscall" "time" "github.com/kidoman/embd" @@ -69,6 +70,9 @@ func (p *digitalPin) export() error { } defer exporter.Close() _, err = exporter.WriteString(strconv.Itoa(p.n)) + if e, ok := err.(*os.PathError); ok && e.Err == syscall.EBUSY { + return nil // EBUSY -> the pin has already been exported + } return err } From e16818f0aac35d121688fdd049ad19cc5eeaa85b Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Sat, 27 Aug 2016 00:35:14 -0700 Subject: [PATCH 13/27] add support for NextThing CHIP, part 3 --- host/chip/chip.go | 85 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 27 deletions(-) diff --git a/host/chip/chip.go b/host/chip/chip.go index e7b541a..c6bf7cc 100644 --- a/host/chip/chip.go +++ b/host/chip/chip.go @@ -21,31 +21,62 @@ import ( var spiDeviceMinor = byte(0) var chipPins = embd.PinMap{ - &embd.PinDesc{"XIO-P0", []string{"1016", "0", "gpio0"}, embd.CapDigital, 1016, 0}, - &embd.PinDesc{"XIO-P6", []string{"1022", "6", "gpio6"}, embd.CapDigital, 1022, 0}, - /* - &embd.PinDesc{ID: "P1_3", Aliases: []string{"0", "GPIO_0", "SDA", "I2C0_SDA"}, Caps: embd.CapDigital | embd.CapI2C, DigitalLogical: 0}, - &embd.PinDesc{ID: "P1_5", Aliases: []string{"1", "GPIO_1", "SCL", "I2C0_SCL"}, Caps: embd.CapDigital | embd.CapI2C, DigitalLogical: 1}, - &embd.PinDesc{ID: "P1_7", Aliases: []string{"4", "GPIO_4", "GPCLK0"}, Caps: embd.CapDigital, DigitalLogical: 4}, - &embd.PinDesc{ID: "P1_8", Aliases: []string{"14", "GPIO_14", "TXD", "UART0_TXD"}, Caps: embd.CapDigital | embd.CapUART, DigitalLogical: 14}, - &embd.PinDesc{ID: "P1_10", Aliases: []string{"15", "GPIO_15", "RXD", "UART0_RXD"}, Caps: embd.CapDigital | embd.CapUART, DigitalLogical: 15}, - &embd.PinDesc{ID: "P1_11", Aliases: []string{"17", "GPIO_17"}, Caps: embd.CapDigital, DigitalLogical: 17}, - &embd.PinDesc{ID: "P1_12", Aliases: []string{"18", "GPIO_18", "PCM_CLK"}, Caps: embd.CapDigital, DigitalLogical: 18}, - &embd.PinDesc{ID: "P1_13", Aliases: []string{"21", "GPIO_21"}, Caps: embd.CapDigital, DigitalLogical: 21}, - &embd.PinDesc{ID: "P1_15", Aliases: []string{"22", "GPIO_22"}, Caps: embd.CapDigital, DigitalLogical: 22}, - &embd.PinDesc{ID: "P1_16", Aliases: []string{"23", "GPIO_23"}, Caps: embd.CapDigital, DigitalLogical: 23}, - &embd.PinDesc{ID: "P1_18", Aliases: []string{"24", "GPIO_24"}, Caps: embd.CapDigital, DigitalLogical: 24}, - &embd.PinDesc{ID: "P1_19", Aliases: []string{"10", "GPIO_10", "MOSI", "SPI0_MOSI"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 10}, - &embd.PinDesc{ID: "P1_21", Aliases: []string{"9", "GPIO_9", "MISO", "SPI0_MISO"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 9}, - &embd.PinDesc{ID: "P1_22", Aliases: []string{"25", "GPIO_25"}, Caps: embd.CapDigital, DigitalLogical: 25}, - &embd.PinDesc{ID: "P1_23", Aliases: []string{"11", "GPIO_11", "SCLK", "SPI0_SCLK"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 11}, - &embd.PinDesc{ID: "P1_24", Aliases: []string{"8", "GPIO_8", "CE0", "SPI0_CE0_N"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 8}, - &embd.PinDesc{ID: "P1_26", Aliases: []string{"7", "GPIO_7", "CE1", "SPI0_CE1_N"}, Caps: embd.CapDigital | embd.CapSPI, DigitalLogical: 7}, - */ -} + // official GPIO pins (U14 connector) using the pcf8574a + &embd.PinDesc{"XIO-P0", []string{"1016", "0", "U14-13", "gpio0"}, embd.CapDigital, 1016, 0}, + &embd.PinDesc{"XIO-P1", []string{"1017", "1", "U14-14", "gpio1"}, embd.CapDigital, 1017, 0}, + &embd.PinDesc{"XIO-P2", []string{"1018", "2", "U14-15", "gpio2"}, embd.CapDigital, 1018, 0}, + &embd.PinDesc{"XIO-P3", []string{"1019", "3", "U14-16", "gpio3"}, embd.CapDigital, 1019, 0}, + &embd.PinDesc{"XIO-P4", []string{"1020", "4", "U14-17", "gpio4"}, embd.CapDigital, 1020, 0}, + &embd.PinDesc{"XIO-P5", []string{"1021", "5", "U14-18", "gpio5"}, embd.CapDigital, 1021, 0}, + &embd.PinDesc{"XIO-P6", []string{"1022", "6", "U14-19", "gpio6"}, embd.CapDigital, 1022, 0}, + &embd.PinDesc{"XIO-P7", []string{"1023", "7", "U14-20", "gpio7"}, embd.CapDigital, 1023, 0}, -var ledMap = embd.LEDMap{ - "led0": []string{"0", "led0", "LED0"}, + // pins usable on the U13 connector + &embd.PinDesc{"TWI1-SDA", []string{"48", "U13-9", "I2C0_SDA"}, embd.CapDigital | embd.CapI2C, 48, 0}, + &embd.PinDesc{"TWI1-SCK", []string{"47", "U13-11", "I2C0_SCK"}, embd.CapDigital | embd.CapI2C, 47, 0}, + &embd.PinDesc{"PWM0", []string{"34", "U13-18"}, embd.CapDigital | embd.CapPWM, 34, 0}, + &embd.PinDesc{"LCD-D2", []string{"98", "U13-17"}, embd.CapDigital, 98, 0}, + &embd.PinDesc{"LCD-D3", []string{"99", "U13-20"}, embd.CapDigital, 99, 0}, + &embd.PinDesc{"LCD-D4", []string{"100", "U13-19"}, embd.CapDigital, 100, 0}, + &embd.PinDesc{"LCD-D5", []string{"101", "U13-22"}, embd.CapDigital, 101, 0}, + &embd.PinDesc{"LCD-D6", []string{"102", "U13-21"}, embd.CapDigital, 102, 0}, + &embd.PinDesc{"LCD-D7", []string{"103", "U13-24"}, embd.CapDigital, 103, 0}, + &embd.PinDesc{"LCD-D10", []string{"106", "U13-23"}, embd.CapDigital, 106, 0}, + &embd.PinDesc{"LCD-D11", []string{"107", "U13-26"}, embd.CapDigital, 107, 0}, + &embd.PinDesc{"LCD-D12", []string{"108", "U13-25"}, embd.CapDigital, 108, 0}, + &embd.PinDesc{"LCD-D13", []string{"109", "U13-28"}, embd.CapDigital, 109, 0}, + &embd.PinDesc{"LCD-D14", []string{"110", "U13-27"}, embd.CapDigital, 110, 0}, + &embd.PinDesc{"LCD-D15", []string{"111", "U13-30"}, embd.CapDigital, 111, 0}, + &embd.PinDesc{"LCD-D18", []string{"114", "U13-29"}, embd.CapDigital, 114, 0}, + &embd.PinDesc{"LCD-D19", []string{"115", "U13-32"}, embd.CapDigital, 115, 0}, + &embd.PinDesc{"LCD-D20", []string{"116", "U13-31"}, embd.CapDigital, 116, 0}, + &embd.PinDesc{"LCD-D21", []string{"117", "U13-34"}, embd.CapDigital, 117, 0}, + &embd.PinDesc{"LCD-D22", []string{"118", "U13-33"}, embd.CapDigital, 118, 0}, + &embd.PinDesc{"LCD-D23", []string{"119", "U13-36"}, embd.CapDigital, 119, 0}, + &embd.PinDesc{"LCD-CLK", []string{"120", "U13-35"}, embd.CapDigital, 120, 0}, + &embd.PinDesc{"LCD-VSYNC", []string{"123", "U13-37"}, embd.CapDigital, 123, 0}, + &embd.PinDesc{"LCD-HSYNC", []string{"122", "U13-38"}, embd.CapDigital, 122, 0}, + &embd.PinDesc{"LCD-DE", []string{"121", "U13-40"}, embd.CapDigital, 121, 0}, + + // pins usable on the U14 connector + &embd.PinDesc{"UART1-TX", []string{"195", "U14-3", "EINT3"}, embd.CapDigital | embd.CapUART, 195, 0}, + &embd.PinDesc{"UART1-RX", []string{"196", "U14-5", "EINT4"}, embd.CapDigital | embd.CapUART, 196, 0}, + &embd.PinDesc{"AP-EINT1", []string{"193", "U14-23", "EINT1"}, embd.CapDigital, 193, 0}, + &embd.PinDesc{"AP-EINT3", []string{"35", "U14-24", "EINT3"}, embd.CapDigital, 35, 0}, + &embd.PinDesc{"TWI2-SDA", []string{"50", "U14-25", "I2C2_SDA"}, embd.CapDigital | embd.CapI2C, 50, 0}, + &embd.PinDesc{"TWI2-SCK", []string{"49", "U14-26", "I2C2_SCK"}, embd.CapDigital | embd.CapI2C, 49, 0}, + &embd.PinDesc{"CSIPCK", []string{"128", "U14-27", "SPI2_SCO", "SPI2_CS0"}, embd.CapDigital | embd.CapSPI, 128, 0}, + &embd.PinDesc{"CSICK", []string{"129", "U14-28", "SPI2_CLK"}, embd.CapDigital | embd.CapSPI, 129, 0}, + &embd.PinDesc{"CSIHSYNC", []string{"130", "U14-29", "SPI2_MOSI"}, embd.CapDigital | embd.CapSPI, 130, 0}, + &embd.PinDesc{"CSIVSYNC", []string{"131", "U14-30", "SPI2_MISO"}, embd.CapDigital | embd.CapSPI, 131, 0}, + &embd.PinDesc{"CSID0", []string{"132", "U14-31"}, embd.CapDigital, 132, 0}, + &embd.PinDesc{"CSID1", []string{"133", "U14-32"}, embd.CapDigital, 133, 0}, + &embd.PinDesc{"CSID2", []string{"134", "U14-33"}, embd.CapDigital, 134, 0}, + &embd.PinDesc{"CSID3", []string{"135", "U14-34"}, embd.CapDigital, 135, 0}, + &embd.PinDesc{"CSID4", []string{"136", "U14-35"}, embd.CapDigital, 136, 0}, + &embd.PinDesc{"CSID5", []string{"137", "U14-36"}, embd.CapDigital, 137, 0}, + &embd.PinDesc{"CSID6", []string{"138", "U14-37", "UART1_TX"}, embd.CapDigital | embd.CapUART, 138, 0}, + &embd.PinDesc{"CSID7", []string{"139", "U14-38", "UART1_RX"}, embd.CapDigital | embd.CapUART, 139, 0}, } func init() { @@ -57,9 +88,9 @@ func init() { I2CDriver: func() embd.I2CDriver { return embd.NewI2CDriver(generic.NewI2CBus) }, - LEDDriver: func() embd.LEDDriver { - return embd.NewLEDDriver(ledMap, generic.NewLED) - }, + //LEDDriver: func() embd.LEDDriver { + // return embd.NewLEDDriver(ledMap, generic.NewLED) + //}, SPIDriver: func() embd.SPIDriver { return embd.NewSPIDriver(spiDeviceMinor, generic.NewSPIBus, nil) }, From 56cb934dbfbea57124e395deebcb3b0f5aadd84b Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Mon, 5 Sep 2016 23:11:12 -0700 Subject: [PATCH 14/27] Update README for CHIP support by TvE --- README.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f37b5b5..94a954a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,22 @@ -# embd [![Build Status](https://travis-ci.org/kidoman/embd.svg?branch=master)](https://travis-ci.org/kidoman/embd) [![GoDoc](http://godoc.org/github.com/kidoman/embd?status.png)](http://godoc.org/github.com/kidoman/embd) +# embd [![Build Status](https://travis-ci.org/tve/embd.svg?branch=master)](https://travis-ci.org/tve/embd) [![GoDoc](http://godoc.org/github.com/tve/embd?status.png)](http://godoc.org/github.com/tve/embd) **embd** is a hardware abstraction layer (HAL) for embedded systems. -It allows you to start your hardware hack on easily available hobby boards (like the Raspberry Pi, BeagleBone Black, etc.) by giving you staight forward access to the board's capabilities as well as a plethora of **sensors** (like accelerometers, gyroscopes, thermometers, etc.) and **controllers** (PWM generators, digital-to-analog convertors) for which we have written drivers. And when things get serious, you dont have to throw away the code. You carry forward the effort onto more custom designed boards where the HAL abstraction of EMBD will save you precious time. +**The github.com/tve/embd fork** attempts to continue the work started by +@kidoman and adds support for NextThing's C.H.I.P. -Development supported and sponsored by [**SoStronk**](https://www.sostronk.com) and [**ThoughtWorks**](http://www.thoughtworks.com/) +It allows you to start your hardware hack on easily available hobby boards +(like the Raspberry Pi, BeagleBone Black, C.H.I.P., etc.) by giving you staight +forward access to the board's capabilities as well as a plethora of +**sensors** (like accelerometers, gyroscopes, thermometers, etc.) and +**controllers** (PWM generators, digital-to-analog convertors) for +which we have written drivers. And when things get serious, you dont +have to throw away the code. You carry forward the effort onto more +custom designed boards where the HAL abstraction of EMBD will save you +precious time. + +Original development supported and sponsored by [**SoStronk**](https://www.sostronk.com) and +[**ThoughtWorks**](http://www.thoughtworks.com/). Also, you might be interested in: [Why Golang?](https://github.com/kidoman/embd/wiki/Why-Go) @@ -12,7 +24,8 @@ Also, you might be interested in: [Why Golang?](https://github.com/kidoman/embd/ ## Getting Started -After installing Go* and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), create your first .go file. We'll call it ```simpleblinker.go```. +After installing Go* and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), +create your first .go file. We'll call it ```simpleblinker.go```. ```go package main @@ -32,9 +45,9 @@ func main() { } ``` -Then install the EMBD package (go1.2 and greater is required): +Then install the EMBD package (go1.6 or greater is required): - $ go get github.com/kidoman/embd + $ go get github.com/tve/embd Build the binary*: @@ -54,11 +67,11 @@ Then run the program with ```sudo```*: *** Notes** -* Please install the cross compilers. Mac users: ```brew install go --cross-compile-common```. [goxc](https://github.com/laher/goxc) can be a big help as well * We are instructing the ```go``` compiler to create a binary which will run on the RaspberryPi processor * Assuming your RaspberryPi has an IP address of ```192.168.2.2```. Substitute as necessary * ```sudo``` (root) permission is required as we are controlling the hardware by writing to special files -* This sample program is optimized for brevity and does not clean up after itself. Click here to see the [full version](https://github.com/kidoman/embd/blob/master/samples/fullblinker.go) +* This sample program is optimized for brevity and does not clean up after itself. Click here to + see the [full version](https://github.com/kidoman/embd/blob/master/samples/fullblinker.go) ## Getting Help @@ -68,6 +81,7 @@ Join the [mailing list](https://groups.google.com/forum/#!forum/go-embd) * [RaspberryPi](http://www.raspberrypi.org/) (including [A+](http://www.raspberrypi.org/products/model-a-plus/) and [B+](http://www.raspberrypi.org/products/model-b-plus/)) * [RaspberryPi 2](http://www.raspberrypi.org/) +* [NextThing C.H.I.P](https://www.nextthing.co/pages/chip) * [BeagleBone Black](http://beagleboard.org/Products/BeagleBone%20Black) * [Intel Edison](http://www.intel.com/content/www/us/en/do-it-yourself/galileo-maker-quark-board.html) **coming soon** * [Radxa](http://radxa.com/) **coming soon** @@ -202,6 +216,40 @@ heading, err := mag.Heading() The above two examples depend on **I2C** and therefore will work without change on almost all platforms. +## Using embd on CHIP + +The CHIP drivers support gpio, I2C, SPI, and pin interrupts. Not supported are PWM or LED. +The names of the pins on chip have multiple aliases. The official CHIP pin names are supported, +for example XIO-P1 or LCD-D2 and the pin number are also supported, such as U14-14 (same as XIO-P1) +or U13-17. Some of the alternate function names are also supported, like "SPI2_MOSI", and the +linux 4.4 kernel gpio pin numbers as well, e.g., 1017 for XIO-P1. Finally, the official GPIO pins +(XIO-P0 thru XIO-P7) can be addressed as gpio0-gpio7. + +A simple demo to blink an LED connected with a small resistor between XIO-P6 and 3.3V is + +``` +package main +import ( + "time" + "github.com/kidoman/embd" + _ "github.com/kidoman/embd/host/chip" +) + +func main() { + embd.InitGPIO() + defer embd.CloseGPIO() + + embd.SetDirection("gpio6", embd.Out) + on := 0 + for { + embd.DigitalWrite("gpio6", on) + on = 1 - on + time.Sleep(250 * time.Millisecond) + } +} +``` +Run it as root: `sudo ./blinky` + ## Protocols Supported * **Digital GPIO** [Documentation](http://godoc.org/github.com/kidoman/embd#DigitalPin) From 6cfa481f30ea3425d5480d4e0d016b75d908d0b4 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Mon, 5 Sep 2016 23:13:14 -0700 Subject: [PATCH 15/27] Support SPI minor devices >255 (PR #33) --- host/bbb/bbb.go | 2 +- host/chip/chip.go | 2 +- host/generic/i2cbus.go | 2 +- host/generic/spibus.go | 4 ++-- host/rpi/rpi.go | 2 +- spidriver.go | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/host/bbb/bbb.go b/host/bbb/bbb.go index f909627..1f42d7d 100644 --- a/host/bbb/bbb.go +++ b/host/bbb/bbb.go @@ -95,7 +95,7 @@ var ledMap = embd.LEDMap{ "beaglebone:green:usr3": []string{"3", "USR3", "usr3"}, } -var spiDeviceMinor byte = 1 +var spiDeviceMinor int = 1 func ensureFeatureEnabled(id string) error { glog.V(3).Infof("bbb: enabling feature %v", id) diff --git a/host/chip/chip.go b/host/chip/chip.go index c6bf7cc..277b72f 100644 --- a/host/chip/chip.go +++ b/host/chip/chip.go @@ -18,7 +18,7 @@ import ( "github.com/kidoman/embd/host/generic" ) -var spiDeviceMinor = byte(0) +var spiDeviceMinor = 32766 var chipPins = embd.PinMap{ // official GPIO pins (U14 connector) using the pcf8574a diff --git a/host/generic/i2cbus.go b/host/generic/i2cbus.go index 45c5870..fbe6f55 100644 --- a/host/generic/i2cbus.go +++ b/host/generic/i2cbus.go @@ -245,7 +245,7 @@ func (b *i2cBus) WriteToReg(addr, reg byte, value []byte) error { message.addr = uint16(addr) message.flags = 0 message.len = uint16(len(outbuf)) - message.buf = uintptr(unsafe.Pointer(&hdrp.Data)) + message.buf = uintptr(unsafe.Pointer(hdrp.Data)) var packets i2c_rdwr_ioctl_data diff --git a/host/generic/spibus.go b/host/generic/spibus.go index ef29c02..a33576f 100644 --- a/host/generic/spibus.go +++ b/host/generic/spibus.go @@ -43,7 +43,7 @@ type spiIOCTransfer struct { type spiBus struct { file *os.File - spiDevMinor byte + spiDevMinor int channel byte mode byte @@ -63,7 +63,7 @@ func spiIOCMessageN(n uint32) uint32 { return (spiIOCMessage0 + (n * spiIOCIncrementor)) } -func NewSPIBus(spiDevMinor, mode, channel byte, speed, bpw, delay int, i func() error) embd.SPIBus { +func NewSPIBus(spiDevMinor int, mode, channel byte, speed, bpw, delay int, i func() error) embd.SPIBus { return &spiBus{ spiDevMinor: spiDevMinor, mode: mode, diff --git a/host/rpi/rpi.go b/host/rpi/rpi.go index 0a82a4b..9279ca8 100644 --- a/host/rpi/rpi.go +++ b/host/rpi/rpi.go @@ -13,7 +13,7 @@ import ( "github.com/kidoman/embd/host/generic" ) -var spiDeviceMinor = byte(0) +var spiDeviceMinor = 0 var rev1Pins = embd.PinMap{ &embd.PinDesc{ID: "P1_3", Aliases: []string{"0", "GPIO_0", "SDA", "I2C0_SDA"}, Caps: embd.CapDigital | embd.CapI2C, DigitalLogical: 0}, diff --git a/spidriver.go b/spidriver.go index cecc19d..a145155 100644 --- a/spidriver.go +++ b/spidriver.go @@ -2,10 +2,10 @@ package embd import "sync" -type spiBusFactory func(byte, byte, byte, int, int, int, func() error) SPIBus +type spiBusFactory func(int, byte, byte, int, int, int, func() error) SPIBus type spiDriver struct { - spiDevMinor byte + spiDevMinor int initializer func() error busMap map[byte]SPIBus @@ -16,7 +16,7 @@ type spiDriver struct { // NewSPIDriver returns a SPIDriver interface which allows control // over the SPI bus. -func NewSPIDriver(spiDevMinor byte, sbf spiBusFactory, i func() error) SPIDriver { +func NewSPIDriver(spiDevMinor int, sbf spiBusFactory, i func() error) SPIDriver { return &spiDriver{ spiDevMinor: spiDevMinor, sbf: sbf, From 997876e74b6b82d668d37e0003ad2f9758161ea1 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Mon, 5 Sep 2016 23:14:12 -0700 Subject: [PATCH 16/27] Initial support for rfm69 radio --- controller/doc.go | 2 + radio/doc.go | 1 + radio/rfm69/README.md | 8 ++ radio/rfm69/registers.go | 68 +++++++++++ radio/rfm69/rfm69.go | 257 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 336 insertions(+) create mode 100644 controller/doc.go create mode 100644 radio/doc.go create mode 100644 radio/rfm69/README.md create mode 100644 radio/rfm69/registers.go create mode 100644 radio/rfm69/rfm69.go diff --git a/controller/doc.go b/controller/doc.go new file mode 100644 index 0000000..01256a5 --- /dev/null +++ b/controller/doc.go @@ -0,0 +1,2 @@ +// Package controller is a container for the various device controllers supported by EMBD. +package controller diff --git a/radio/doc.go b/radio/doc.go new file mode 100644 index 0000000..3e2bdf6 --- /dev/null +++ b/radio/doc.go @@ -0,0 +1 @@ +package radio diff --git a/radio/rfm69/README.md b/radio/rfm69/README.md new file mode 100644 index 0000000..9dcd402 --- /dev/null +++ b/radio/rfm69/README.md @@ -0,0 +1,8 @@ +RFM69 Driver Info +================= + + + +Interesting links +----------------- +- Info about listen mode with low duty cycle: https://lowpowerlab.com/forum/low-power-techniques/ultra-low-power-listening-mode-for-battery-nodes/ diff --git a/radio/rfm69/registers.go b/radio/rfm69/registers.go new file mode 100644 index 0000000..0e2b2e3 --- /dev/null +++ b/radio/rfm69/registers.go @@ -0,0 +1,68 @@ +// Copyright 2016 by Thorsten von Eicken + +package rfm69 + +const ( + REG_FIFO = 0x00 + REG_OPMODE = 0x01 + REG_FRFMSB = 0x07 + REG_PALEVEL = 0x11 + REG_LNAVALUE = 0x18 + REG_AFCMSB = 0x1F + REG_AFCLSB = 0x20 + REG_FEIMSB = 0x21 + REG_FEILSB = 0x22 + REG_RSSIVALUE = 0x24 + REG_IRQFLAGS1 = 0x27 + REG_IRQFLAGS2 = 0x28 + REG_SYNCVALUE1 = 0x2F + REG_SYNCVALUE2 = 0x30 + REG_NODEADDR = 0x39 + REG_BCASTADDR = 0x3A + REG_FIFOTHRESH = 0x3C + REG_PKTCONFIG2 = 0x3D + REG_AESKEYMSB = 0x3E + + MODE_SLEEP = 0 << 2 + MODE_STANDBY = 1 << 2 + MODE_TRANSMIT = 3 << 2 + MODE_RECEIVE = 4 << 2 + + START_TX = 0xC2 + STOP_TX = 0x42 + + RCCALSTART = 0x80 + IRQ1_MODEREADY = 1 << 7 + IRQ1_RXREADY = 1 << 6 + IRQ1_SYNADDRMATCH = 1 << 0 + + IRQ2_FIFONOTEMPTY = 1 << 6 + IRQ2_PACKETSENT = 1 << 3 + IRQ2_PAYLOADREADY = 1 << 2 +) + +// register values to initialize the chip, this array has pairs of +var configRegs = []byte{ + // POR value is better for first rf_sleep 0x01, 0x00, // OpMode = sleep + 0x02, 0x00, // DataModul = packet mode, fsk + 0x03, 0x02, // BitRateMsb, data rate = 49,261 khz + 0x04, 0x8A, // BitRateLsb, divider = 32 MHz / 650 + 0x05, 0x02, // FdevMsb = 45 KHz + 0x06, 0xE1, // FdevLsb = 45 KHz + 0x0B, 0x20, // Low M + 0x19, 0x4A, // RxBw 100 KHz + 0x1A, 0x42, // AfcBw 125 KHz + 0x1E, 0x0C, // AfcAutoclearOn, AfcAutoOn + //0x25, 0x40, //0x80, // DioMapping1 = SyncAddress (Rx) + 0x26, 0x07, // disable clkout + 0x29, 0xA0, // RssiThresh -80 dB + 0x2D, 0x05, // PreambleSize = 5 + 0x2E, 0x88, // SyncConfig = sync on, sync size = 2 + 0x2F, 0x2D, // SyncValue1 = 0x2D + 0x37, 0xD0, // PacketConfig1 = fixed, white, no filtering + 0x38, 0x42, // PayloadLength = 0, unlimited + 0x3C, 0x8F, // FifoTresh, not empty, level 15 + 0x3D, 0x12, // 0x10, // PacketConfig2, interpkt = 1, autorxrestart off + 0x6F, 0x20, // TestDagc ... + 0x71, 0x02, // RegTestAfc +} diff --git a/radio/rfm69/rfm69.go b/radio/rfm69/rfm69.go new file mode 100644 index 0000000..ec2d638 --- /dev/null +++ b/radio/rfm69/rfm69.go @@ -0,0 +1,257 @@ +// Copyright 2016 by Thorsten von Eicken + +// The RFM69 package interfaces with a HopeRF RFM69 radio connected to an SPI bus. In addition, +// an interrupt capable GPIO pin may be used to avoid having to poll the radio. +package rfm69 + +import ( + "fmt" + "log" + + "github.com/kidoman/embd" +) + +// rfm69 represents a HopeRF RFM69 radio +type rfm69 struct { + // configuration + spi embd.SPIBus // bus where the radio is connected + intrPin embd.InterruptPin // interrupt pin for RX and TX interrupts + id byte // my RF ID/address + group byte // RF address of group + freq int // center frequency + parity byte // ??? + // state + mode byte // current operation mode + // info about current RX packet + rxInfo *RxInfo +} + +type Packet struct { + Length uint8 // number of message bytes plus 1 for the address byte + Address uint8 // destination address + Message []byte +} + +type RxInfo struct { + rssi int // rssi value for current packet + lna int // low noise amp gain for current packet + fei int // frequency error for current packet + afc int // frequency correction applied for current packet +} + +// New creates a connection to an rfm69 radio connected to the provided SPI bus and interrupt pin. +// the bufCount determines how many transmit buffers are allocated to allow for the queueing of +// transmit packets. +// For the RFM69 the SPI bus must be set to 10Mhz and mode 0. +func New(bus embd.SPIBus, intr embd.InterruptPin, id, group byte, freq int) *rfm69 { + // bit 7 = b7^b5^b3^b1; bit 6 = b6^b4^b2^b0 + parity := group ^ (group << 4) + parity = (parity ^ (parity << 2)) & 0xc0 + return &rfm69{spi: bus, intrPin: intr, id: id, group: group, freq: freq, parity: parity, + mode: 255} +} + +func (rf *rfm69) writeReg(addr, data byte) error { + buf := []byte{addr | 0x80, data} + return rf.spi.TransferAndReceiveData(buf) +} + +func (rf *rfm69) readReg(addr byte) (byte, error) { + buf := []byte{addr & 0x7f, 0} + err := rf.spi.TransferAndReceiveData(buf) + return buf[1], err +} + +func (rf *rfm69) Init() error { + // try to establish communication with the rfm69 + sync := func(pattern byte) error { + n := 10 + for { + rf.writeReg(REG_SYNCVALUE1, pattern) + v, err := rf.readReg(REG_SYNCVALUE1) + if err != nil { + return err + } + if v == pattern { + return nil + } + if n == 0 { + return fmt.Errorf("Cannot sync with rfm69 chip") + } + n-- + } + } + if err := sync(0xaa); err != nil { + return err + } + if err := sync(0x55); err != nil { + return err + } + + // write the configuration into the registers + for i := 0; i < len(configRegs)-1; i += 2 { + if err := rf.writeReg(configRegs[i], configRegs[i+1]); err != nil { + return err + } + } + + rf.setFrequency(rf.freq) + rf.writeReg(REG_SYNCVALUE2, rf.group) + + if gpio, ok := rf.intrPin.(embd.DigitalPin); ok { + log.Printf("Set intr direction") + gpio.SetDirection(embd.In) + } + if err := rf.intrPin.Watch(embd.EdgeRising, rf.intrHandler); err != nil { + return err + } + + return nil +} + +func (rf *rfm69) setFrequency(freq int) { + // accept any frequency scale as input, including KHz and MHz + // multiply by 10 until freq >= 100 MHz + for freq > 0 && freq < 100000000 { + freq = freq * 10 + } + + // Frequency steps are in units of (32,000,000 >> 19) = 61.03515625 Hz + // use multiples of 64 to avoid multi-precision arithmetic, i.e. 3906.25 Hz + // due to this, the lower 6 bits of the calculated factor will always be 0 + // this is still 4 ppm, i.e. well below the radio's 32 MHz crystal accuracy + // 868.0 MHz = 0xD90000, 868.3 MHz = 0xD91300, 915.0 MHz = 0xE4C000 + frf := (freq << 2) / (32000000 >> 11) + rf.writeReg(REG_FRFMSB, byte(frf>>10)) + rf.writeReg(REG_FRFMSB+1, byte(frf>>2)) + rf.writeReg(REG_FRFMSB+2, byte(frf<<6)) +} + +func (rf *rfm69) setMode(mode byte) error { + reg, err := rf.readReg(REG_OPMODE) + if err != nil { + return err + } + reg = (reg & 0xE3) | mode + err = rf.writeReg(REG_OPMODE, reg) + if err != nil { + return err + } + for { + val, err := rf.readReg(REG_IRQFLAGS1) + if err != nil { + rf.mode = 255 + return err + } + if val&IRQ1_MODEREADY != 0 { + rf.mode = mode + return nil + } + } +} + +func (rf *rfm69) Send(header byte, message []byte) error { + if len(message) > 62 { + return fmt.Errorf("message too long") + } + rf.setMode(MODE_SLEEP) + + buf := make([]byte, len(message)+4) + buf[0] = REG_FIFO | 0x80 + buf[1] = byte(len(message) + 2) + buf[2] = (header & 0x3f) | rf.parity + buf[3] = (header & 0xC0) | rf.id + copy(buf[4:], message) + err := rf.spi.TransferAndReceiveData(buf) + if err != nil { + return err + } + rf.setMode(MODE_TRANSMIT) + for { + val, err := rf.readReg(REG_IRQFLAGS2) + if err != nil { + return err + } + if val&IRQ2_PACKETSENT != 0 { + break + } + } + rf.setMode(MODE_STANDBY) + return nil +} + +func (rf *rfm69) readInfo() *RxInfo { + // collect rxinfo, start with rssi + rxInfo := &RxInfo{} + rssi, _ := rf.readReg(REG_RSSIVALUE) + rxInfo.rssi = 0 - int(rssi)/2 + // low noise amp gain + lna, _ := rf.readReg(REG_LNAVALUE) + rxInfo.lna = int((lna >> 3) & 0x7) + // auto freq correction applied, caution: signed value + buf := []byte{REG_AFCMSB, 0, 0} + rf.spi.TransferAndReceiveData(buf) + rxInfo.afc = int(int8(buf[1]))<<8 | int(buf[2]) + // freq error detected, caution: signed value + buf = []byte{REG_FEIMSB, 0, 0} + rf.spi.TransferAndReceiveData(buf) + rxInfo.fei = int(int8(buf[1]))<<8 | int(buf[2]) + return rxInfo +} + +func (rf *rfm69) Receive() (header byte, message []byte, info *RxInfo, err error) { + // if we're not in receive mode, then switch, this also flushes the FIFO + if rf.mode != MODE_RECEIVE { + rf.setMode(MODE_RECEIVE) + return + } + + // if we don't have rxinfo check whether we have RX_READY, which means that we've + // started receiving a packet so we can collect info + if rf.rxInfo == nil { + irq1, err := rf.readReg(REG_IRQFLAGS1) + if err != nil { + return 0, nil, nil, err + } + if irq1&IRQ1_RXREADY != 0 { + rf.rxInfo = rf.readInfo() + } + } + + // see whether we have a full packet + irq2, err := rf.readReg(REG_IRQFLAGS2) + if err != nil { + return 0, nil, nil, err + } + if irq2&IRQ2_PAYLOADREADY == 0 { + return + } + i2 := rf.readInfo() + if rf.rxInfo != nil && i2 != nil && + (rf.rxInfo.rssi != i2.rssi || rf.rxInfo.lna != i2.lna || + rf.rxInfo.afc != i2.afc || rf.rxInfo.fei != i2.fei) { + fmt.Printf("\nrxInfo mismatch: %+v vs %+v\n", *rf.rxInfo, *i2) + } + // got packet, read it by fetching the entire FIFO, should be faster than first + // looking at the length + buf := make([]byte, 67) + buf[0] = REG_FIFO + err = rf.spi.TransferAndReceiveData(buf) + if err != nil { + return 0, nil, nil, err + } + // return the packet + info = rf.rxInfo + rf.rxInfo = nil + l := buf[1] + if l > 66 { + l = 66 // or error? + } + header = buf[2] + message = buf[3 : 2+l] + return +} + +func (rf *rfm69) intrHandler(pin embd.DigitalPin) { + log.Printf("Interrupt called!") +} From b6706df9a8525e587eb72be1a833cc59c512611b Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Tue, 6 Sep 2016 21:07:08 -0700 Subject: [PATCH 17/27] make fork ready for merge-back --- README.md | 39 +-------------------------------------- host/chip/README.md | 34 ++++++++++++++++++++++++++++++++++ host/chip/chip.go | 2 +- radio/rfm69/registers.go | 2 +- radio/rfm69/rfm69.go | 2 +- 5 files changed, 38 insertions(+), 41 deletions(-) create mode 100644 host/chip/README.md diff --git a/README.md b/README.md index 94a954a..a7396b8 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,7 @@ -# embd [![Build Status](https://travis-ci.org/tve/embd.svg?branch=master)](https://travis-ci.org/tve/embd) [![GoDoc](http://godoc.org/github.com/tve/embd?status.png)](http://godoc.org/github.com/tve/embd) +# embd [![Build Status](https://travis-ci.org/kidoman/embd.svg?branch=master)](https://travis-ci.org/kidoman/embd) [![GoDoc](http://godoc.org/github.com/kidoman/embd?status.png)](http://godoc.org/github.com/kidoman/embd) **embd** is a hardware abstraction layer (HAL) for embedded systems. -**The github.com/tve/embd fork** attempts to continue the work started by -@kidoman and adds support for NextThing's C.H.I.P. - It allows you to start your hardware hack on easily available hobby boards (like the Raspberry Pi, BeagleBone Black, C.H.I.P., etc.) by giving you staight forward access to the board's capabilities as well as a plethora of @@ -216,40 +213,6 @@ heading, err := mag.Heading() The above two examples depend on **I2C** and therefore will work without change on almost all platforms. -## Using embd on CHIP - -The CHIP drivers support gpio, I2C, SPI, and pin interrupts. Not supported are PWM or LED. -The names of the pins on chip have multiple aliases. The official CHIP pin names are supported, -for example XIO-P1 or LCD-D2 and the pin number are also supported, such as U14-14 (same as XIO-P1) -or U13-17. Some of the alternate function names are also supported, like "SPI2_MOSI", and the -linux 4.4 kernel gpio pin numbers as well, e.g., 1017 for XIO-P1. Finally, the official GPIO pins -(XIO-P0 thru XIO-P7) can be addressed as gpio0-gpio7. - -A simple demo to blink an LED connected with a small resistor between XIO-P6 and 3.3V is - -``` -package main -import ( - "time" - "github.com/kidoman/embd" - _ "github.com/kidoman/embd/host/chip" -) - -func main() { - embd.InitGPIO() - defer embd.CloseGPIO() - - embd.SetDirection("gpio6", embd.Out) - on := 0 - for { - embd.DigitalWrite("gpio6", on) - on = 1 - on - time.Sleep(250 * time.Millisecond) - } -} -``` -Run it as root: `sudo ./blinky` - ## Protocols Supported * **Digital GPIO** [Documentation](http://godoc.org/github.com/kidoman/embd#DigitalPin) diff --git a/host/chip/README.md b/host/chip/README.md new file mode 100644 index 0000000..51fd49e --- /dev/null +++ b/host/chip/README.md @@ -0,0 +1,34 @@ +# Using embd on CHIP + +The CHIP drivers support gpio, I2C, SPI, and pin interrupts. Not supported are PWM or LED. +The names of the pins on chip have multiple aliases. The official CHIP pin names are supported, +for example XIO-P1 or LCD-D2 and the pin number are also supported, such as U14-14 (same as XIO-P1) +or U13-17. Some of the alternate function names are also supported, like "SPI2_MOSI", and the +linux 4.4 kernel gpio pin numbers as well, e.g., 1017 for XIO-P1. Finally, the official GPIO pins +(XIO-P0 thru XIO-P7) can be addressed as gpio0-gpio7. + +A simple demo to blink an LED connected with a small resistor between XIO-P6 and 3.3V is + +``` +package main +import ( + "time" + "github.com/kidoman/embd" + _ "github.com/kidoman/embd/host/chip" +) + +func main() { + embd.InitGPIO() + defer embd.CloseGPIO() + + embd.SetDirection("gpio6", embd.Out) + on := 0 + for { + embd.DigitalWrite("gpio6", on) + on = 1 - on + time.Sleep(250 * time.Millisecond) + } +} +``` +Run it as root: `sudo ./blinky` + diff --git a/host/chip/chip.go b/host/chip/chip.go index 277b72f..d849df4 100644 --- a/host/chip/chip.go +++ b/host/chip/chip.go @@ -1,4 +1,4 @@ -// Copyright 2016 by Thorsten von Eicken +// Copyright 2016 by Thorsten von Eicken, see LICENSE file // Package chip provides NextThing C.H.I.P. support. // References: diff --git a/radio/rfm69/registers.go b/radio/rfm69/registers.go index 0e2b2e3..94e2a73 100644 --- a/radio/rfm69/registers.go +++ b/radio/rfm69/registers.go @@ -1,4 +1,4 @@ -// Copyright 2016 by Thorsten von Eicken +// Copyright 2016 by Thorsten von Eicken, see LICENSE file package rfm69 diff --git a/radio/rfm69/rfm69.go b/radio/rfm69/rfm69.go index ec2d638..15029b6 100644 --- a/radio/rfm69/rfm69.go +++ b/radio/rfm69/rfm69.go @@ -1,4 +1,4 @@ -// Copyright 2016 by Thorsten von Eicken +// Copyright 2016 by Thorsten von Eicken, see LICENSE file // The RFM69 package interfaces with a HopeRF RFM69 radio connected to an SPI bus. In addition, // an interrupt capable GPIO pin may be used to avoid having to poll the radio. From 789e3f82b2ca9146700c87a08a48e0f8499b86e8 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Tue, 6 Sep 2016 21:12:17 -0700 Subject: [PATCH 18/27] make fork ready for merge-back, try #2 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a7396b8..1bc5e08 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ **embd** is a hardware abstraction layer (HAL) for embedded systems. It allows you to start your hardware hack on easily available hobby boards -(like the Raspberry Pi, BeagleBone Black, C.H.I.P., etc.) by giving you staight -forward access to the board's capabilities as well as a plethora of +(like the Raspberry Pi, BeagleBone Black, C.H.I.P., etc.) by giving you +straight-forward access to the board's capabilities as well as a plethora of **sensors** (like accelerometers, gyroscopes, thermometers, etc.) and **controllers** (PWM generators, digital-to-analog convertors) for which we have written drivers. And when things get serious, you dont @@ -12,7 +12,7 @@ have to throw away the code. You carry forward the effort onto more custom designed boards where the HAL abstraction of EMBD will save you precious time. -Original development supported and sponsored by [**SoStronk**](https://www.sostronk.com) and +Development supported and sponsored by [**SoStronk**](https://www.sostronk.com) and [**ThoughtWorks**](http://www.thoughtworks.com/). Also, you might be interested in: [Why Golang?](https://github.com/kidoman/embd/wiki/Why-Go) From e19d72b27bf87a65287313b1eee5285383e73106 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Tue, 6 Sep 2016 21:13:16 -0700 Subject: [PATCH 19/27] make fork ready for merge-back, try #3 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1bc5e08..932be11 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ func main() { Then install the EMBD package (go1.6 or greater is required): - $ go get github.com/tve/embd + $ go get github.com/kidoman/embd Build the binary*: From acf38b972d836b77c09fc755e5710ff69d86d795 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 8 Sep 2016 21:02:34 -0700 Subject: [PATCH 20/27] Back out addition of rfm69 radio support 'cause it's not ready --- radio/doc.go | 1 - radio/rfm69/README.md | 8 -- radio/rfm69/registers.go | 68 ----------- radio/rfm69/rfm69.go | 257 --------------------------------------- 4 files changed, 334 deletions(-) delete mode 100644 radio/doc.go delete mode 100644 radio/rfm69/README.md delete mode 100644 radio/rfm69/registers.go delete mode 100644 radio/rfm69/rfm69.go diff --git a/radio/doc.go b/radio/doc.go deleted file mode 100644 index 3e2bdf6..0000000 --- a/radio/doc.go +++ /dev/null @@ -1 +0,0 @@ -package radio diff --git a/radio/rfm69/README.md b/radio/rfm69/README.md deleted file mode 100644 index 9dcd402..0000000 --- a/radio/rfm69/README.md +++ /dev/null @@ -1,8 +0,0 @@ -RFM69 Driver Info -================= - - - -Interesting links ------------------ -- Info about listen mode with low duty cycle: https://lowpowerlab.com/forum/low-power-techniques/ultra-low-power-listening-mode-for-battery-nodes/ diff --git a/radio/rfm69/registers.go b/radio/rfm69/registers.go deleted file mode 100644 index 94e2a73..0000000 --- a/radio/rfm69/registers.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2016 by Thorsten von Eicken, see LICENSE file - -package rfm69 - -const ( - REG_FIFO = 0x00 - REG_OPMODE = 0x01 - REG_FRFMSB = 0x07 - REG_PALEVEL = 0x11 - REG_LNAVALUE = 0x18 - REG_AFCMSB = 0x1F - REG_AFCLSB = 0x20 - REG_FEIMSB = 0x21 - REG_FEILSB = 0x22 - REG_RSSIVALUE = 0x24 - REG_IRQFLAGS1 = 0x27 - REG_IRQFLAGS2 = 0x28 - REG_SYNCVALUE1 = 0x2F - REG_SYNCVALUE2 = 0x30 - REG_NODEADDR = 0x39 - REG_BCASTADDR = 0x3A - REG_FIFOTHRESH = 0x3C - REG_PKTCONFIG2 = 0x3D - REG_AESKEYMSB = 0x3E - - MODE_SLEEP = 0 << 2 - MODE_STANDBY = 1 << 2 - MODE_TRANSMIT = 3 << 2 - MODE_RECEIVE = 4 << 2 - - START_TX = 0xC2 - STOP_TX = 0x42 - - RCCALSTART = 0x80 - IRQ1_MODEREADY = 1 << 7 - IRQ1_RXREADY = 1 << 6 - IRQ1_SYNADDRMATCH = 1 << 0 - - IRQ2_FIFONOTEMPTY = 1 << 6 - IRQ2_PACKETSENT = 1 << 3 - IRQ2_PAYLOADREADY = 1 << 2 -) - -// register values to initialize the chip, this array has pairs of -var configRegs = []byte{ - // POR value is better for first rf_sleep 0x01, 0x00, // OpMode = sleep - 0x02, 0x00, // DataModul = packet mode, fsk - 0x03, 0x02, // BitRateMsb, data rate = 49,261 khz - 0x04, 0x8A, // BitRateLsb, divider = 32 MHz / 650 - 0x05, 0x02, // FdevMsb = 45 KHz - 0x06, 0xE1, // FdevLsb = 45 KHz - 0x0B, 0x20, // Low M - 0x19, 0x4A, // RxBw 100 KHz - 0x1A, 0x42, // AfcBw 125 KHz - 0x1E, 0x0C, // AfcAutoclearOn, AfcAutoOn - //0x25, 0x40, //0x80, // DioMapping1 = SyncAddress (Rx) - 0x26, 0x07, // disable clkout - 0x29, 0xA0, // RssiThresh -80 dB - 0x2D, 0x05, // PreambleSize = 5 - 0x2E, 0x88, // SyncConfig = sync on, sync size = 2 - 0x2F, 0x2D, // SyncValue1 = 0x2D - 0x37, 0xD0, // PacketConfig1 = fixed, white, no filtering - 0x38, 0x42, // PayloadLength = 0, unlimited - 0x3C, 0x8F, // FifoTresh, not empty, level 15 - 0x3D, 0x12, // 0x10, // PacketConfig2, interpkt = 1, autorxrestart off - 0x6F, 0x20, // TestDagc ... - 0x71, 0x02, // RegTestAfc -} diff --git a/radio/rfm69/rfm69.go b/radio/rfm69/rfm69.go deleted file mode 100644 index 15029b6..0000000 --- a/radio/rfm69/rfm69.go +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright 2016 by Thorsten von Eicken, see LICENSE file - -// The RFM69 package interfaces with a HopeRF RFM69 radio connected to an SPI bus. In addition, -// an interrupt capable GPIO pin may be used to avoid having to poll the radio. -package rfm69 - -import ( - "fmt" - "log" - - "github.com/kidoman/embd" -) - -// rfm69 represents a HopeRF RFM69 radio -type rfm69 struct { - // configuration - spi embd.SPIBus // bus where the radio is connected - intrPin embd.InterruptPin // interrupt pin for RX and TX interrupts - id byte // my RF ID/address - group byte // RF address of group - freq int // center frequency - parity byte // ??? - // state - mode byte // current operation mode - // info about current RX packet - rxInfo *RxInfo -} - -type Packet struct { - Length uint8 // number of message bytes plus 1 for the address byte - Address uint8 // destination address - Message []byte -} - -type RxInfo struct { - rssi int // rssi value for current packet - lna int // low noise amp gain for current packet - fei int // frequency error for current packet - afc int // frequency correction applied for current packet -} - -// New creates a connection to an rfm69 radio connected to the provided SPI bus and interrupt pin. -// the bufCount determines how many transmit buffers are allocated to allow for the queueing of -// transmit packets. -// For the RFM69 the SPI bus must be set to 10Mhz and mode 0. -func New(bus embd.SPIBus, intr embd.InterruptPin, id, group byte, freq int) *rfm69 { - // bit 7 = b7^b5^b3^b1; bit 6 = b6^b4^b2^b0 - parity := group ^ (group << 4) - parity = (parity ^ (parity << 2)) & 0xc0 - return &rfm69{spi: bus, intrPin: intr, id: id, group: group, freq: freq, parity: parity, - mode: 255} -} - -func (rf *rfm69) writeReg(addr, data byte) error { - buf := []byte{addr | 0x80, data} - return rf.spi.TransferAndReceiveData(buf) -} - -func (rf *rfm69) readReg(addr byte) (byte, error) { - buf := []byte{addr & 0x7f, 0} - err := rf.spi.TransferAndReceiveData(buf) - return buf[1], err -} - -func (rf *rfm69) Init() error { - // try to establish communication with the rfm69 - sync := func(pattern byte) error { - n := 10 - for { - rf.writeReg(REG_SYNCVALUE1, pattern) - v, err := rf.readReg(REG_SYNCVALUE1) - if err != nil { - return err - } - if v == pattern { - return nil - } - if n == 0 { - return fmt.Errorf("Cannot sync with rfm69 chip") - } - n-- - } - } - if err := sync(0xaa); err != nil { - return err - } - if err := sync(0x55); err != nil { - return err - } - - // write the configuration into the registers - for i := 0; i < len(configRegs)-1; i += 2 { - if err := rf.writeReg(configRegs[i], configRegs[i+1]); err != nil { - return err - } - } - - rf.setFrequency(rf.freq) - rf.writeReg(REG_SYNCVALUE2, rf.group) - - if gpio, ok := rf.intrPin.(embd.DigitalPin); ok { - log.Printf("Set intr direction") - gpio.SetDirection(embd.In) - } - if err := rf.intrPin.Watch(embd.EdgeRising, rf.intrHandler); err != nil { - return err - } - - return nil -} - -func (rf *rfm69) setFrequency(freq int) { - // accept any frequency scale as input, including KHz and MHz - // multiply by 10 until freq >= 100 MHz - for freq > 0 && freq < 100000000 { - freq = freq * 10 - } - - // Frequency steps are in units of (32,000,000 >> 19) = 61.03515625 Hz - // use multiples of 64 to avoid multi-precision arithmetic, i.e. 3906.25 Hz - // due to this, the lower 6 bits of the calculated factor will always be 0 - // this is still 4 ppm, i.e. well below the radio's 32 MHz crystal accuracy - // 868.0 MHz = 0xD90000, 868.3 MHz = 0xD91300, 915.0 MHz = 0xE4C000 - frf := (freq << 2) / (32000000 >> 11) - rf.writeReg(REG_FRFMSB, byte(frf>>10)) - rf.writeReg(REG_FRFMSB+1, byte(frf>>2)) - rf.writeReg(REG_FRFMSB+2, byte(frf<<6)) -} - -func (rf *rfm69) setMode(mode byte) error { - reg, err := rf.readReg(REG_OPMODE) - if err != nil { - return err - } - reg = (reg & 0xE3) | mode - err = rf.writeReg(REG_OPMODE, reg) - if err != nil { - return err - } - for { - val, err := rf.readReg(REG_IRQFLAGS1) - if err != nil { - rf.mode = 255 - return err - } - if val&IRQ1_MODEREADY != 0 { - rf.mode = mode - return nil - } - } -} - -func (rf *rfm69) Send(header byte, message []byte) error { - if len(message) > 62 { - return fmt.Errorf("message too long") - } - rf.setMode(MODE_SLEEP) - - buf := make([]byte, len(message)+4) - buf[0] = REG_FIFO | 0x80 - buf[1] = byte(len(message) + 2) - buf[2] = (header & 0x3f) | rf.parity - buf[3] = (header & 0xC0) | rf.id - copy(buf[4:], message) - err := rf.spi.TransferAndReceiveData(buf) - if err != nil { - return err - } - rf.setMode(MODE_TRANSMIT) - for { - val, err := rf.readReg(REG_IRQFLAGS2) - if err != nil { - return err - } - if val&IRQ2_PACKETSENT != 0 { - break - } - } - rf.setMode(MODE_STANDBY) - return nil -} - -func (rf *rfm69) readInfo() *RxInfo { - // collect rxinfo, start with rssi - rxInfo := &RxInfo{} - rssi, _ := rf.readReg(REG_RSSIVALUE) - rxInfo.rssi = 0 - int(rssi)/2 - // low noise amp gain - lna, _ := rf.readReg(REG_LNAVALUE) - rxInfo.lna = int((lna >> 3) & 0x7) - // auto freq correction applied, caution: signed value - buf := []byte{REG_AFCMSB, 0, 0} - rf.spi.TransferAndReceiveData(buf) - rxInfo.afc = int(int8(buf[1]))<<8 | int(buf[2]) - // freq error detected, caution: signed value - buf = []byte{REG_FEIMSB, 0, 0} - rf.spi.TransferAndReceiveData(buf) - rxInfo.fei = int(int8(buf[1]))<<8 | int(buf[2]) - return rxInfo -} - -func (rf *rfm69) Receive() (header byte, message []byte, info *RxInfo, err error) { - // if we're not in receive mode, then switch, this also flushes the FIFO - if rf.mode != MODE_RECEIVE { - rf.setMode(MODE_RECEIVE) - return - } - - // if we don't have rxinfo check whether we have RX_READY, which means that we've - // started receiving a packet so we can collect info - if rf.rxInfo == nil { - irq1, err := rf.readReg(REG_IRQFLAGS1) - if err != nil { - return 0, nil, nil, err - } - if irq1&IRQ1_RXREADY != 0 { - rf.rxInfo = rf.readInfo() - } - } - - // see whether we have a full packet - irq2, err := rf.readReg(REG_IRQFLAGS2) - if err != nil { - return 0, nil, nil, err - } - if irq2&IRQ2_PAYLOADREADY == 0 { - return - } - i2 := rf.readInfo() - if rf.rxInfo != nil && i2 != nil && - (rf.rxInfo.rssi != i2.rssi || rf.rxInfo.lna != i2.lna || - rf.rxInfo.afc != i2.afc || rf.rxInfo.fei != i2.fei) { - fmt.Printf("\nrxInfo mismatch: %+v vs %+v\n", *rf.rxInfo, *i2) - } - // got packet, read it by fetching the entire FIFO, should be faster than first - // looking at the length - buf := make([]byte, 67) - buf[0] = REG_FIFO - err = rf.spi.TransferAndReceiveData(buf) - if err != nil { - return 0, nil, nil, err - } - // return the packet - info = rf.rxInfo - rf.rxInfo = nil - l := buf[1] - if l > 66 { - l = 66 // or error? - } - header = buf[2] - message = buf[3 : 2+l] - return -} - -func (rf *rfm69) intrHandler(pin embd.DigitalPin) { - log.Printf("Interrupt called!") -} From 94cc116a8139a70a4e08fc40c65f161f1df7dc97 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 8 Sep 2016 21:15:09 -0700 Subject: [PATCH 21/27] update contributors --- CONTRIBUTORS | 15 ++++++++++++--- update_contibutors.sh | 4 +++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index f44d830..e3ca3e1 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,8 +1,17 @@ -Karan Misra +adeschamps +alsm +Al S-M +Ben Delarre +Ben Schwartz +Gavin Cabbage +gotang Kashyap Kopparam Kunal Powar Marco P. Monteiro +Matthew Dale Nikesh Vora +SjB Steve Beaulac -Al S-M -Ben Delarre +Thorsten von Eicken +wiless +Wu Jiang diff --git a/update_contibutors.sh b/update_contibutors.sh index adde090..1446108 100755 --- a/update_contibutors.sh +++ b/update_contibutors.sh @@ -1,3 +1,5 @@ #!/usr/bin/env bash -git log --all --format='%cN <%cE>' | sort -u | grep -v karan.misra@gmail.com > CONTRIBUTORS +git log --all --format='%cN <%cE>' | sort -u | grep -v karan.misra@gmail.com |\ + grep -v noreply@ | cat CONTRIBUTORS - | sort | uniq > CONTRIBUTORS.new +mv CONTRIBUTORS.new CONTRIBUTORS From b013125381e9ce2d7ddfb01bcee269619617f957 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 8 Sep 2016 22:50:29 -0700 Subject: [PATCH 22/27] update documentation a bit --- .travis.yml | 7 ++- README.md | 45 ++++++----------- doc.go | 140 ++++++++++++++++++++++++++-------------------------- 3 files changed, 89 insertions(+), 103 deletions(-) diff --git a/.travis.yml b/.travis.yml index 14c3702..4fdf33a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,11 +5,10 @@ branches: - go-rpi go: - - 1.2.2 - - 1.3.3 - - 1.4 - - tip + - 1.6 + - 1.7 script: - go test -bench=. -v ./... | grep -v 'no test files' ; test ${PIPESTATUS[0]} -eq 0 - cd samples; find . -name "*.go" -print0 | xargs -0 -n1 go build + - cd embd; go build . diff --git a/README.md b/README.md index 932be11..b47e533 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,9 @@ It allows you to start your hardware hack on easily available hobby boards straight-forward access to the board's capabilities as well as a plethora of **sensors** (like accelerometers, gyroscopes, thermometers, etc.) and **controllers** (PWM generators, digital-to-analog convertors) for -which we have written drivers. And when things get serious, you dont -have to throw away the code. You carry forward the effort onto more -custom designed boards where the HAL abstraction of EMBD will save you -precious time. +which it includes drivers. If you move to custom designed boards +you have to throw away your code: you carry forward the effort +where the HAL abstraction of EMBD will save you precious time. Development supported and sponsored by [**SoStronk**](https://www.sostronk.com) and [**ThoughtWorks**](http://www.thoughtworks.com/). @@ -21,8 +20,9 @@ Also, you might be interested in: [Why Golang?](https://github.com/kidoman/embd/ ## Getting Started -After installing Go* and setting up your [GOPATH](http://golang.org/doc/code.html#GOPATH), -create your first .go file. We'll call it ```simpleblinker.go```. +Install Go version 1.6 or later to make compiling for ARM easy. +The set up your [GOPATH](http://golang.org/doc/code.html#GOPATH), +and create your first .go file. We'll call it `simpleblinker.go`. ```go package main @@ -42,11 +42,11 @@ func main() { } ``` -Then install the EMBD package (go1.6 or greater is required): +Then install the EMBD package: $ go get github.com/kidoman/embd -Build the binary*: +Build the binary for linux/ARM: $ export GOOS=linux $ export GOARCH=arm @@ -56,7 +56,7 @@ Copy the cross-compiled binary to your RaspberryPi*: $ scp simpleblinker pi@192.168.2.2:~ -Then run the program with ```sudo```*: +Then on the rPi run the program with ```sudo```*: $ sudo ./simpleblinker @@ -64,15 +64,14 @@ Then run the program with ```sudo```*: *** Notes** -* We are instructing the ```go``` compiler to create a binary which will run on the RaspberryPi processor * Assuming your RaspberryPi has an IP address of ```192.168.2.2```. Substitute as necessary -* ```sudo``` (root) permission is required as we are controlling the hardware by writing to special files +* `sudo` (root) permission is required as we are controlling the hardware by writing to special files * This sample program is optimized for brevity and does not clean up after itself. Click here to see the [full version](https://github.com/kidoman/embd/blob/master/samples/fullblinker.go) ## Getting Help -Join the [mailing list](https://groups.google.com/forum/#!forum/go-embd) +Join the [slack channel](https://gophers.slack.com/archives/embd) ## Platforms Supported @@ -80,10 +79,6 @@ Join the [mailing list](https://groups.google.com/forum/#!forum/go-embd) * [RaspberryPi 2](http://www.raspberrypi.org/) * [NextThing C.H.I.P](https://www.nextthing.co/pages/chip) * [BeagleBone Black](http://beagleboard.org/Products/BeagleBone%20Black) -* [Intel Edison](http://www.intel.com/content/www/us/en/do-it-yourself/galileo-maker-quark-board.html) **coming soon** -* [Radxa](http://radxa.com/) **coming soon** -* [Cubietruck](http://www.cubietruck.com/) **coming soon** -* Bring Your Own **coming soon** ## The command line tool @@ -91,8 +86,6 @@ Join the [mailing list](https://groups.google.com/forum/#!forum/go-embd) will install a command line utility ```embd``` which will allow you to quickly get started with prototyping. The binary should be available in your ```$GOPATH/bin```. However, to be able to run this on a ARM based device, you will need to build it with ```GOOS=linux``` and ```GOARCH=arm``` environment variables set. -But, since I am feeling so generous, a prebuilt/tested version is available for direct download and deployment [here](https://dl.dropboxusercontent.com/u/6727135/Binaries/embd/linux-arm/embd). - For example, if you run ```embd detect``` on a **BeagleBone Black**: root@beaglebone:~# embd detect @@ -225,17 +218,11 @@ platforms. ## Sensors Supported * **TMP006** Thermopile sensor [Documentation](http://godoc.org/github.com/kidoman/embd/sensor/tmp006), [Datasheet](http://www.adafruit.com/datasheets/tmp006.pdf), [Userguide](http://www.adafruit.com/datasheets/tmp006ug.pdf) - * **BMP085** Barometric pressure sensor [Documentation](http://godoc.org/github.com/kidoman/embd/sensor/bmp085), [Datasheet](https://www.sparkfun.com/datasheets/Components/General/BST-BMP085-DS000-05.pdf) - * **BMP180** Barometric pressure sensor [Documentation](http://godoc.org/github.com/kidoman/embd/sensor/bmp180), [Datasheet](http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf) - * **LSM303** Accelerometer and magnetometer [Documentation](http://godoc.org/github.com/kidoman/embd/sensor/lsm303), [Datasheet](https://www.sparkfun.com/datasheets/Sensors/Magneto/LSM303%20Datasheet.pdf) - * **L3GD20** Gyroscope [Documentation](http://godoc.org/github.com/kidoman/embd/sensor/l3gd20), [Datasheet](http://www.adafruit.com/datasheets/L3GD20.pdf) - * **US020** Ultrasonic proximity sensor [Documentation](http://godoc.org/github.com/kidoman/embd/sensor/us020), [Product Page](http://www.digibay.in/sensor/object-detection-and-proximity?product_id=239) - * **BH1750FVI** Luminosity sensor [Documentation](http://godoc.org/github.com/kidoman/embd/sensor/bh1750fvi), [Datasheet](http://www.elechouse.com/elechouse/images/product/Digital%20light%20Sensor/bh1750fvi-e.pdf) ## Interfaces @@ -245,9 +232,7 @@ platforms. ## Controllers * **PCA9685** 16-channel, 12-bit PWM Controller with I2C protocol [Documentation](http://godoc.org/github.com/kidoman/embd/controller/pca9685), [Datasheet](http://www.adafruit.com/datasheets/PCA9685.pdf), [Product Page](http://www.adafruit.com/products/815) - * **MCP4725** 12-bit DAC [Documentation](http://godoc.org/github.com/kidoman/embd/controller/mcp4725), [Datasheet](http://www.adafruit.com/datasheets/mcp4725.pdf), [Product Page](http://www.adafruit.com/products/935) - * **ServoBlaster** RPi PWM/PCM based PWM controller [Documentation](http://godoc.org/github.com/kidoman/embd/controller/servoblaster), [Product Page](https://github.com/richardghirst/PiBits/tree/master/ServoBlaster) ## Convertors @@ -256,9 +241,11 @@ platforms. ## Contributing -We look forward to your pull requests, but contributions which abide by the [guidelines](https://github.com/kidoman/embd/blob/master/CONTRIBUTING.md) will get a free beer! - -File an [issue](https://github.com/kidoman/embd/issues), open a [pull request](https://github.com/kidoman/embd/pulls). We are waiting. +[Pull requests](https://github.com/kidoman/embd/pulls) that follow the +[guidelines](https://github.com/kidoman/embd/blob/master/CONTRIBUTING.md) are very appreciated. +If you find a problem but are not up to coding a fix please file an +[issue](https://github.com/kidoman/embd/issues). +Thank you! ## About diff --git a/doc.go b/doc.go index 80118d4..761f0e3 100644 --- a/doc.go +++ b/doc.go @@ -1,88 +1,88 @@ -/* - Package embd provides a hardware abstraction layer for doing embedded programming - on supported platforms like the Raspberry Pi and BeagleBone Black. Most of the examples below - will work without change (i.e. the same binary) on all supported platforms. How cool is that? +/* doc +Package embd provides a hardware abstraction layer for doing embedded programming +on supported platforms like the Raspberry Pi and BeagleBone Black. Most of the examples below +will work without change (i.e. the same binary) on all supported platforms. How cool is that? - Although samples are all present in the samples folder, we will show a few choice examples here. +Although samples are all present in the samples folder, we will show a few choice examples here. - Use the LED driver to toggle LEDs on the BBB: +Use the LED driver to toggle LEDs on the BBB: - import "github.com/kidoman/embd" - ... - embd.InitLED() - defer embd.CloseLED() - ... - led, err := embd.NewLED("USR3") - ... - led.Toggle() + import "github.com/kidoman/embd" + ... + embd.InitLED() + defer embd.CloseLED() + ... + led, err := embd.NewLED("USR3") + ... + led.Toggle() - Even shorter while prototyping: +Even shorter while prototyping: - import "github.com/kidoman/embd" - ... - embd.InitLED() - defer embd.CloseLED() - ... - embd.ToggleLED(3) + import "github.com/kidoman/embd" + ... + embd.InitLED() + defer embd.CloseLED() + ... + embd.ToggleLED(3) - BBB + PWM: +BBB + PWM: - import "github.com/kidoman/embd" - ... - embd.InitGPIO() - defer embd.CloseGPIO() - ... - pwm, _ := embd.NewPWMPin("P9_14") - defer pwm.Close() - ... - pwm.SetDuty(1000) + import "github.com/kidoman/embd" + ... + embd.InitGPIO() + defer embd.CloseGPIO() + ... + pwm, _ := embd.NewPWMPin("P9_14") + defer pwm.Close() + ... + pwm.SetDuty(1000) - Control GPIO pins on the RaspberryPi / BeagleBone Black: +Control GPIO pins on the RaspberryPi / BeagleBone Black: - import "github.com/kidoman/embd" - ... - embd.InitGPIO() - defer embd.CloseGPIO() - ... - embd.SetDirection(10, embd.Out) - embd.DigitalWrite(10, embd.High) + import "github.com/kidoman/embd" + ... + embd.InitGPIO() + defer embd.CloseGPIO() + ... + embd.SetDirection(10, embd.Out) + embd.DigitalWrite(10, embd.High) - Could also do: +Could also do: - import "github.com/kidoman/embd" - ... - embd.InitGPIO() - defer embd.CloseGPIO() - ... - pin, err := embd.NewDigitalPin(10) - ... - pin.SetDirection(embd.Out) - pin.Write(embd.High) + import "github.com/kidoman/embd" + ... + embd.InitGPIO() + defer embd.CloseGPIO() + ... + pin, err := embd.NewDigitalPin(10) + ... + pin.SetDirection(embd.Out) + pin.Write(embd.High) - Or read data from the Bosch BMP085 barometric sensor: +Or read data from the Bosch BMP085 barometric sensor: - import "github.com/kidoman/embd" - import "github.com/kidoman/embd/sensor/bmp085" - ... - bus := embd.NewI2CBus(1) - ... - baro := bmp085.New(bus) - ... - temp, err := baro.Temperature() - altitude, err := baro.Altitude() + import "github.com/kidoman/embd" + import "github.com/kidoman/embd/sensor/bmp085" + ... + bus := embd.NewI2CBus(1) + ... + baro := bmp085.New(bus) + ... + temp, err := baro.Temperature() + altitude, err := baro.Altitude() - Even find out the heading from the LSM303 magnetometer: +Even find out the heading from the LSM303 magnetometer: - import "github.com/kidoman/embd" - import "github.com/kidoman/embd/sensor/lsm303" - ... - bus := embd.NewI2CBus(1) - ... - mag := lsm303.New(bus) - ... - heading, err := mag.Heading() + import "github.com/kidoman/embd" + import "github.com/kidoman/embd/sensor/lsm303" + ... + bus := embd.NewI2CBus(1) + ... + mag := lsm303.New(bus) + ... + heading, err := mag.Heading() - The above two examples depend on I2C and therefore will work without change on almost all - platforms. +The above two examples depend on I2C and therefore will work without change on almost all +platforms. */ package embd From 905f4857d9fdaba614d625c5ced4ea4bc7f4b2dd Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 8 Sep 2016 23:28:20 -0700 Subject: [PATCH 23/27] minor documentation addition --- gpio.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gpio.go b/gpio.go index 26bd866..3d7baf7 100644 --- a/gpio.go +++ b/gpio.go @@ -33,7 +33,11 @@ const ( EdgeBoth Edge = "both" ) -// InterruptPin implements access to a Interruptable capable GPIO pin. +// InterruptPin implements access to an interrupt capable GPIO pin. +// The basic capability provided is to watch for a transition on the pin and +// generate a callback to a handler when a transition occurs. +// On Linux the underlying implementation generally uses epoll to receive the +// interrupts at user-level. type InterruptPin interface { // Start watching this pin for interrupt From 400ff1a279c7d0fa66bd38c0938aaa6a79f44488 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 8 Sep 2016 23:32:02 -0700 Subject: [PATCH 24/27] fix travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4fdf33a..f7153e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,4 +11,4 @@ go: script: - go test -bench=. -v ./... | grep -v 'no test files' ; test ${PIPESTATUS[0]} -eq 0 - cd samples; find . -name "*.go" -print0 | xargs -0 -n1 go build - - cd embd; go build . + - cd ../embd; go build . From 7790078c56b7b7f240f799671519f4b85ecdf095 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 8 Sep 2016 23:34:34 -0700 Subject: [PATCH 25/27] README update --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index b47e533..93896f8 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,13 @@ which it includes drivers. If you move to custom designed boards you have to throw away your code: you carry forward the effort where the HAL abstraction of EMBD will save you precious time. +The overall strategy used in embd is to use Linux device drivers to access gpio pins, +SPI and I2C buses, as well as interrupts. This makes it easy to port from one platform +to another and it enables kernel code to handle the devices as efficiently as possible. +What embd then adds is first a Golang library interface on top of the various Linux +devices and then another layer of user-level drivers for specific sensors and controllers +that are connected to gpio pins or one of the buses. + Development supported and sponsored by [**SoStronk**](https://www.sostronk.com) and [**ThoughtWorks**](http://www.thoughtworks.com/). From 5b6fbf3be12b583d64507f9e4e9dd10ca87453b9 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 8 Sep 2016 23:37:51 -0700 Subject: [PATCH 26/27] revert some gratuitous whitespace changes --- doc.go | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/doc.go b/doc.go index 761f0e3..a31cab1 100644 --- a/doc.go +++ b/doc.go @@ -1,9 +1,40 @@ -/* doc +/* Package embd provides a hardware abstraction layer for doing embedded programming -on supported platforms like the Raspberry Pi and BeagleBone Black. Most of the examples below -will work without change (i.e. the same binary) on all supported platforms. How cool is that? +on supported platforms like the Raspberry Pi, BeagleBone Black and CHIP. Most of the examples below +will work without change (i.e. the same binary) on all supported platforms. -Although samples are all present in the samples folder, we will show a few choice examples here. +== Overall structure + +It's best to think of the top-level embd package as a switchboard that doesn't implement anything +on its own but rather relies on sub-packages for hosts drivers and devices and stitches them +together. The exports in the top-level package serve a number of different purposes, +which can be confusing at first: +- it defines a number of driver interfaces, such as the GPIODriver, this is the interface that +the driver for each specific platform must implement and is not something of concern to the +typical user. +- it defines the main low-level hardware interface types: analog pins, digital pins, +interrupt pins, I2Cbuses, SPI buses, PWM pins and LEDs. Each type has a New function to +instantiate one of these pins or buses. +- it defines a number of InitXXX functions that initialize the various drivers, however, these +are called by the coresponding NewXXX functions, so can be ignored. +- it defines a number of top-level convenience functions, such as DigitalWrite, that can be +called as 1-liners instead of first instantiating a DigitalPin and then writing to it + +To get started a host driver needs to be registered with the top-level embd package. This is +most easily accomplished by doing an "underscore import" on of the sub-packages of embd/host, +e.g., `import _ "github.com/kidoman/embd/host/chip"`. An `Init()` function in the host driver +registers all the individual drivers with embd. + +After getting the host driver the next step might be to instantiate a GPIO pin using +`NewDigitalPin` or an I2CBus using `NewI2CBus`. Such a pin or bus can be used directly but +often it is passed into the initializer of a sensor, controller or other user-level driver +which provides a high-level interface to some device. For example, the New function +for the BMP180 type in the `embd/sensor/bmp180` package takes an I2CBus as argument, which +it will use to reach the sensor. + +== Samples + +This section shows a few choice samples, more are available in the samples folder. Use the LED driver to toggle LEDs on the BBB: From f256bd47158dfeb3b45d725af8bc448c477d07f5 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Thu, 8 Sep 2016 23:38:53 -0700 Subject: [PATCH 27/27] rename update_contibutors.sh --- update_contibutors.sh => update_contributors.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename update_contibutors.sh => update_contributors.sh (100%) diff --git a/update_contibutors.sh b/update_contributors.sh similarity index 100% rename from update_contibutors.sh rename to update_contributors.sh