gobot.io/x/gobot/v2@v2.1.0/platforms/jetson/pwm_pin.go (about)

     1  package jetson
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"path"
     8  
     9  	"gobot.io/x/gobot/v2"
    10  	"gobot.io/x/gobot/v2/system"
    11  )
    12  
    13  const (
    14  	minimumPeriod = 5334
    15  	minimumRate   = 0.05
    16  )
    17  
    18  // PWMPin is the Jetson Nano implementation of the PWMPinner interface.
    19  // It uses gpio pwm.
    20  type PWMPin struct {
    21  	sys     *system.Accesser
    22  	path    string
    23  	fn      string
    24  	dc      uint32
    25  	period  uint32
    26  	enabled bool
    27  }
    28  
    29  // NewPWMPin returns a new PWMPin
    30  // pin32 pwm0, pin33 pwm2
    31  func NewPWMPin(sys *system.Accesser, path string, fn string) *PWMPin {
    32  	p := &PWMPin{
    33  		sys:  sys,
    34  		path: path,
    35  		fn:   fn,
    36  	}
    37  	return p
    38  }
    39  
    40  // Export exports the pin for use by the Jetson Nano
    41  func (p *PWMPin) Export() error {
    42  	return p.writeFile("export", p.fn)
    43  }
    44  
    45  // Unexport releases the pin from the operating system
    46  func (p *PWMPin) Unexport() error {
    47  	return p.writeFile("unexport", p.fn)
    48  }
    49  
    50  // Enabled returns the cached enabled state of the PWM pin
    51  func (p *PWMPin) Enabled() (bool, error) {
    52  	return p.enabled, nil
    53  }
    54  
    55  // SetEnabled enables/disables the PWM pin
    56  func (p *PWMPin) SetEnabled(e bool) error {
    57  	if err := p.writeFile(fmt.Sprintf("pwm%s/enable", p.fn), fmt.Sprintf("%v", bool2int(e))); err != nil {
    58  		return err
    59  	}
    60  	p.enabled = e
    61  	return nil
    62  }
    63  
    64  // Polarity returns always the polarity "true" for normal
    65  func (p *PWMPin) Polarity() (bool, error) {
    66  	return true, nil
    67  }
    68  
    69  // SetPolarity does not do anything when using Jetson Nano
    70  func (p *PWMPin) SetPolarity(bool) error {
    71  	return nil
    72  }
    73  
    74  // Period returns the cached PWM period for pin
    75  func (p *PWMPin) Period() (period uint32, err error) {
    76  	if p.period == 0 {
    77  		return p.period, errors.New("Jetson PWM pin period not set")
    78  	}
    79  
    80  	return p.period, nil
    81  }
    82  
    83  // SetPeriod uses Jetson Nano setting and cannot be changed once set
    84  func (p *PWMPin) SetPeriod(period uint32) error {
    85  	if p.period != 0 {
    86  		return errors.New("Cannot set the period of individual PWM pins on Jetson")
    87  	}
    88  	// JetsonNano Minimum period
    89  	if period < minimumPeriod {
    90  		return errors.New("Cannot set the period more then minimum")
    91  	}
    92  	if err := p.writeFile(fmt.Sprintf("pwm%s/period", p.fn), fmt.Sprintf("%v", p.period)); err != nil {
    93  		return err
    94  	}
    95  	p.period = period
    96  	return nil
    97  }
    98  
    99  // DutyCycle returns the cached duty cycle for the pin
   100  func (p *PWMPin) DutyCycle() (uint32, error) {
   101  	return p.dc, nil
   102  }
   103  
   104  // SetDutyCycle writes the duty cycle to the pin
   105  func (p *PWMPin) SetDutyCycle(duty uint32) error {
   106  	if p.period == 0 {
   107  		return errors.New("Jetson PWM pin period not set")
   108  	}
   109  
   110  	if duty > p.period {
   111  		return errors.New("Duty cycle exceeds period")
   112  	}
   113  
   114  	rate := gobot.FromScale(float64(duty), 0, float64(p.period))
   115  	// never go below minimum allowed duty because very short duty
   116  	if rate < minimumRate {
   117  		duty = uint32(minimumRate * float64(p.period) / 100)
   118  	}
   119  	if err := p.writeFile(fmt.Sprintf("pwm%s/duty_cycle", p.fn), fmt.Sprintf("%v", duty)); err != nil {
   120  		return err
   121  	}
   122  
   123  	p.dc = duty
   124  	return nil
   125  }
   126  
   127  func (p *PWMPin) writeFile(subpath string, value string) error {
   128  	sysfspath := path.Join(p.path, subpath)
   129  	fi, err := p.sys.OpenFile(sysfspath, os.O_WRONLY|os.O_APPEND, 0644)
   130  	defer fi.Close() //nolint:staticcheck // for historical reasons
   131  
   132  	if err != nil {
   133  		return err
   134  	}
   135  
   136  	_, err = fi.WriteString(value)
   137  	return err
   138  }
   139  
   140  func bool2int(b bool) int {
   141  	if b {
   142  		return 1
   143  	}
   144  	return 0
   145  }