Skip to content

Commit

Permalink
Refactor sysfs to use internal fs
Browse files Browse the repository at this point in the history
  • Loading branch information
zankich committed Nov 8, 2014
1 parent ea00d66 commit a0bcef7
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 150 deletions.
95 changes: 0 additions & 95 deletions mocks/fs.go

This file was deleted.

31 changes: 18 additions & 13 deletions sysfs/digital_pin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package sysfs

import (
"fmt"
"io/ioutil"
"os"
"strconv"
)
Expand Down Expand Up @@ -44,40 +43,39 @@ func NewDigitalPin(pin int, v ...string) DigitalPin {

// Direction sets the direction for the pin
func (d *digitalPin) Direction(dir string) error {
_, err := WriteFile(fmt.Sprintf("%v/%v/direction", GPIOPATH, d.label), []byte(dir))
_, err := writeFile(fmt.Sprintf("%v/%v/direction", GPIOPATH, d.label), []byte(dir))
return err
}

// Write writes to the pin
func (d *digitalPin) Write(b int) error {
_, err := WriteFile(fmt.Sprintf("%v/%v/value", GPIOPATH, d.label), []byte(strconv.Itoa(b)))
_, err := writeFile(fmt.Sprintf("%v/%v/value", GPIOPATH, d.label), []byte(strconv.Itoa(b)))
return err
}

// Read reads the current value of the pin
func (d *digitalPin) Read() (n int, err error) {
buf, err := ReadFile(fmt.Sprintf("%v/%v/value", GPIOPATH, d.label))
buf, err := readFile(fmt.Sprintf("%v/%v/value", GPIOPATH, d.label))
if err != nil {
return
return 0, err
}
return strconv.Atoi(string(buf[0]))
}

// Export exports the pin for use by the operating system
func (d *digitalPin) Export() error {
_, err := WriteFile(GPIOPATH+"/export", []byte(d.pin))
_, err := writeFile(GPIOPATH+"/export", []byte(d.pin))
return err
}

// Unexport unexports the pin and releases the pin from the operating system
func (d *digitalPin) Unexport() error {
_, err := WriteFile(GPIOPATH+"/unexport", []byte(d.pin))
_, err := writeFile(GPIOPATH+"/unexport", []byte(d.pin))
return err
}

//var writeFile = func(path string, data []byte) (i int, err error) {
var WriteFile = func(path string, data []byte) (i int, err error) {
file, err := os.OpenFile(path, os.O_WRONLY, 0644)
func writeFile(path string, data []byte) (i int, err error) {
file, err := OpenFile(path, os.O_WRONLY, 0644)
defer file.Close()
if err != nil {
return
Expand All @@ -86,7 +84,14 @@ var WriteFile = func(path string, data []byte) (i int, err error) {
return file.Write(data)
}

//var readFile = func(path string) (b []byte, err error) {
var ReadFile = func(path string) (b []byte, err error) {
return ioutil.ReadFile(path)
func readFile(path string) ([]byte, error) {
file, err := OpenFile(path, os.O_RDONLY, 0644)
defer file.Close()
if err != nil {
return make([]byte, 0), err
}

buf := make([]byte, 2)
_, err = file.Read(buf)
return buf, err
}
40 changes: 19 additions & 21 deletions sysfs/digital_pin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,14 @@ import (
)

func TestDigitalPin(t *testing.T) {
lastPath := ""
lastData := []byte{}
fs := NewMockFilesystem([]string{
"/sys/class/gpio/export",
"/sys/class/gpio/unexport",
"/sys/class/gpio/gpio10/value",
"/sys/class/gpio/gpio10/direction",
})

WriteFile = func(path string, data []byte) (i int, err error) {
lastPath = path
lastData = data
return
}

ReadFile = func(path string) (b []byte, err error) {
lastPath = path
return []byte("0"), nil
}
SetFilesystem(fs)

pin := NewDigitalPin(10, "custom").(*digitalPin)
gobot.Assert(t, pin.pin, "10")
Expand All @@ -29,22 +24,25 @@ func TestDigitalPin(t *testing.T) {
gobot.Assert(t, pin.label, "gpio10")

pin.Unexport()
gobot.Assert(t, lastPath, "/sys/class/gpio/unexport")
gobot.Assert(t, string(lastData), "10")
gobot.Assert(t, fs.Files["/sys/class/gpio/unexport"].Contents, "10")

pin.Export()
gobot.Assert(t, lastPath, "/sys/class/gpio/export")
gobot.Assert(t, string(lastData), "10")
gobot.Assert(t, fs.Files["/sys/class/gpio/unexport"].Contents, "10")

pin.Write(1)
gobot.Assert(t, lastPath, "/sys/class/gpio/gpio10/value")
gobot.Assert(t, string(lastData), "1")
gobot.Assert(t, fs.Files["/sys/class/gpio/gpio10/value"].Contents, "1")

pin.Direction(IN)
gobot.Assert(t, lastPath, "/sys/class/gpio/gpio10/direction")
gobot.Assert(t, string(lastData), "in")
gobot.Assert(t, fs.Files["/sys/class/gpio/gpio10/direction"].Contents, "in")

data, _ := pin.Read()
gobot.Assert(t, 1, data)

pin2 := NewDigitalPin(30, "custom")
err := pin2.Write(1)
gobot.Refute(t, err, nil)

data, err = pin2.Read()
gobot.Refute(t, err, nil)
gobot.Assert(t, data, 0)
gobot.Assert(t, lastPath, "/sys/class/gpio/gpio10/value")
}
6 changes: 2 additions & 4 deletions internal/fs.go → sysfs/fs.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package internal
package sysfs

import (
"os"
Expand All @@ -11,7 +11,6 @@ type File interface {
Read(b []byte) (n int, err error)
ReadAt(b []byte, off int64) (n int, err error)
Fd() uintptr

Close() error
}

Expand All @@ -20,8 +19,7 @@ type Filesystem interface {
}

// Filesystem that opens real files on the host.
type NativeFilesystem struct {
}
type NativeFilesystem struct{}

// Default to the host filesystem.
var fs Filesystem = &NativeFilesystem{}
Expand Down
103 changes: 103 additions & 0 deletions sysfs/fs_mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package sysfs

import (
"errors"
"os"
"time"
)

// A mock filesystem of simple files.
type MockFilesystem struct {
Seq int // Increases with each write or read.
Files map[string]*MockFile
}

// A simple mock file that contains a single string. Any write
// overwrites, and any read returns from the start.
type MockFile struct {
Contents string
Seq int // When this file was last written or read.
Opened bool
Closed bool
fd uintptr

fs *MockFilesystem
}

var _ File = (*MockFile)(nil)
var _ Filesystem = (*MockFilesystem)(nil)

func (f *MockFile) Write(b []byte) (n int, err error) {
return f.WriteString(string(b))
}

func (f *MockFile) WriteString(s string) (ret int, err error) {
f.Contents = s
f.Seq = f.fs.next()
return len(s), nil
}

func (f *MockFile) Sync() (err error) {
return nil
}

func (f *MockFile) Read(b []byte) (n int, err error) {
count := len(b)
if len(f.Contents) < count {
count = len(f.Contents)
}
copy(b, []byte(f.Contents)[:count])
f.Seq = f.fs.next()

return count, nil
}

func (f *MockFile) ReadAt(b []byte, off int64) (n int, err error) {
return f.Read(b)
}

func (f *MockFile) Fd() uintptr {
return f.fd
}

func (f *MockFile) Close() error {
return nil
}

func NewMockFilesystem(files []string) *MockFilesystem {
m := &MockFilesystem{
Files: make(map[string]*MockFile),
}

for i := range files {
m.Add(files[i])
}

return m
}

func (fs *MockFilesystem) OpenFile(name string, flag int, perm os.FileMode) (file File, err error) {
f, ok := fs.Files[name]
if ok {
f.Opened = true
f.Closed = false
return f, nil
} else {
return (*MockFile)(nil), errors.New("No such file.")
}
}

func (fs *MockFilesystem) Add(name string) *MockFile {
f := &MockFile{
Seq: -1,
fd: uintptr(time.Now().UnixNano() & 0xffff),
fs: fs,
}
fs.Files[name] = f
return f
}

func (fs *MockFilesystem) next() int {
fs.Seq++
return fs.Seq
}
Loading

0 comments on commit a0bcef7

Please sign in to comment.