gobot.io/x/gobot/v2@v2.1.0/platforms/raspi/pwm_pin.go (about) 1 package raspi 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 8 "gobot.io/x/gobot/v2" 9 "gobot.io/x/gobot/v2/system" 10 ) 11 12 // PWMPin is the Raspberry Pi implementation of the PWMPinner interface. 13 // It uses Pi Blaster. 14 type PWMPin struct { 15 sys *system.Accesser 16 path string 17 pin string 18 dc uint32 19 period uint32 20 } 21 22 // NewPWMPin returns a new PWMPin 23 func NewPWMPin(sys *system.Accesser, path string, pin string) *PWMPin { 24 return &PWMPin{ 25 sys: sys, 26 path: path, 27 pin: pin, 28 } 29 } 30 31 // Export exports the pin for use by the Raspberry Pi 32 func (p *PWMPin) Export() error { 33 return nil 34 } 35 36 // Unexport releases the pin from the operating system 37 func (p *PWMPin) Unexport() error { 38 return p.writeValue(fmt.Sprintf("release %v\n", p.pin)) 39 } 40 41 // Enabled returns always true for "enabled" 42 func (p *PWMPin) Enabled() (bool, error) { 43 return true, nil 44 } 45 46 // SetEnabled do nothing for PiBlaster 47 func (p *PWMPin) SetEnabled(e bool) error { 48 return nil 49 } 50 51 // Polarity returns always true for "normal" 52 func (p *PWMPin) Polarity() (bool, error) { 53 return true, nil 54 } 55 56 // SetPolarity does not do anything when using PiBlaster 57 func (p *PWMPin) SetPolarity(bool) (err error) { 58 return nil 59 } 60 61 // Period returns the cached PWM period for pin 62 func (p *PWMPin) Period() (uint32, error) { 63 if p.period == 0 { 64 return p.period, errors.New("Raspi PWM pin period not set") 65 } 66 67 return p.period, nil 68 } 69 70 // SetPeriod uses PiBlaster setting and cannot be changed once set 71 func (p *PWMPin) SetPeriod(period uint32) error { 72 if p.period != 0 { 73 return errors.New("Cannot set the period of individual PWM pins on Raspi") 74 } 75 p.period = period 76 return nil 77 } 78 79 // DutyCycle returns the duty cycle for the pin 80 func (p *PWMPin) DutyCycle() (uint32, error) { 81 return p.dc, nil 82 } 83 84 // SetDutyCycle writes the duty cycle to the pin 85 func (p *PWMPin) SetDutyCycle(duty uint32) error { 86 if p.period == 0 { 87 return errors.New("Raspi PWM pin period not set") 88 } 89 90 if duty > p.period { 91 return errors.New("Duty cycle exceeds period") 92 } 93 94 val := gobot.FromScale(float64(duty), 0, float64(p.period)) 95 // never go below minimum allowed duty for pi blaster 96 // unless the duty equals to 0 97 if val < 0.05 && val != 0 { 98 val = 0.05 99 } 100 101 if err := p.writeValue(fmt.Sprintf("%v=%v\n", p.pin, val)); err != nil { 102 return err 103 } 104 105 p.dc = duty 106 return nil 107 } 108 109 func (p *PWMPin) writeValue(data string) (err error) { 110 fi, err := p.sys.OpenFile(p.path, os.O_WRONLY|os.O_APPEND, 0644) 111 defer fi.Close() //nolint:staticcheck // for historical reasons 112 113 if err != nil { 114 return err 115 } 116 117 _, err = fi.WriteString(data) 118 return 119 }