Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate gpio #24

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ RTE controller

* Install `config/RteCtrl.cfg` to `/etc/RteCtrl/RteCtrl.cfg`

* [Optional] If you want to select a specific gpio interface, in the
`RteCtrl.cfg` config set the `gpio_type` field to either `sysfs` or
`chardev`. The sysfs interace is configured by default, but is
deprecated.

* Install `web` directory to path pointed in `RteCtrl.cfg`:

```
Expand Down
1 change: 1 addition & 0 deletions config/RteCtrl.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"web_directory" : "web",
"flashrom_bin" : "/usr/local/sbin/flashrom",
"sys_gpio_path" : "/sys/class/gpio",
"gpio_type" : "sysfs",
"cmd_id" : {
"power" : 9,
"reset" : 8,
Expand Down
11 changes: 9 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
module 3mdeb/RteCtrl

go 1.16
go 1.22

require github.com/gorilla/mux v1.8.0
toolchain go1.23.3

require github.com/gorilla/mux v1.8.1

require (
github.com/jonboulle/clockwork v0.4.0 // indirect
periph.io/x/conn/v3 v3.7.1 // indirect
)
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
periph.io/x/conn/v3 v3.7.1 h1:tMjNv3WO8jEz/ePuXl7y++2zYi8LsQ5otbmqGKy3Myg=
periph.io/x/conn/v3 v3.7.1/go.mod h1:c+HCVjkzbf09XzcqZu/t+U8Ss/2QuJj0jgRF6Nye838=
36 changes: 28 additions & 8 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,25 @@ import (
"3mdeb/RteCtrl/pkg/restServer"
"flag"
"log"
"strings"
"time"
)

var version = "0.5.2"

// Flags
var (
configFilePath = flag.String("c", "/etc/RteCtrl/RteCtrl.cfg", "path to config file")
configFilePath = flag.String("c", "/etc/RteCtrl/RteCtrl.cfg", "path to config file")
)

func pressButton(g *gpioControl.Gpio, id int, t time.Duration) {
func pressButton(g *gpioControl.GpioSysfs, id int, t time.Duration) {
g.SetDirection(id, "out")
g.SetState(id, 1)
time.Sleep(t)
g.SetState(id, 0)
}

func toggleButton(g *gpioControl.Gpio, id int) {
func toggleButton(g *gpioControl.GpioSysfs, id int) {
g.SetDirection(id, "out")
val, _ := g.GetState(id)
if val == 0 {
Expand All @@ -38,18 +39,37 @@ func main() {

flag.Parse()

log.Println("RteCtrl version:", version);

log.Println("RteCtrl version:", version)
log.Println("reading", *configFilePath)

cfg, err := config.NewConfig(*configFilePath)
if err != nil {
log.Fatal(err)
}

gpio, err := gpioControl.New(cfg.SysGpioPath, cfg.Gpios)
if err != nil {
log.Fatal(err)
if !strings.Contains("sysgs;chardev", cfg.GpioType) {
log.Fatalf("Configuration Error! "+
"The 'gpio_type' should be one of the accepted values: "+
"[sysfs/chardev]. Current value is '%v'", cfg.GpioType)
}

log.Println("GPIO type:", cfg.GpioType)

var gpio gpioControl.IGpio

switch cfg.GpioType {
case "sysfs":
gpio, err = gpioControl.NewGpioSysfs(cfg.SysGpioPath, cfg.Gpios)
if err != nil {
log.Fatal(err)
}
case "chardev":
gpio, err = gpioControl.NewGpioChardev(cfg.SysGpioPath, cfg.Gpios)
if err != nil {
log.Fatal(err)
}
default:
log.Fatalf("Error! GPIO interface '%v' is not implemented!", cfg.GpioType)
}

flash, err := flashromControl.New(cfg.FlashromBin)
Expand Down
1 change: 1 addition & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Config struct {
SysGpioPath string `json:"sys_gpio_path"`
CommandIDs CmdIds `json:"cmd_id"`
Gpios []PinConfig `json:"gpios"`
GpioType string `json:"gpio_type"`
}

var cfg Config
Expand Down
10 changes: 10 additions & 0 deletions pkg/gpioControl/IgpioControl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package gpioControl

type IGpio interface {
GetDescription(id int) string
GetDirection(id int) (string, error)
GetNumberOfGpios() int
GetState(id int) (uint, error)
SetDirection(id int, direction string) error
SetState(id int, state uint) error
}
18 changes: 9 additions & 9 deletions pkg/gpioControl/gpioControl.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ type pin struct {
description string
}

type Gpio struct {
type GpioSysfs struct {
sysGpioPath string
gpios map[int]pin
}

var ctrl = Gpio{
var ctrl = GpioSysfs{
sysGpioPath: "/sys/class/gpio",
}

Expand All @@ -37,7 +37,7 @@ func checkGpio(sysGpio uint) bool {
return false
}

func New(gpioPath string, cfg []config.PinConfig) (*Gpio, error) {
func NewGpioSysfs(gpioPath string, cfg []config.PinConfig) (*GpioSysfs, error) {
if gpioPath != "" {
ctrl.sysGpioPath = gpioPath
}
Expand Down Expand Up @@ -71,7 +71,7 @@ func New(gpioPath string, cfg []config.PinConfig) (*Gpio, error) {
return &ctrl, nil
}

func (ctrl *Gpio) SetDirection(id int, direction string) error {
func (ctrl *GpioSysfs) SetDirection(id int, direction string) error {
target := fmt.Sprintf("%s/gpio%d/direction", ctrl.sysGpioPath, ctrl.gpios[id].sysNum)
var d string
switch direction {
Expand All @@ -88,7 +88,7 @@ func (ctrl *Gpio) SetDirection(id int, direction string) error {
return err
}

func (ctrl *Gpio) GetDirection(id int) (string, error) {
func (ctrl *GpioSysfs) GetDirection(id int) (string, error) {
target := fmt.Sprintf("%s/gpio%d/direction", ctrl.sysGpioPath, ctrl.gpios[id].sysNum)
dat, err := ioutil.ReadFile(target)
if err != nil {
Expand All @@ -105,7 +105,7 @@ func (ctrl *Gpio) GetDirection(id int) (string, error) {
return val, err
}

func (ctrl *Gpio) SetState(id int, state uint) error {
func (ctrl *GpioSysfs) SetState(id int, state uint) error {
dir, err := ctrl.GetDirection(id)
if err != nil {
return err
Expand All @@ -128,7 +128,7 @@ func (ctrl *Gpio) SetState(id int, state uint) error {
return err
}

func (ctrl *Gpio) GetState(id int) (uint, error) {
func (ctrl *GpioSysfs) GetState(id int) (uint, error) {
target := fmt.Sprintf("%s/gpio%d/value", ctrl.sysGpioPath, ctrl.gpios[id].sysNum)
dat, err := ioutil.ReadFile(target)
if err != nil {
Expand All @@ -149,10 +149,10 @@ func (ctrl *Gpio) GetState(id int) (uint, error) {
return 0, nil
}

func (ctrl *Gpio) GetNumberOfGpios() int {
func (ctrl *GpioSysfs) GetNumberOfGpios() int {
return len(ctrl.gpios)
}

func (ctrl *Gpio) GetDescription(id int) string {
func (ctrl *GpioSysfs) GetDescription(id int) string {
return ctrl.gpios[id].description
}
143 changes: 143 additions & 0 deletions pkg/gpioControl/gpioControlChardev.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package gpioControl

import (
"3mdeb/RteCtrl/pkg/config"
"fmt"
"periph.io/x/conn/v3/driver/driverreg"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/gpio/gpioreg"
)

type GpioChardev struct {
sysGpioPath string
gpios map[int]pin
pinDirection map[int]string
}

func GetGpioName(gpioNum uint) string {
return "GPIO" + fmt.Sprintf("%d", gpioNum)
}

func NewGpioChardev(gpioPath string, cfg []config.PinConfig) (*GpioChardev, error) {
if _, err := driverreg.Init(); err != nil {
return nil, err
}

if gpioPath != "" {
ctrl.sysGpioPath = gpioPath
}
var err error

ctrlChardev := GpioChardev{
sysGpioPath: gpioPath,
gpios: make(map[int]pin),
}

ctrlChardev.gpios = make(map[int]pin)
ctrlChardev.pinDirection = make(map[int]string)

for _, val := range cfg {
newPin := pin{sysNum: val.SysGpio, description: val.Description}
ctrl.gpios[val.ID] = newPin

// Check if pin can be found on the system
pinName := GetGpioName(val.SysGpio)
pin := gpioreg.ByName(pinName)
if pin != nil {
return nil, err // Return error if we can't find the GPIO pin
}

err = ctrlChardev.SetDirection(val.ID, val.Direction)
if err != nil {
return nil, err
}

err = ctrlChardev.SetState(val.ID, val.InitValue)
if err != nil {
return nil, err
}

}

return &ctrlChardev, nil
}

func (ctrl *GpioChardev) GetPinNumByID(id int) uint {
return ctrl.gpios[id].sysNum
}

func (ctrl *GpioChardev) GetPinNameByID(id int) string {
return GetGpioName(ctrl.gpios[id].sysNum)
}

func (ctrl *GpioChardev) SetDirection(id int, direction string) error {
pinID := ctrl.GetPinNumByID(id)
pin := gpioreg.ByName(ctrl.GetPinNameByID(id))

switch direction {
case "out", "o":
pin.Out(gpio.Low)
case "in", "i":
fallthrough
default:
pin.In(gpio.PullNoChange, gpio.NoEdge)
}
ctrl.pinDirection[int(pinID)] = direction

return nil
}

func (ctrl *GpioChardev) GetDirection(id int) (string, error) {
pinID := ctrl.GetPinNumByID(id)
val, ok := ctrl.pinDirection[int(pinID)]
if ok {
return val, nil
}

return "", fmt.Errorf("Cannot get the last saved state for pin with id %d", id)
}

func (ctrl *GpioChardev) SetState(id int, state uint) error {
dir, err := ctrl.GetDirection(id)
if err != nil {
return err
}
if dir == "in" {
return nil
}

pin := gpioreg.ByName(GetGpioName(ctrl.GetPinNumByID(id)))

switch state {
case 0:
pin.Out(gpio.Low)
case 1:
pin.Out(gpio.High)
default:
err = fmt.Errorf("Unsupported state: %d; Supported states are: [0, 1]")
return err
}

return nil
}

func (ctrl *GpioChardev) GetState(id int) (uint, error) {
pin := gpioreg.ByName(GetGpioName(ctrl.GetPinNumByID(id)))
state := pin.Read()

if state == gpio.High {
return 1, nil
} else if state == gpio.Low {
return 0, nil
} else {
return 0, fmt.Errorf("Unknown state of the pin: %v", state)
}
}

func (ctrl *GpioChardev) GetNumberOfGpios() int {
return len(ctrl.gpios)
}

func (ctrl *GpioChardev) GetDescription(id int) string {
return ctrl.gpios[id].description
}
8 changes: 3 additions & 5 deletions pkg/restServer/restServer.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import (
const restPrefix = "/api/v1"
const romFilename = "rte_romfile.rom"

var gpio *gpioControl.Gpio
var gpio *gpioControl.GpioSysfs
var flash *flashromControl.Flashrom
var tempRomFile string

Expand Down Expand Up @@ -214,14 +214,13 @@ func setGpioState(w http.ResponseWriter, r *http.Request) {
func uploadFile(w http.ResponseWriter, r *http.Request) {
out := json.NewEncoder(w)
rf, _, err := r.FormFile("file")
defer rf.Close()
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusNotFound)
out.Encode(errorStatus{Error: errCantUploadFile})
return
}
defer rf.Close()

h := md5.New()

tee := io.TeeReader(rf, h)
Expand Down Expand Up @@ -408,9 +407,8 @@ func logFunc(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWrite
}
}

func Start(address, webDir string, g *gpioControl.Gpio, f *flashromControl.Flashrom) {
func Start(address, webDir string, gpio gpioControl.IGpio, f *flashromControl.Flashrom) {

gpio = g
flash = f

tempRomFile = fmt.Sprintf("%s/%s", os.TempDir(), romFilename)
Expand Down