mirror of
https://github.com/kidoman/embd
synced 2024-12-22 12:50:19 +01:00
gpio: analog pin support for the bbb
This commit is contained in:
parent
f667c93b7a
commit
d64682bf34
124
bbb.go
124
bbb.go
@ -1,10 +1,19 @@
|
|||||||
package embd
|
package embd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Describers[HostBBB] = func(rev int) *Descriptor {
|
Describers[HostBBB] = func(rev int) *Descriptor {
|
||||||
return &Descriptor{
|
return &Descriptor{
|
||||||
GPIO: func() GPIO {
|
GPIO: func() GPIO {
|
||||||
return newGPIODriver(bbbPins)
|
return newGPIODriver(bbbPins, newDigitalPin, newBBBAnalogPin)
|
||||||
},
|
},
|
||||||
I2C: newI2CDriver,
|
I2C: newI2CDriver,
|
||||||
}
|
}
|
||||||
@ -69,12 +78,111 @@ var bbbPins = PinMap{
|
|||||||
&PinDesc{ID: "P9_30", Aliases: []string{"112", "GPIO_112", "SPI1_D1"}, Caps: CapNormal | CapSPI, DigitalLogical: 112},
|
&PinDesc{ID: "P9_30", Aliases: []string{"112", "GPIO_112", "SPI1_D1"}, Caps: CapNormal | CapSPI, DigitalLogical: 112},
|
||||||
&PinDesc{ID: "P9_31", Aliases: []string{"110", "GPIO_110", "SPI1_SCLK"}, Caps: CapNormal | CapSPI, DigitalLogical: 110},
|
&PinDesc{ID: "P9_31", Aliases: []string{"110", "GPIO_110", "SPI1_SCLK"}, Caps: CapNormal | CapSPI, DigitalLogical: 110},
|
||||||
&PinDesc{ID: "P9_32", Aliases: []string{"VADC"}},
|
&PinDesc{ID: "P9_32", Aliases: []string{"VADC"}},
|
||||||
&PinDesc{ID: "P9_33", Aliases: []string{"AIN4"}, Caps: CapAnalog, AnalogLogical: 4},
|
&PinDesc{ID: "P9_33", Aliases: []string{"4", "AIN4"}, Caps: CapAnalog, AnalogLogical: 4},
|
||||||
&PinDesc{ID: "P9_34", Aliases: []string{"AGND"}},
|
&PinDesc{ID: "P9_34", Aliases: []string{"AGND"}},
|
||||||
&PinDesc{ID: "P9_35", Aliases: []string{"AIN6"}, Caps: CapAnalog, AnalogLogical: 6},
|
&PinDesc{ID: "P9_35", Aliases: []string{"6", "AIN6"}, Caps: CapAnalog, AnalogLogical: 6},
|
||||||
&PinDesc{ID: "P9_36", Aliases: []string{"AIN5"}, Caps: CapAnalog, AnalogLogical: 5},
|
&PinDesc{ID: "P9_36", Aliases: []string{"5", "AIN5"}, Caps: CapAnalog, AnalogLogical: 5},
|
||||||
&PinDesc{ID: "P9_37", Aliases: []string{"AIN2"}, Caps: CapAnalog, AnalogLogical: 2},
|
&PinDesc{ID: "P9_37", Aliases: []string{"2", "AIN2"}, Caps: CapAnalog, AnalogLogical: 2},
|
||||||
&PinDesc{ID: "P9_38", Aliases: []string{"AIN3"}, Caps: CapAnalog, AnalogLogical: 3},
|
&PinDesc{ID: "P9_38", Aliases: []string{"3", "AIN3"}, Caps: CapAnalog, AnalogLogical: 3},
|
||||||
&PinDesc{ID: "P9_39", Aliases: []string{"AIN0"}, Caps: CapAnalog, AnalogLogical: 0},
|
&PinDesc{ID: "P9_39", Aliases: []string{"0", "AIN0"}, Caps: CapAnalog, AnalogLogical: 0},
|
||||||
&PinDesc{ID: "P9_40", Aliases: []string{"AIN1"}, Caps: CapAnalog, AnalogLogical: 1},
|
&PinDesc{ID: "P9_40", Aliases: []string{"1", "AIN1"}, Caps: CapAnalog, AnalogLogical: 1},
|
||||||
|
}
|
||||||
|
|
||||||
|
type bbbAnalogPin struct {
|
||||||
|
n int
|
||||||
|
|
||||||
|
val *os.File
|
||||||
|
|
||||||
|
initialized bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBBBAnalogPin(n int) AnalogPin {
|
||||||
|
return &bbbAnalogPin{n: n}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *bbbAnalogPin) N() int {
|
||||||
|
return p.n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *bbbAnalogPin) init() error {
|
||||||
|
if p.initialized {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if err = p.ensureEnabled(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if p.val, err = p.valueFile(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.initialized = true
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *bbbAnalogPin) ensureEnabled() error {
|
||||||
|
file := "/sys/devices/bone_capemgr.8/slots"
|
||||||
|
bytes, err := ioutil.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
str := string(bytes)
|
||||||
|
if strings.Contains(str, "cape-bone-iio") {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Not initialized yet
|
||||||
|
slots, err := os.OpenFile(file, os.O_WRONLY, os.ModeExclusive)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer slots.Close()
|
||||||
|
_, err = slots.WriteString("cape-bone-iio")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *bbbAnalogPin) valueFilePath() string {
|
||||||
|
return fmt.Sprintf("/sys/devices/ocp.2/helper.14/AIN%v", p.n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *bbbAnalogPin) openFile(path string) (*os.File, error) {
|
||||||
|
return os.OpenFile(path, os.O_RDONLY, os.ModeExclusive)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *bbbAnalogPin) valueFile() (*os.File, error) {
|
||||||
|
return p.openFile(p.valueFilePath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *bbbAnalogPin) Read() (int, error) {
|
||||||
|
if err := p.init(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.val.Seek(0, 0)
|
||||||
|
bytes, err := ioutil.ReadAll(p.val)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
str := string(bytes)
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
return strconv.Atoi(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *bbbAnalogPin) Write(_ int) error {
|
||||||
|
return errors.New("gpio: not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *bbbAnalogPin) Close() error {
|
||||||
|
if !p.initialized {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.val.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.initialized = false
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,14 @@ type digitalPin struct {
|
|||||||
initialized bool
|
initialized bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDigitalPin(n int) *digitalPin {
|
func newDigitalPin(n int) DigitalPin {
|
||||||
return &digitalPin{n: n}
|
return &digitalPin{n: n}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *digitalPin) N() int {
|
||||||
|
return p.n
|
||||||
|
}
|
||||||
|
|
||||||
func (p *digitalPin) init() error {
|
func (p *digitalPin) init() error {
|
||||||
if p.initialized {
|
if p.initialized {
|
||||||
return nil
|
return nil
|
||||||
|
34
gpio.go
34
gpio.go
@ -13,6 +13,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DigitalPin interface {
|
type DigitalPin interface {
|
||||||
|
N() int
|
||||||
|
|
||||||
Write(val int) error
|
Write(val int) error
|
||||||
Read() (int, error)
|
Read() (int, error)
|
||||||
|
|
||||||
@ -25,8 +27,18 @@ type DigitalPin interface {
|
|||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AnalogPin interface {
|
||||||
|
N() int
|
||||||
|
|
||||||
|
Write(val int) error
|
||||||
|
Read() (int, error)
|
||||||
|
|
||||||
|
Close() error
|
||||||
|
}
|
||||||
|
|
||||||
type GPIO interface {
|
type GPIO interface {
|
||||||
DigitalPin(key interface{}) (DigitalPin, error)
|
DigitalPin(key interface{}) (DigitalPin, error)
|
||||||
|
AnalogPin(key interface{}) (AnalogPin, error)
|
||||||
|
|
||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
@ -87,3 +99,25 @@ func ActiveLow(key interface{}, b bool) error {
|
|||||||
|
|
||||||
return pin.ActiveLow(b)
|
return pin.ActiveLow(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewAnalogPin(key interface{}) (AnalogPin, error) {
|
||||||
|
return gpioInstance.AnalogPin(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AnalogWrite(key interface{}, val int) error {
|
||||||
|
pin, err := NewAnalogPin(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pin.Write(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AnalogRead(key interface{}) (int, error) {
|
||||||
|
pin, err := NewAnalogPin(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return pin.Read()
|
||||||
|
}
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package embd
|
package embd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type pin interface {
|
type pin interface {
|
||||||
@ -11,39 +10,54 @@ type pin interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type gpioDriver struct {
|
type gpioDriver struct {
|
||||||
pinMap PinMap
|
pinMap PinMap
|
||||||
|
|
||||||
|
dpf func(n int) DigitalPin
|
||||||
|
apf func(n int) AnalogPin
|
||||||
|
|
||||||
initializedPins map[string]pin
|
initializedPins map[string]pin
|
||||||
}
|
}
|
||||||
|
|
||||||
func newGPIODriver(pinMap PinMap) *gpioDriver {
|
func newGPIODriver(pinMap PinMap, dpf func(n int) DigitalPin, apf func(n int) AnalogPin) GPIO {
|
||||||
return &gpioDriver{
|
return &gpioDriver{
|
||||||
pinMap: pinMap,
|
pinMap: pinMap,
|
||||||
|
dpf: dpf,
|
||||||
|
apf: apf,
|
||||||
|
|
||||||
initializedPins: map[string]pin{},
|
initializedPins: map[string]pin{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (io *gpioDriver) lookupKey(key interface{}, cap int) (*PinDesc, bool) {
|
|
||||||
return io.pinMap.Lookup(key, cap)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpioDriver) digitalPin(key interface{}) (*digitalPin, error) {
|
|
||||||
pd, found := io.lookupKey(key, CapNormal)
|
|
||||||
if !found {
|
|
||||||
return nil, fmt.Errorf("gpio: could not find pin matching %q", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
if pd.Caps != CapNormal {
|
|
||||||
glog.Infof("gpio: pin %q is not a dedicated digital io pin. please refer to the system reference manual for more details", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
dp := newDigitalPin(pd.DigitalLogical)
|
|
||||||
io.initializedPins[pd.ID] = dp
|
|
||||||
|
|
||||||
return dp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (io *gpioDriver) DigitalPin(key interface{}) (DigitalPin, error) {
|
func (io *gpioDriver) DigitalPin(key interface{}) (DigitalPin, error) {
|
||||||
return io.digitalPin(key)
|
if io.dpf == nil {
|
||||||
|
return nil, errors.New("gpio: digital io not supported on this host")
|
||||||
|
}
|
||||||
|
|
||||||
|
pd, found := io.pinMap.Lookup(key, CapNormal)
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("gpio: could not find pin matching %v", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := io.dpf(pd.DigitalLogical)
|
||||||
|
io.initializedPins[pd.ID] = p
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (io *gpioDriver) AnalogPin(key interface{}) (AnalogPin, error) {
|
||||||
|
if io.apf == nil {
|
||||||
|
return nil, errors.New("gpio: analog io not supported on this host")
|
||||||
|
}
|
||||||
|
|
||||||
|
pd, found := io.pinMap.Lookup(key, CapAnalog)
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("gpio: could not find pin matching %v", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := io.apf(pd.AnalogLogical)
|
||||||
|
io.initializedPins[pd.ID] = p
|
||||||
|
|
||||||
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (io *gpioDriver) Close() error {
|
func (io *gpioDriver) Close() error {
|
||||||
|
@ -2,6 +2,46 @@ package embd
|
|||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
|
type fakeDigitalPin struct {
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *fakeDigitalPin) N() int {
|
||||||
|
return p.n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeDigitalPin) SetDirection(dir Direction) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeDigitalPin) Read() (int, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeDigitalPin) Write(val int) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeDigitalPin) ActiveLow(b bool) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeDigitalPin) PullUp() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeDigitalPin) PullDown() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeDigitalPin) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFakeDigitalPin(n int) DigitalPin {
|
||||||
|
return &fakeDigitalPin{n}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGpioDriverDigitalPin(t *testing.T) {
|
func TestGpioDriverDigitalPin(t *testing.T) {
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
key interface{}
|
key interface{}
|
||||||
@ -12,15 +52,86 @@ func TestGpioDriverDigitalPin(t *testing.T) {
|
|||||||
var pinMap = PinMap{
|
var pinMap = PinMap{
|
||||||
&PinDesc{ID: "P1_1", Aliases: []string{"1"}, Caps: CapNormal, DigitalLogical: 1},
|
&PinDesc{ID: "P1_1", Aliases: []string{"1"}, Caps: CapNormal, DigitalLogical: 1},
|
||||||
}
|
}
|
||||||
driver := newGPIODriver(pinMap)
|
driver := newGPIODriver(pinMap, newFakeDigitalPin, nil)
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
pin, err := driver.digitalPin(test.key)
|
pin, err := driver.DigitalPin(test.key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Looking up %v: unexpected error: %v", test.key, err)
|
t.Errorf("Looking up %v: unexpected error: %v", test.key, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if pin.n != test.n {
|
if pin.N() != test.n {
|
||||||
t.Errorf("Looking up %v: got %v, want %v", test.key, pin.n, test.n)
|
t.Errorf("Looking up %v: got %v, want %v", test.key, pin.N(), test.n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fakeAnalogPin struct {
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *fakeAnalogPin) N() int {
|
||||||
|
return p.n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeAnalogPin) Read() (int, error) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeAnalogPin) Write(val int) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeAnalogPin) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFakeAnalogPin(n int) AnalogPin {
|
||||||
|
return &fakeAnalogPin{n}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGpioDriverAnalogPin(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
key interface{}
|
||||||
|
n int
|
||||||
|
}{
|
||||||
|
{1, 1},
|
||||||
|
}
|
||||||
|
var pinMap = PinMap{
|
||||||
|
&PinDesc{ID: "P1_1", Aliases: []string{"1"}, Caps: CapAnalog, AnalogLogical: 1},
|
||||||
|
}
|
||||||
|
driver := newGPIODriver(pinMap, nil, newFakeAnalogPin)
|
||||||
|
for _, test := range tests {
|
||||||
|
pin, err := driver.AnalogPin(test.key)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Looking up %v: unexpected error: %v", test.key, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if pin.N() != test.n {
|
||||||
|
t.Errorf("Looking up %v: got %v, want %v", test.key, pin.N(), test.n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGpioDriverUnavailablePinType(t *testing.T) {
|
||||||
|
var pinMap = PinMap{
|
||||||
|
&PinDesc{ID: "P1_1", Aliases: []string{"1"}, Caps: CapNormal, DigitalLogical: 1},
|
||||||
|
&PinDesc{ID: "P1_2", Aliases: []string{"1"}, Caps: CapAnalog, AnalogLogical: 1},
|
||||||
|
}
|
||||||
|
driver := newGPIODriver(pinMap, nil, nil)
|
||||||
|
_, err := driver.DigitalPin(1)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Looking up digital pin 1: did not get error")
|
||||||
|
}
|
||||||
|
expected := "gpio: digital io not supported on this host"
|
||||||
|
if err.Error() != expected {
|
||||||
|
t.Fatalf("Looking up digital pin 1: got error %q, expected %q", err, expected)
|
||||||
|
}
|
||||||
|
_, err = driver.AnalogPin(1)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("Looking up analog pin 1: did not get error")
|
||||||
|
}
|
||||||
|
expected = "gpio: analog io not supported on this host"
|
||||||
|
if err.Error() != expected {
|
||||||
|
t.Fatalf("Looking up analog pin 1: got error %q, expected %q", err, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2
rpi.go
2
rpi.go
@ -9,7 +9,7 @@ func init() {
|
|||||||
|
|
||||||
return &Descriptor{
|
return &Descriptor{
|
||||||
GPIO: func() GPIO {
|
GPIO: func() GPIO {
|
||||||
return newGPIODriver(pins)
|
return newGPIODriver(pins, newDigitalPin, nil)
|
||||||
},
|
},
|
||||||
I2C: newI2CDriver,
|
I2C: newI2CDriver,
|
||||||
}
|
}
|
||||||
|
1
samples/.gitignore
vendored
1
samples/.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
analog
|
||||||
bh1750fvi
|
bh1750fvi
|
||||||
bmp085
|
bmp085
|
||||||
bmp180
|
bmp180
|
||||||
|
42
samples/analog.go
Normal file
42
samples/analog.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/kidoman/embd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if err := embd.InitGPIO(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer embd.CloseGPIO()
|
||||||
|
|
||||||
|
pin, err := embd.NewAnalogPin(0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer pin.Close()
|
||||||
|
|
||||||
|
quit := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(quit, os.Interrupt, os.Kill)
|
||||||
|
defer signal.Stop(quit)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-time.After(100 * time.Millisecond):
|
||||||
|
val, err := pin.Read()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("reading: %v\n", val)
|
||||||
|
case <-quit:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user