gobot.io/x/gobot@v1.16.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"
     9  	"gobot.io/x/gobot/sysfs"
    10  )
    11  
    12  // PWMPin is the Raspberry Pi implementation of the PWMPinner interface.
    13  // It uses Pi Blaster.
    14  type PWMPin struct {
    15  	pin    string
    16  	dc     uint32
    17  	period uint32
    18  }
    19  
    20  // NewPwmPin returns a new PWMPin
    21  func NewPWMPin(pin string) *PWMPin {
    22  	return &PWMPin{
    23  		pin: pin}
    24  }
    25  
    26  // Export exports the pin for use by the Raspberry Pi
    27  func (p *PWMPin) Export() error {
    28  	return nil
    29  }
    30  
    31  // Unexport unexports the pin and releases the pin from the operating system
    32  func (p *PWMPin) Unexport() error {
    33  	return p.piBlaster(fmt.Sprintf("release %v\n", p.pin))
    34  }
    35  
    36  // Enable enables/disables the PWM pin
    37  func (p *PWMPin) Enable(e bool) (err error) {
    38  	return nil
    39  }
    40  
    41  // Polarity returns the polarity either normal or inverted
    42  func (p *PWMPin) Polarity() (polarity string, err error) {
    43  	return "normal", nil
    44  }
    45  
    46  // InvertPolarity does not do anything when using PiBlaster
    47  func (p *PWMPin) InvertPolarity(invert bool) (err error) {
    48  	return nil
    49  }
    50  
    51  // Period returns the current PWM period for pin
    52  func (p *PWMPin) Period() (period uint32, err error) {
    53  	if p.period == 0 {
    54  		return p.period, errors.New("Raspi PWM pin period not set")
    55  	}
    56  
    57  	return p.period, nil
    58  }
    59  
    60  // SetPeriod uses PiBlaster setting and cannot be changed once set
    61  func (p *PWMPin) SetPeriod(period uint32) (err error) {
    62  	if p.period != 0 {
    63  		return errors.New("Cannot set the period of individual PWM pins on Raspi")
    64  	}
    65  	p.period = period
    66  	return nil
    67  }
    68  
    69  // DutyCycle returns the duty cycle for the pin
    70  func (p *PWMPin) DutyCycle() (duty uint32, err error) {
    71  	return p.dc, nil
    72  }
    73  
    74  // SetDutyCycle writes the duty cycle to the pin
    75  func (p *PWMPin) SetDutyCycle(duty uint32) (err error) {
    76  	if p.period == 0 {
    77  		return errors.New("Raspi PWM pin period not set")
    78  	}
    79  
    80  	if duty > p.period {
    81  		return errors.New("Duty cycle exceeds period.")
    82  	}
    83  	p.dc = duty
    84  
    85  	val := gobot.FromScale(float64(p.dc), 0, float64(p.period))
    86  	
    87  	// never go below minimum allowed duty for pi blaster
    88  	// unless the duty equals to 0
    89  	if val < 0.05 && val != 0 {
    90  		val = 0.05
    91  	}
    92  	return p.piBlaster(fmt.Sprintf("%v=%v\n", p.pin, val))
    93  }
    94  
    95  func (p *PWMPin) piBlaster(data string) (err error) {
    96  	fi, err := sysfs.OpenFile("/dev/pi-blaster", os.O_WRONLY|os.O_APPEND, 0644)
    97  	defer fi.Close()
    98  
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	_, err = fi.WriteString(data)
   104  	return
   105  }