189 lines
3.9 KiB
Go
189 lines
3.9 KiB
Go
package chip
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"gobot.io/x/gobot/sysfs"
|
|
)
|
|
|
|
const pwmSysfsPath = "/sys/class/pwm/pwmchip0"
|
|
|
|
type pwmControl struct {
|
|
periodFile sysfs.File
|
|
dutyFile sysfs.File
|
|
polarityFile sysfs.File
|
|
enableFile sysfs.File
|
|
|
|
duty uint32
|
|
periodNanos uint32
|
|
enabled bool
|
|
}
|
|
|
|
func exportPWM() (err error) {
|
|
exporter, err := sysfs.OpenFile(pwmSysfsPath+"/export", os.O_WRONLY, 0666)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = io.WriteString(exporter, "0")
|
|
return err
|
|
}
|
|
|
|
func unexportPWM() (err error) {
|
|
exporter, err := sysfs.OpenFile(pwmSysfsPath+"/unexport", os.O_WRONLY, 0666)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = io.WriteString(exporter, "0")
|
|
return err
|
|
}
|
|
|
|
func (c *Adaptor) initPWM(pwmFrequency float64) (err error) {
|
|
const basePath = pwmSysfsPath + "/pwm0"
|
|
|
|
if _, err = sysfs.Stat(basePath); err != nil {
|
|
if os.IsNotExist(err) {
|
|
if err = exportPWM(); err != nil {
|
|
return
|
|
}
|
|
} else {
|
|
return
|
|
}
|
|
}
|
|
|
|
var enableFile sysfs.File
|
|
var periodFile sysfs.File
|
|
var dutyFile sysfs.File
|
|
var polarityFile sysfs.File
|
|
|
|
defer func() {
|
|
if enableFile != nil {
|
|
enableFile.Close()
|
|
}
|
|
if periodFile != nil {
|
|
periodFile.Close()
|
|
}
|
|
if dutyFile != nil {
|
|
dutyFile.Close()
|
|
}
|
|
if polarityFile != nil {
|
|
polarityFile.Close()
|
|
}
|
|
}()
|
|
|
|
if enableFile, err = sysfs.OpenFile(basePath+"/enable", os.O_WRONLY, 0666); err != nil {
|
|
return
|
|
}
|
|
if periodFile, err = sysfs.OpenFile(basePath+"/period", os.O_WRONLY, 0666); err != nil {
|
|
return
|
|
}
|
|
if dutyFile, err = sysfs.OpenFile(basePath+"/duty_cycle", os.O_WRONLY, 0666); err != nil {
|
|
return
|
|
}
|
|
if polarityFile, err = sysfs.OpenFile(basePath+"/polarity", os.O_WRONLY, 0666); err != nil {
|
|
return
|
|
}
|
|
|
|
c.pwm = &pwmControl{
|
|
enableFile: enableFile,
|
|
periodFile: periodFile,
|
|
dutyFile: dutyFile,
|
|
polarityFile: polarityFile,
|
|
}
|
|
|
|
enableFile = nil
|
|
periodFile = nil
|
|
dutyFile = nil
|
|
polarityFile = nil
|
|
|
|
// Set up some sane PWM defaults to make servo functions
|
|
// work out of the box.
|
|
if err = c.pwm.setPolarityInverted(false); err != nil {
|
|
return
|
|
}
|
|
if err = c.pwm.setEnable(true); err != nil {
|
|
return
|
|
}
|
|
if err = c.pwm.setFrequency(pwmFrequency); err != nil {
|
|
return
|
|
}
|
|
if err = c.pwm.setDutycycle(0); err != nil {
|
|
return
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Adaptor) closePWM() error {
|
|
pwm := c.pwm
|
|
if pwm != nil {
|
|
pwm.setFrequency(0)
|
|
pwm.setDutycycle(0)
|
|
pwm.setEnable(false)
|
|
|
|
if pwm.enableFile != nil {
|
|
pwm.enableFile.Close()
|
|
}
|
|
if pwm.periodFile != nil {
|
|
pwm.periodFile.Close()
|
|
}
|
|
if pwm.dutyFile != nil {
|
|
pwm.dutyFile.Close()
|
|
}
|
|
if pwm.polarityFile != nil {
|
|
pwm.polarityFile.Close()
|
|
}
|
|
if err := unexportPWM(); err != nil {
|
|
return err
|
|
}
|
|
c.pwm = nil
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *pwmControl) setPolarityInverted(invPolarity bool) error {
|
|
if !p.enabled {
|
|
polarityString := "normal"
|
|
if invPolarity {
|
|
polarityString = "inverted"
|
|
}
|
|
_, err := io.WriteString(p.polarityFile, polarityString)
|
|
return err
|
|
}
|
|
return fmt.Errorf("Cannot set PWM polarity when enabled")
|
|
}
|
|
|
|
func (p *pwmControl) setDutycycle(duty float64) error {
|
|
p.duty = uint32((float64(p.periodNanos) * (duty / 100.0)))
|
|
if p.enabled {
|
|
//fmt.Printf("PWM: Setting duty cycle to %v (%v)\n", p.duty, duty)
|
|
_, err := io.WriteString(p.dutyFile, fmt.Sprintf("%v", p.duty))
|
|
return err
|
|
}
|
|
return fmt.Errorf("Cannot set PWM duty cycle when disabled")
|
|
}
|
|
|
|
func (p *pwmControl) setFrequency(freq float64) error {
|
|
periodNanos := uint32(1e9 / freq)
|
|
if p.enabled && (p.periodNanos != periodNanos) {
|
|
p.periodNanos = periodNanos
|
|
_, err := io.WriteString(p.periodFile, fmt.Sprintf("%v", periodNanos))
|
|
return err
|
|
}
|
|
return fmt.Errorf("Cannot set PWM frequency when disabled")
|
|
}
|
|
|
|
func (p *pwmControl) setEnable(enabled bool) error {
|
|
if p.enabled != enabled {
|
|
p.enabled = enabled
|
|
enableVal := 0
|
|
if enabled {
|
|
enableVal = 1
|
|
}
|
|
_, err := io.WriteString(p.enableFile, fmt.Sprintf("%v", enableVal))
|
|
return err
|
|
}
|
|
return nil
|
|
}
|