davecheney / gpio

GPIO for Go
BSD 2-Clause "Simplified" License
228 stars 52 forks source link

Export pin type #25

Closed OrangeTux closed 7 years ago

OrangeTux commented 7 years ago

I want to build a package on top of GPIO to interact with Atmel GPIO Controller.

This controller exposes the pins at a slightly different base path. Instead of /sys/class/gpio/gpioN the pins are exposed like this /sys/class/gpio/pioANtill /sys/class/gpio/EN.

Currently it's hard to write a package for this controller because the pin type is not exported. I propose to export the pin type. Then it's possible to write your own NewPin() and expose() functions to build support for GPIO controllers. Below I've put some code to demonstrate how exporting the pin struct could help to create support for GPIO controllers.

package atmel

import (
    "fmt"
    "github.com/orangetux/gpio"
    "os"
    "path/filepath"
)

const (
    gpiobase   = "/sys/class/gpio"
    exportPath = "/sys/class/gpio/export"
)

// OpenPin exports the pin, creating the virtual files necessary for interacting with the pin.
// It also sets the mode for the pin, making it ready for use.
func OpenPin(n int, mode gpio.Mode) (gpio.Pinner, error) {
    // export this pin to create the virtual files on the system
    pinBase, err := expose(n)
    if err != nil {
        return nil, err
    }
    value, err := os.OpenFile(filepath.Join(pinBase, "value"), os.O_RDWR, 0600)
    if err != nil {
        return nil, err
    }
    p := &gpio.Pin{
        Number:    n,
        ModePath:  filepath.Join(pinBase, "direction"),
        EdgePath:  filepath.Join(pinBase, "edge"),
        ValueFile: value,
        Initial:   true,
    }
    p.SetMode(mode)
    if p.Err() != nil {
        p.Close()
        return nil, p.Err()
    }
    return p, nil
}

func expose(pin int) (string, error) {
    var pinController string
    pinNumber := pin % 32
    var err error

    switch pin / 32 {
    case 1:
        pinController = "A"
    case 2:
        pinController = "B"
    case 3:
        pinController = "C"
    case 4:
        pinController = "D"
    case 5:
        pinController = "E"
    default:
        err = fmt.Errorf("GPIO %d does not exist", pin)
    }

    pinBase := filepath.Join(gpiobase, fmt.Sprintf("pio%s%d", pinController, pinNumber))

    if _, statErr := os.Stat(pinBase); os.IsNotExist(statErr) {
        err = gpio.WriteFile(filepath.Join(gpiobase, "export"), "%d", pin)
    }
    return pinBase, err
}
davecheney commented 7 years ago

Thank you for raising this issue. TBH, this package is dead, I haven't updated it in years. I recommend you fork it and make any changes you see necessary.

OrangeTux commented 7 years ago

I saw that it hasn't been updated for a while. But the concepts of GPIO are pretty solid as well, so I think this package is still usefull.

I'll fork it and do the changes.