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 }