diff --git a/sysfs/digital_pin.go b/sysfs/digital_pin.go index 2c5740e8..0df1aa75 100644 --- a/sysfs/digital_pin.go +++ b/sysfs/digital_pin.go @@ -8,18 +8,29 @@ import ( ) const ( - IN = "in" - OUT = "out" - HIGH = 1 - LOW = 0 + // IN gpio direction + IN = "in" + // OUT gpio direction + OUT = "out" + // HIGH gpio level + HIGH = 1 + // LOW gpio level + LOW = 0 + // GPIOPATH default linux gpio path GPIOPATH = "/sys/class/gpio" ) +// DigitalPin is the interface for sysfs gpio interactions type DigitalPin interface { + // Unexport unexports the pin and releases the pin from the operating system Unexport() error + // Export exports the pin for use by the operating system Export() error + // Read reads the current value of the pin Read() (int, error) + // Direction sets the direction for the pin Direction(string) error + // Write writes to the pin Write(int) error } @@ -42,19 +53,16 @@ func NewDigitalPin(pin int, v ...string) DigitalPin { return d } -// 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)) 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))) 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)) if err != nil { @@ -63,7 +71,6 @@ func (d *digitalPin) Read() (n int, err error) { return strconv.Atoi(string(buf[0])) } -// Export exports the pin for use by the operating system func (d *digitalPin) Export() error { if _, err := writeFile(GPIOPATH+"/export", []byte(d.pin)); err != nil { // If EBUSY then the pin has already been exported @@ -74,7 +81,6 @@ func (d *digitalPin) Export() error { return nil } -// Unexport unexports the pin and releases the pin from the operating system func (d *digitalPin) Unexport() error { if _, err := writeFile(GPIOPATH+"/unexport", []byte(d.pin)); err != nil { // If EINVAL then the pin is reserved in the system and can't be unexported diff --git a/sysfs/fs.go b/sysfs/fs.go index c1703ea3..c6eed1ef 100644 --- a/sysfs/fs.go +++ b/sysfs/fs.go @@ -4,6 +4,7 @@ import ( "os" ) +// A File represents basic IO interactions with the underlying file system type File interface { Write(b []byte) (n int, err error) WriteString(s string) (ret int, err error) @@ -14,26 +15,28 @@ type File interface { Close() error } +// Filesystem opens files and returns either a native file system or user defined type Filesystem interface { OpenFile(name string, flag int, perm os.FileMode) (file File, err error) } -// Filesystem that opens real files on the host. +// NativeFilesystem represents the native file system implementation type NativeFilesystem struct{} // Default to the host filesystem. var fs Filesystem = &NativeFilesystem{} -// Override the default filesystem. +// SetFilesystem sets the filesystem implementation. func SetFilesystem(f Filesystem) { fs = f } +// OpenFile calls os.OpenFile(). func (fs *NativeFilesystem) OpenFile(name string, flag int, perm os.FileMode) (file File, err error) { return os.OpenFile(name, flag, perm) } -// Open a file the same as os.OpenFile(). +// OpenFile calls either the NativeFilesystem or user defined OpenFile func OpenFile(name string, flag int, perm os.FileMode) (file File, err error) { return fs.OpenFile(name, flag, perm) } diff --git a/sysfs/fs_mock.go b/sysfs/fs_mock.go index 7620724d..41ce1c36 100644 --- a/sysfs/fs_mock.go +++ b/sysfs/fs_mock.go @@ -6,13 +6,16 @@ import ( "time" ) -// A mock filesystem of simple files. +var _ File = (*MockFile)(nil) +var _ Filesystem = (*MockFilesystem)(nil) + +// MockFilesystem represents a filesystem of mock 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 +// A MockFile represents a mock file that contains a single string. Any write // overwrites, and any read returns from the start. type MockFile struct { Contents string @@ -24,23 +27,24 @@ type MockFile struct { fs *MockFilesystem } -var _ File = (*MockFile)(nil) -var _ Filesystem = (*MockFilesystem)(nil) - +// Write writes string(b) to f.Contents func (f *MockFile) Write(b []byte) (n int, err error) { return f.WriteString(string(b)) } +// WriteString writes s to f.Contents func (f *MockFile) WriteString(s string) (ret int, err error) { f.Contents = s f.Seq = f.fs.next() return len(s), nil } +// Sync implements the File interface Sync function func (f *MockFile) Sync() (err error) { return nil } +// Read copies b bytes from f.Contents func (f *MockFile) Read(b []byte) (n int, err error) { count := len(b) if len(f.Contents) < count { @@ -52,18 +56,22 @@ func (f *MockFile) Read(b []byte) (n int, err error) { return count, nil } +// ReadAt calls MockFile.Read func (f *MockFile) ReadAt(b []byte, off int64) (n int, err error) { return f.Read(b) } +// Fd returns a random uintprt based on the time of the MockFile creation func (f *MockFile) Fd() uintptr { return f.fd } +// Close implements the File interface Close function func (f *MockFile) Close() error { return nil } +// NewMockFilesystem returns a new MockFilesystem given a list of file paths func NewMockFilesystem(files []string) *MockFilesystem { m := &MockFilesystem{ Files: make(map[string]*MockFile), @@ -76,17 +84,18 @@ func NewMockFilesystem(files []string) *MockFilesystem { return m } +// OpenFile opens file name from fs.Files, if the file does not exist it returns an os.PathError 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), &os.PathError{Err: errors.New(name + ": No such file.")} } + return (*MockFile)(nil), &os.PathError{Err: errors.New(name + ": No such file.")} } +// Add adds a new file to fs.Files given a name, and returns the newly created file func (fs *MockFilesystem) Add(name string) *MockFile { f := &MockFile{ Seq: -1, diff --git a/sysfs/fs_mock_test.go b/sysfs/fs_mock_test.go index 3ccc37fe..18ccaa28 100644 --- a/sysfs/fs_mock_test.go +++ b/sysfs/fs_mock_test.go @@ -1,8 +1,9 @@ package sysfs import ( - "github.com/hybridgroup/gobot" "testing" + + "github.com/hybridgroup/gobot" ) func TestMockFilesystemOpen(t *testing.T) { diff --git a/sysfs/fs_test.go b/sysfs/fs_test.go index ba06c8fa..793d8545 100644 --- a/sysfs/fs_test.go +++ b/sysfs/fs_test.go @@ -1,9 +1,10 @@ package sysfs import ( - "github.com/hybridgroup/gobot" "os" "testing" + + "github.com/hybridgroup/gobot" ) func TestFilesystemOpen(t *testing.T) { diff --git a/sysfs/i2c_device.go b/sysfs/i2c_device.go index 78c04365..67a20f76 100644 --- a/sysfs/i2c_device.go +++ b/sysfs/i2c_device.go @@ -1,16 +1,17 @@ package sysfs import ( - "errors" "fmt" "io" "os" "syscall" ) +// I2CSlave is the linux default ioctrl request code const I2CSlave = 0x0703 -// NewI2cDevice creates a new io.ReadWriteCloser with the proper ioctrl given an i2c bus location and device address +// NewI2cDevice returns an io.ReadWriteCloser with the proper ioctrl given +// an i2c bus location and device address func NewI2cDevice(location string, address byte) (io.ReadWriteCloser, error) { file, err := OpenFile(location, os.O_RDWR, os.ModeExclusive) @@ -26,7 +27,7 @@ func NewI2cDevice(location string, address byte) (io.ReadWriteCloser, error) { ) if errno != 0 { - return nil, errors.New(fmt.Sprintf("Failed with syscall.Errno %v", errno)) + return nil, fmt.Errorf("Failed with syscall.Errno %v", errno) } return file, nil diff --git a/sysfs/i2c_device_test.go b/sysfs/i2c_device_test.go index bd729721..53257ae5 100644 --- a/sysfs/i2c_device_test.go +++ b/sysfs/i2c_device_test.go @@ -1,10 +1,11 @@ package sysfs import ( - "github.com/hybridgroup/gobot" "io" "os" "testing" + + "github.com/hybridgroup/gobot" ) func TestNewI2cDevice(t *testing.T) { diff --git a/sysfs/syscall.go b/sysfs/syscall.go index c0ac5548..07300495 100644 --- a/sysfs/syscall.go +++ b/sysfs/syscall.go @@ -4,27 +4,35 @@ import ( "syscall" ) +// SystemCaller represents a Syscall type SystemCaller interface { Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) } +// NativeSyscall represents the native Syscall type NativeSyscall struct{} + +// MockSyscall represents the mock Syscall type MockSyscall struct{} var sys SystemCaller = &NativeSyscall{} +// SetSyscall sets the Syscall implementation func SetSyscall(s SystemCaller) { sys = s } +// Syscall calls either the NativeSyscall or user defined Syscall func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return sys.Syscall(trap, a1, a2, a3) } +// Syscall calls syscall.Syscall func (sys *NativeSyscall) Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return syscall.Syscall(trap, a1, a2, a3) } +// Syscall implements the SystemCaller interface func (sys *MockSyscall) Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) { return 0, 0, 0 }