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

     1  package i2c
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"gobot.io/x/gobot"
    10  	"gobot.io/x/gobot/drivers/gpio"
    11  )
    12  
    13  const adafruit1109Debug = false
    14  
    15  type adafruit1109PortPin struct {
    16  	port string
    17  	pin  uint8
    18  }
    19  
    20  // have to implement DigitalWriter, DigitalReader interface
    21  type Adafruit1109Driver struct {
    22  	name string
    23  	*MCP23017Driver
    24  	redPin    adafruit1109PortPin
    25  	greenPin  adafruit1109PortPin
    26  	bluePin   adafruit1109PortPin
    27  	selectPin adafruit1109PortPin
    28  	upPin     adafruit1109PortPin
    29  	downPin   adafruit1109PortPin
    30  	leftPin   adafruit1109PortPin
    31  	rightPin  adafruit1109PortPin
    32  	rwPin     adafruit1109PortPin
    33  	rsPin     adafruit1109PortPin
    34  	enPin     adafruit1109PortPin
    35  	dataPinD4 adafruit1109PortPin
    36  	dataPinD5 adafruit1109PortPin
    37  	dataPinD6 adafruit1109PortPin
    38  	dataPinD7 adafruit1109PortPin
    39  	*gpio.HD44780Driver
    40  }
    41  
    42  // Adafruit1109Driver is a driver for the 2x16 LCD display with RGB backlit and 5 keys from adafruit, designed for Pi.
    43  // The display is driven by the HD44780, and all is connected by i2c port expander MCP23017.
    44  // https://www.adafruit.com/product/1109
    45  //
    46  // Because both are already implemented in gobot, we creates a wrapper for using existing implementation.
    47  // So, for the documentation of the parameters, have a look at this drivers.
    48  //
    49  // Tests are done with a tinkerboard.
    50  func NewAdafruit1109Driver(a Connector, options ...func(Config)) *Adafruit1109Driver {
    51  	options = append(options, WithMCP23017AutoIODirOff(1))
    52  	mcp := NewMCP23017Driver(a, options...)
    53  	m := &Adafruit1109Driver{
    54  		name:           gobot.DefaultName("Adafruit1109"),
    55  		MCP23017Driver: mcp,
    56  		redPin:         adafruit1109PortPin{"A", 6},
    57  		greenPin:       adafruit1109PortPin{"A", 7},
    58  		bluePin:        adafruit1109PortPin{"B", 0},
    59  		selectPin:      adafruit1109PortPin{"A", 0},
    60  		upPin:          adafruit1109PortPin{"A", 3},
    61  		downPin:        adafruit1109PortPin{"A", 2},
    62  		leftPin:        adafruit1109PortPin{"A", 4},
    63  		rightPin:       adafruit1109PortPin{"A", 1},
    64  		rwPin:          adafruit1109PortPin{"B", 6},
    65  		rsPin:          adafruit1109PortPin{"B", 7},
    66  		enPin:          adafruit1109PortPin{"B", 5},
    67  		dataPinD4:      adafruit1109PortPin{"B", 4},
    68  		dataPinD5:      adafruit1109PortPin{"B", 3},
    69  		dataPinD6:      adafruit1109PortPin{"B", 2},
    70  		dataPinD7:      adafruit1109PortPin{"B", 1},
    71  	}
    72  	// mapping for HD44780 to MCP23017 port and IO, 4-Bit data
    73  	dataPins := gpio.HD44780DataPin{
    74  		D4: m.dataPinD4.String(),
    75  		D5: m.dataPinD5.String(),
    76  		D6: m.dataPinD6.String(),
    77  		D7: m.dataPinD7.String(),
    78  	}
    79  
    80  	//rwPin := "B_6" not mapped in HD44780 driver
    81  	// at test initialization, there seems rows and columns be switched
    82  	// but inside the driver the row is used as row and col as column
    83  	rows := 2
    84  	columns := 16
    85  	lcd := gpio.NewHD44780Driver(m, columns, rows, gpio.HD44780_4BITMODE, m.rsPin.String(), m.enPin.String(), dataPins)
    86  	lcd.SetRWPin(m.rwPin.String())
    87  	m.HD44780Driver = lcd
    88  	return m
    89  }
    90  
    91  // gobot.Connection interface
    92  func (m *Adafruit1109Driver) Name() string {
    93  	return fmt.Sprintf("%s_%s_%s", m.name, m.MCP23017Driver.Name(), m.HD44780Driver.Name())
    94  }
    95  func (m *Adafruit1109Driver) SetName(n string) { m.name = n }
    96  
    97  // gobot.Device interface
    98  func (m *Adafruit1109Driver) Connection() gobot.Connection { return m.MCP23017Driver.Connection() }
    99  func (m *Adafruit1109Driver) Halt() (err error)            { return m.MCP23017Driver.Halt() }
   100  
   101  func (m *Adafruit1109Driver) Start() (err error) {
   102  	if adafruit1109Debug {
   103  		log.Printf("## MCP.Start ##")
   104  	}
   105  	if err = m.MCP23017Driver.Start(); err != nil {
   106  		return err
   107  	}
   108  
   109  	// set all to output (inputs will be set by initButton)
   110  	for pin := uint8(0); pin <= 7; pin++ {
   111  		if err := m.PinMode(pin, 0, "A"); err != nil {
   112  			return err
   113  		}
   114  		if err := m.PinMode(pin, 0, "B"); err != nil {
   115  			return err
   116  		}
   117  	}
   118  
   119  	// button pins are inputs, has inverse logic and needs pull up
   120  	if err := m.adafruit1109InitButton(m.selectPin); err != nil {
   121  		return err
   122  	}
   123  	if err := m.adafruit1109InitButton(m.upPin); err != nil {
   124  		return err
   125  	}
   126  	if err := m.adafruit1109InitButton(m.downPin); err != nil {
   127  		return err
   128  	}
   129  	if err := m.adafruit1109InitButton(m.leftPin); err != nil {
   130  		return err
   131  	}
   132  	if err := m.adafruit1109InitButton(m.rightPin); err != nil {
   133  		return err
   134  	}
   135  
   136  	// lets start with neutral background
   137  	if err = m.SetRGB(true, true, true); err != nil {
   138  		return err
   139  	}
   140  	// set rw pin to write
   141  	if err := m.writePin(m.rwPin, 0x00); err != nil {
   142  		return err
   143  	}
   144  	if adafruit1109Debug {
   145  		log.Printf("## HD.Start ##")
   146  	}
   147  	return m.HD44780Driver.Start()
   148  }
   149  
   150  // DigitalWriter interface
   151  // This is called by HD44780 driver to set one gpio output. We redirect the call to the i2c driver MCP23017.
   152  // The given id is the same as defined in dataPins and has the syntax "<port>_<pin>".
   153  func (m *Adafruit1109Driver) DigitalWrite(id string, val byte) (err error) {
   154  	portio := adafruit1109ParseId(id)
   155  	return m.writePin(portio, val)
   156  }
   157  
   158  // DigitalReader interface
   159  // This is called by HD44780 driver to read one gpio input. We redirect the call to the i2c driver MCP23017.
   160  // The given id is the same as defined in dataPins and has the syntax "<port>_<pin>".
   161  func (m *Adafruit1109Driver) DigitalRead(id string) (val int, err error) {
   162  	portio := adafruit1109ParseId(id)
   163  	uval, err := m.readPin(portio)
   164  	if err != nil {
   165  		return 0, err
   166  	}
   167  	return int(uval), err
   168  }
   169  
   170  // Connector interface, haven't found any adaptor which implements this with more content
   171  func (m *Adafruit1109Driver) Connect() (err error)  { return }
   172  func (m *Adafruit1109Driver) Finalize() (err error) { return }
   173  
   174  // SetRGB sets the Red Green Blue value of backlit.
   175  // The MCP23017 variant don't support PWM and have inverted logic
   176  func (m *Adafruit1109Driver) SetRGB(r, g, b bool) error {
   177  	if adafruit1109Debug {
   178  		log.Printf("## SetRGB %t, %t, %t ##", r, g, b)
   179  	}
   180  	rio := m.redPin
   181  	gio := m.greenPin
   182  	bio := m.bluePin
   183  	rval := uint8(0x1)
   184  	gval := uint8(0x1)
   185  	bval := uint8(0x1)
   186  	if r {
   187  		rval = 0x00
   188  	}
   189  	if g {
   190  		gval = 0x00
   191  	}
   192  	if b {
   193  		bval = 0x00
   194  	}
   195  
   196  	if err := m.writePin(rio, rval); err != nil {
   197  		return err
   198  	}
   199  
   200  	if err := m.writePin(gio, gval); err != nil {
   201  		return err
   202  	}
   203  
   204  	if err := m.writePin(bio, bval); err != nil {
   205  		return err
   206  	}
   207  	return nil
   208  }
   209  
   210  func (m *Adafruit1109Driver) SelectButton() (uint8, error) {
   211  	return m.readPin(m.selectPin)
   212  }
   213  
   214  func (m *Adafruit1109Driver) UpButton() (uint8, error) {
   215  	return m.readPin(m.upPin)
   216  }
   217  
   218  func (m *Adafruit1109Driver) DownButton() (uint8, error) {
   219  	return m.readPin(m.downPin)
   220  }
   221  
   222  func (m *Adafruit1109Driver) LeftButton() (uint8, error) {
   223  	return m.readPin(m.leftPin)
   224  }
   225  
   226  func (m *Adafruit1109Driver) RightButton() (uint8, error) {
   227  	return m.readPin(m.rightPin)
   228  }
   229  
   230  func (m *Adafruit1109Driver) writePin(ap adafruit1109PortPin, val uint8) (err error) {
   231  	return m.WriteGPIO(ap.pin, val, ap.port)
   232  }
   233  
   234  func (m *Adafruit1109Driver) readPin(ap adafruit1109PortPin) (uint8, error) {
   235  	return m.ReadGPIO(ap.pin, ap.port)
   236  }
   237  
   238  func (ap *adafruit1109PortPin) String() string {
   239  	return fmt.Sprintf("%s_%d", ap.port, ap.pin)
   240  }
   241  
   242  func adafruit1109ParseId(id string) adafruit1109PortPin {
   243  	items := strings.Split(id, "_")
   244  	io := uint8(0)
   245  	if io64, err := strconv.ParseUint(items[1], 10, 32); err == nil {
   246  		io = uint8(io64)
   247  	}
   248  	return adafruit1109PortPin{port: items[0], pin: io}
   249  }
   250  
   251  func (m *Adafruit1109Driver) adafruit1109InitButton(p adafruit1109PortPin) error {
   252  	// make an input
   253  	if err := m.PinMode(p.pin, 1, p.port); err != nil {
   254  		return err
   255  	}
   256  	// add pull up resistors
   257  	if err := m.SetPullUp(p.pin, 1, p.port); err != nil {
   258  		return err
   259  	}
   260  	// invert polarity
   261  	if err := m.SetGPIOPolarity(p.pin, 1, p.port); err != nil {
   262  		return err
   263  	}
   264  	return nil
   265  }