gobot.io/x/gobot@v1.16.0/drivers/i2c/grovepi_driver.go (about)

     1  package i2c
     2  
     3  import (
     4  	"strconv"
     5  	"strings"
     6  	"sync"
     7  	"time"
     8  
     9  	"gobot.io/x/gobot"
    10  )
    11  
    12  const grovePiAddress = 0x04
    13  
    14  // Commands format
    15  const (
    16  	CommandReadDigital    = 1
    17  	CommandWriteDigital   = 2
    18  	CommandReadAnalog     = 3
    19  	CommandWriteAnalog    = 4
    20  	CommandPinMode        = 5
    21  	CommandReadUltrasonic = 7
    22  	CommandReadDHT        = 40
    23  )
    24  
    25  // GrovePiDriver is a driver for the GrovePi+ for I²C bus interface.
    26  // https://www.dexterindustries.com/grovepi/
    27  //
    28  // To use this driver with the GrovePi, it must be running the 1.3.0+ firmware.
    29  // https://forum.dexterindustries.com/t/pre-release-of-grovepis-firmware-v1-3-0-open-to-testers/5119
    30  //
    31  type GrovePiDriver struct {
    32  	name        string
    33  	digitalPins map[int]string
    34  	analogPins  map[int]string
    35  	mutex       *sync.Mutex
    36  	connector   Connector
    37  	connection  Connection
    38  	Config
    39  }
    40  
    41  // NewGrovePiDriver creates a new driver with specified i2c interface
    42  // Params:
    43  //		conn Connector - the Adaptor to use with this Driver
    44  //
    45  // Optional params:
    46  //		i2c.WithBus(int):	bus to use with this driver
    47  //		i2c.WithAddress(int):	address to use with this driver
    48  //
    49  func NewGrovePiDriver(a Connector, options ...func(Config)) *GrovePiDriver {
    50  	d := &GrovePiDriver{
    51  		name:        gobot.DefaultName("GrovePi"),
    52  		digitalPins: make(map[int]string),
    53  		analogPins:  make(map[int]string),
    54  		mutex:       &sync.Mutex{},
    55  		connector:   a,
    56  		Config:      NewConfig(),
    57  	}
    58  
    59  	for _, option := range options {
    60  		option(d)
    61  	}
    62  
    63  	// TODO: add commands for API
    64  	return d
    65  }
    66  
    67  // Name returns the Name for the Driver
    68  func (d *GrovePiDriver) Name() string { return d.name }
    69  
    70  // SetName sets the Name for the Driver
    71  func (d *GrovePiDriver) SetName(n string) { d.name = n }
    72  
    73  // Connection returns the connection for the Driver
    74  func (d *GrovePiDriver) Connection() gobot.Connection { return d.connector.(gobot.Connection) }
    75  
    76  // Start initialized the GrovePi
    77  func (d *GrovePiDriver) Start() (err error) {
    78  	bus := d.GetBusOrDefault(d.connector.GetDefaultBus())
    79  	address := d.GetAddressOrDefault(grovePiAddress)
    80  
    81  	d.connection, err = d.connector.GetConnection(address, bus)
    82  	if err != nil {
    83  		return err
    84  	}
    85  
    86  	return
    87  }
    88  
    89  // Halt returns true if devices is halted successfully
    90  func (d *GrovePiDriver) Halt() (err error) { return }
    91  
    92  // Connect is here to implement the Adaptor interface.
    93  func (d *GrovePiDriver) Connect() (err error) {
    94  	return
    95  }
    96  
    97  // Finalize is here to implement the Adaptor interface.
    98  func (d *GrovePiDriver) Finalize() (err error) {
    99  	return
   100  }
   101  
   102  // AnalogRead returns value from analog pin implementing the AnalogReader interface.
   103  func (d *GrovePiDriver) AnalogRead(pin string) (value int, err error) {
   104  	pin = getPin(pin)
   105  
   106  	var pinNum int
   107  	pinNum, err = strconv.Atoi(pin)
   108  	if err != nil {
   109  		return
   110  	}
   111  
   112  	value, err = d.readAnalog(byte(pinNum))
   113  
   114  	return
   115  }
   116  
   117  // DigitalRead performs a read on a digital pin.
   118  func (d *GrovePiDriver) DigitalRead(pin string) (val int, err error) {
   119  	pin = getPin(pin)
   120  
   121  	var pinNum int
   122  	pinNum, err = strconv.Atoi(pin)
   123  	if err != nil {
   124  		return
   125  	}
   126  
   127  	if dir, ok := d.digitalPins[pinNum]; !ok || dir != "input" {
   128  		d.PinMode(byte(pinNum), "input")
   129  		d.digitalPins[pinNum] = "input"
   130  	}
   131  
   132  	val, err = d.readDigital(byte(pinNum))
   133  
   134  	return
   135  }
   136  
   137  // UltrasonicRead performs a read on an ultrasonic pin.
   138  func (d *GrovePiDriver) UltrasonicRead(pin string, duration int) (val int, err error) {
   139  	pin = getPin(pin)
   140  
   141  	var pinNum int
   142  	pinNum, err = strconv.Atoi(pin)
   143  	if err != nil {
   144  		return
   145  	}
   146  
   147  	if dir, ok := d.digitalPins[pinNum]; !ok || dir != "input" {
   148  		d.PinMode(byte(pinNum), "input")
   149  		d.digitalPins[pinNum] = "input"
   150  	}
   151  
   152  	val, err = d.readUltrasonic(byte(pinNum), duration)
   153  
   154  	return
   155  }
   156  
   157  // DigitalWrite writes a value to a specific digital pin implementing the DigitalWriter interface.
   158  func (d *GrovePiDriver) DigitalWrite(pin string, val byte) (err error) {
   159  	pin = getPin(pin)
   160  
   161  	var pinNum int
   162  	pinNum, err = strconv.Atoi(pin)
   163  	if err != nil {
   164  		return
   165  	}
   166  
   167  	if dir, ok := d.digitalPins[pinNum]; !ok || dir != "output" {
   168  		d.PinMode(byte(pinNum), "output")
   169  		d.digitalPins[pinNum] = "output"
   170  	}
   171  
   172  	err = d.writeDigital(byte(pinNum), val)
   173  
   174  	return
   175  }
   176  
   177  // WriteAnalog writes PWM aka analog to the GrovePi. Not yet working.
   178  func (d *GrovePiDriver) WriteAnalog(pin byte, val byte) error {
   179  	buf := []byte{CommandWriteAnalog, pin, val, 0}
   180  	_, err := d.connection.Write(buf)
   181  
   182  	time.Sleep(2 * time.Millisecond)
   183  
   184  	data := make([]byte, 1)
   185  	_, err = d.connection.Read(data)
   186  
   187  	return err
   188  }
   189  
   190  // PinMode sets the pin mode to input or output.
   191  func (d *GrovePiDriver) PinMode(pin byte, mode string) error {
   192  	var b []byte
   193  	if mode == "output" {
   194  		b = []byte{CommandPinMode, pin, 1, 0}
   195  	} else {
   196  		b = []byte{CommandPinMode, pin, 0, 0}
   197  	}
   198  	_, err := d.connection.Write(b)
   199  
   200  	time.Sleep(2 * time.Millisecond)
   201  
   202  	_, err = d.connection.ReadByte()
   203  
   204  	return err
   205  }
   206  
   207  func getPin(pin string) string {
   208  	if len(pin) > 1 {
   209  		if strings.ToUpper(pin[0:1]) == "A" || strings.ToUpper(pin[0:1]) == "D" {
   210  			return pin[1:len(pin)]
   211  		}
   212  	}
   213  
   214  	return pin
   215  }
   216  
   217  // readAnalog reads analog value from the GrovePi.
   218  func (d *GrovePiDriver) readAnalog(pin byte) (int, error) {
   219  	d.mutex.Lock()
   220  	defer d.mutex.Unlock()
   221  
   222  	b := []byte{CommandReadAnalog, pin, 0, 0}
   223  	_, err := d.connection.Write(b)
   224  	if err != nil {
   225  		return 0, err
   226  	}
   227  
   228  	time.Sleep(2 * time.Millisecond)
   229  
   230  	data := make([]byte, 3)
   231  	_, err = d.connection.Read(data)
   232  	if err != nil || data[0] != CommandReadAnalog {
   233  		return -1, err
   234  	}
   235  
   236  	v1 := int(data[1])
   237  	v2 := int(data[2])
   238  	return ((v1 * 256) + v2), nil
   239  }
   240  
   241  // readUltrasonic reads ultrasonic from the GrovePi.
   242  func (d *GrovePiDriver) readUltrasonic(pin byte, duration int) (val int, err error) {
   243  	d.mutex.Lock()
   244  	defer d.mutex.Unlock()
   245  
   246  	buf := []byte{CommandReadUltrasonic, pin, 0, 0}
   247  	_, err = d.connection.Write(buf)
   248  	if err != nil {
   249  		return
   250  	}
   251  
   252  	time.Sleep(time.Duration(duration) * time.Millisecond)
   253  
   254  	data := make([]byte, 3)
   255  	_, err = d.connection.Read(data)
   256  	if err != nil || data[0] != CommandReadUltrasonic {
   257  		return 0, err
   258  	}
   259  
   260  	return int(data[1]) * 255 + int(data[2]), err
   261  }
   262  
   263  // readDigital reads digitally from the GrovePi.
   264  func (d *GrovePiDriver) readDigital(pin byte) (val int, err error) {
   265  	d.mutex.Lock()
   266  	defer d.mutex.Unlock()
   267  
   268  	buf := []byte{CommandReadDigital, pin, 0, 0}
   269  	_, err = d.connection.Write(buf)
   270  	if err != nil {
   271  		return
   272  	}
   273  
   274  	time.Sleep(2 * time.Millisecond)
   275  
   276  	data := make([]byte, 2)
   277  	_, err = d.connection.Read(data)
   278  	if err != nil || data[0] != CommandReadDigital {
   279  		return 0, err
   280  	}
   281  
   282  	return int(data[1]), err
   283  }
   284  
   285  // writeDigital writes digitally to the GrovePi.
   286  func (d *GrovePiDriver) writeDigital(pin byte, val byte) error {
   287  	d.mutex.Lock()
   288  	defer d.mutex.Unlock()
   289  
   290  	buf := []byte{CommandWriteDigital, pin, val, 0}
   291  	_, err := d.connection.Write(buf)
   292  
   293  	time.Sleep(2 * time.Millisecond)
   294  
   295  	_, err = d.connection.ReadByte()
   296  
   297  	return err
   298  }