From f0d709e3653a477d4215dc676dd7472631ed919f Mon Sep 17 00:00:00 2001 From: Jay Date: Sun, 29 Jan 2023 22:38:17 +0800 Subject: [PATCH] first version --- cmd/backlight-control.go | 34 ++++++++ cmd/set/set.go | 132 ++++++++++++++++++++++++++++++++ cmd/status/status.go | 66 ++++++++++++++++ go.mod | 13 ++++ go.sum | 12 +++ internal/backlight/backlight.go | 71 +++++++++++++++++ 6 files changed, 328 insertions(+) create mode 100644 cmd/backlight-control.go create mode 100644 cmd/set/set.go create mode 100644 cmd/status/status.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/backlight/backlight.go diff --git a/cmd/backlight-control.go b/cmd/backlight-control.go new file mode 100644 index 0000000..4bedf30 --- /dev/null +++ b/cmd/backlight-control.go @@ -0,0 +1,34 @@ +package main + +import ( + "backlight-control/cmd/set" + "backlight-control/cmd/status" + + "github.com/spf13/cobra" +) + +var rootCmd *cobra.Command + +func main() { + rootCmd = &cobra.Command{ + Use: "backlight-control", + Short: "backlight control tool", + SilenceUsage: true, + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, + } + + rootCmd.PersistentFlags().String("path", "", "control file directory path (/path/to/dir/{brightness,max_brightness})") + + if err := rootCmd.MarkPersistentFlagRequired("path"); err != nil { + panic(err) + } + + set.NewCommand(rootCmd) + status.NewCommand(rootCmd) + + if err := rootCmd.Execute(); err != nil { + panic(err) + } +} diff --git a/cmd/set/set.go b/cmd/set/set.go new file mode 100644 index 0000000..88f20f6 --- /dev/null +++ b/cmd/set/set.go @@ -0,0 +1,132 @@ +package set + +import ( + "backlight-control/internal/backlight" + "errors" + "fmt" + "regexp" + "strconv" + + "github.com/spf13/cobra" +) + +func NewCommand(parent *cobra.Command) { + cmd := &cobra.Command{ + Use: "set [+/-]VAL[%]", + Aliases: []string{"s"}, + Args: cobra.ExactArgs(1), + RunE: run, + Short: "set backlight value", + } + + parent.AddCommand(cmd) +} + +type operate int + +const ( + None operate = 1 << iota + Equal + Add + Subtract +) + +var changeValueRegex = regexp.MustCompile(`^([+-])?(\d+(\.\d+)?)%?$`) + +func parseChange(val string) (op operate, value float32, err error) { + + find := changeValueRegex.FindAllStringSubmatch(val, -1) + if find == nil || len(find) < 1 { + return None, 0, errors.New("input value pattern invalid") + } + + findList := find[0] + if len(findList) < 3 { + return None, 0, fmt.Errorf("parsed value invalid, %v", findList) + } + + opStr := findList[1] + valStr := findList[2] + + switch opStr { + case "+": + op = Add + case "-": + op = Subtract + default: + op = Equal + } + + f64, err := strconv.ParseFloat(valStr, 32) + if err != nil { + return None, 0, fmt.Errorf("parse value to float fail: (%w)", err) + } + + value = float32(f64) + + return +} + +func run(cmd *cobra.Command, args []string) (err error) { + dirPath, err := cmd.Flags().GetString("path") + if err != nil { + return fmt.Errorf("get directory path from flags fail: (%w)", err) + } + _ = dirPath + + op, value, err := parseChange(args[0]) + if err != nil { + return err + } + + lightInstance, err := backlight.NewInstance(dirPath) + if err != nil { + return fmt.Errorf("create backlight instance fail: %w", err) + } + + cur, err := lightInstance.GetCurrent() + if err != nil { + return fmt.Errorf("get current brightness fail: %w", err) + } + max, err := lightInstance.GetMax() + if err != nil { + return fmt.Errorf("get max brightness fail: %w", err) + } + + // cale percentage + curP := float32(int(float32(cur)/float32(max)*10000)) / 100 + + // 1% base + oneP := float32(max) / 100 + + finalVal := 0 + + switch op { + case Add: + finalVal = int((curP + value) * oneP) + if finalVal > max { + finalVal = max + } + case Subtract: + finalVal = int((curP - value) * oneP) + if finalVal < 0 { + finalVal = 0 + } + case Equal: + if value > 100 { + value = 100 + } else if value < 0 { + value = 0 + } + finalVal = int((value) * oneP) + default: + return errors.New("operate invalid") + } + + err = lightInstance.SetValue(finalVal) + if err != nil { + return fmt.Errorf("set backlight to target value fail: %w", err) + } + + return +} diff --git a/cmd/status/status.go b/cmd/status/status.go new file mode 100644 index 0000000..64eb2a1 --- /dev/null +++ b/cmd/status/status.go @@ -0,0 +1,66 @@ +package status + +import ( + "backlight-control/internal/backlight" + "encoding/json" + "fmt" + + "github.com/spf13/cobra" +) + +func NewCommand(parent *cobra.Command) { + cmd := &cobra.Command{ + Use: "status", + Aliases: []string{"st"}, + RunE: run, + Short: "get backlight status (current,max,percentage)", + } + + parent.AddCommand(cmd) +} + +type backlightStatus struct { + Current int `json:"current"` + Max int `json:"max"` + Percentage float32 `json:"percentage"` +} + +func run(cmd *cobra.Command, args []string) (err error) { + dirPath, err := cmd.Flags().GetString("path") + if err != nil { + return fmt.Errorf("get directory path from flags fail: (%w)", err) + } + + lightInstance, err := backlight.NewInstance(dirPath) + if err != nil { + return fmt.Errorf("create backlight instance fail: %w", err) + } + + cur, err := lightInstance.GetCurrent() + if err != nil { + return fmt.Errorf("get current brightness fail: %w", err) + } + max, err := lightInstance.GetMax() + if err != nil { + return fmt.Errorf("get max brightness fail: %w", err) + } + + status := backlightStatus{ + Current: cur, + Max: max, + } + + // cale percentage + f := float32(int(float32(cur)/float32(max)*10000)) / 100 + + status.Percentage = f + + b, err := json.Marshal(status) + if err != nil { + return err + } + + fmt.Println(string(b)) + + return +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b0d3ad3 --- /dev/null +++ b/go.mod @@ -0,0 +1,13 @@ +module backlight-control + +go 1.19 + +require ( + git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349 + github.com/spf13/cobra v1.6.1 +) + +require ( + github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/spf13/pflag v1.0.5 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c3911d8 --- /dev/null +++ b/go.sum @@ -0,0 +1,12 @@ +git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349 h1:V6ifeiJ3ExnjaUylTOz37n6z5uLwm6fjKjnztbTCaQI= +git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349/go.mod h1:yE+qbsUsijCTdwsaQRkPT1CXYk7ftMzXsCaaYx/0QI0= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= +github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/backlight/backlight.go b/internal/backlight/backlight.go new file mode 100644 index 0000000..67ee549 --- /dev/null +++ b/internal/backlight/backlight.go @@ -0,0 +1,71 @@ +package backlight + +import ( + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + + "git.trj.tw/golang/utils" +) + +type Backlight struct { + Directory string +} + +const currentValueFile = "brightness" +const maxValueFile = "max_brightness" + +func NewInstance(path string) (*Backlight, error) { + bl := &Backlight{Directory: path} + + if !utils.CheckExists(path, true) { + return nil, fmt.Errorf("backlight class directory check fail") + } + + // check brightness and max_brightness file exists + brightnessFile := filepath.Join(path, currentValueFile) + maxBrightnessFile := filepath.Join(path, maxValueFile) + + if !utils.CheckExists(brightnessFile, false) { + return nil, fmt.Errorf("brightness file check fail") + } + if !utils.CheckExists(maxBrightnessFile, false) { + return nil, fmt.Errorf("max_brightness file check fail") + } + + return bl, nil +} + +func readBrightnessValue(file string) (val int, err error) { + cnt, err := os.ReadFile(file) + if err != nil { + return 0, err + } + + val, err = strconv.Atoi(strings.TrimSpace(string(cnt))) + if err != nil { + return 0, err + } + + return +} + +func (b *Backlight) GetCurrent() (val int, err error) { + return readBrightnessValue(filepath.Join(b.Directory, currentValueFile)) +} + +func (b *Backlight) GetMax() (val int, err error) { + return readBrightnessValue(filepath.Join(b.Directory, maxValueFile)) +} + +func (b *Backlight) SetValue(val int) (err error) { + brightness := filepath.Join(b.Directory, "brightness") + + if err := os.WriteFile(brightness, []byte(fmt.Sprintf("%d", val)), 0644); err != nil { + return err + } + + return +}