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  }