193 lines
4.3 KiB
Go
193 lines
4.3 KiB
Go
package gpio
|
|
|
|
import (
|
|
"time"
|
|
|
|
"gobot.io/x/gobot/v2"
|
|
)
|
|
|
|
// Commands of the driver
|
|
const (
|
|
AIP1640DataCmd = 0x40
|
|
AIP1640DispCtrl = 0x88
|
|
AIP1640AddrCmd = 0xC0
|
|
|
|
AIP1640FixedAddr = 0x04
|
|
)
|
|
|
|
// AIP1640Driver is the gobot driver for the AIP1640 LED driver used in the WEMOS D1 mini Matrix LED Shield.
|
|
// It has some similarities with the TM16xx LED drivers
|
|
//
|
|
// Datasheet CN: https://datasheet.lcsc.com/szlcsc/AiP1640_C82650.pdf
|
|
//
|
|
// Library ported from: https://github.com/wemos/WEMOS_Matrix_LED_Shield_Arduino_Library
|
|
type AIP1640Driver struct {
|
|
pinClock *DirectPinDriver
|
|
pinData *DirectPinDriver
|
|
name string
|
|
intensity byte
|
|
buffer [8]byte
|
|
connection gobot.Connection
|
|
gobot.Commander
|
|
}
|
|
|
|
// NewAIP1640Driver return a new AIP1640Driver given a gobot.Connection and the clock, data and strobe pins
|
|
func NewAIP1640Driver(a gobot.Connection, clockPin string, dataPin string) *AIP1640Driver {
|
|
t := &AIP1640Driver{
|
|
name: gobot.DefaultName("AIP1640Driver"),
|
|
pinClock: NewDirectPinDriver(a, clockPin),
|
|
pinData: NewDirectPinDriver(a, dataPin),
|
|
intensity: 7,
|
|
connection: a,
|
|
Commander: gobot.NewCommander(),
|
|
}
|
|
|
|
/* TODO : Add commands */
|
|
|
|
return t
|
|
}
|
|
|
|
// Start initializes the tm1638, it uses a SPI-like communication protocol
|
|
func (a *AIP1640Driver) Start() error {
|
|
if err := a.pinData.On(); err != nil {
|
|
return err
|
|
}
|
|
return a.pinClock.On()
|
|
}
|
|
|
|
// Halt implements the Driver interface
|
|
func (a *AIP1640Driver) Halt() error { return nil }
|
|
|
|
// Name returns the AIP1640Drivers name
|
|
func (a *AIP1640Driver) Name() string { return a.name }
|
|
|
|
// SetName sets the AIP1640Drivers name
|
|
func (a *AIP1640Driver) SetName(n string) { a.name = n }
|
|
|
|
// Connection returns the AIP1640Driver Connection
|
|
func (a *AIP1640Driver) Connection() gobot.Connection {
|
|
return a.connection
|
|
}
|
|
|
|
// SetIntensity changes the intensity (from 1 to 7) of the display
|
|
func (a *AIP1640Driver) SetIntensity(level byte) {
|
|
if level >= 7 {
|
|
level = 7
|
|
}
|
|
a.intensity = level
|
|
}
|
|
|
|
// Display sends the buffer to the display (ie. turns on/off the corresponding LEDs)
|
|
func (a *AIP1640Driver) Display() error {
|
|
for i := 0; i < 8; i++ {
|
|
if err := a.sendData(byte(i), a.buffer[i]); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := a.pinData.Off(); err != nil {
|
|
return err
|
|
}
|
|
if err := a.pinClock.Off(); err != nil {
|
|
return err
|
|
}
|
|
time.Sleep(1 * time.Millisecond)
|
|
if err := a.pinClock.On(); err != nil {
|
|
return err
|
|
}
|
|
if err := a.pinData.On(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return a.sendCommand(AIP1640DispCtrl | a.intensity)
|
|
}
|
|
|
|
// Clear empties the buffer (turns off all the LEDs)
|
|
func (a *AIP1640Driver) Clear() {
|
|
for i := 0; i < 8; i++ {
|
|
a.buffer[i] = 0x00
|
|
}
|
|
}
|
|
|
|
// DrawPixel turns on or off a specific in the buffer
|
|
func (a *AIP1640Driver) DrawPixel(x, y byte, enabled bool) {
|
|
if x >= 8 || y >= 8 {
|
|
return
|
|
}
|
|
y = 7 - y
|
|
if enabled {
|
|
a.buffer[y] |= 1 << x
|
|
} else {
|
|
a.buffer[y] &^= 1 << x
|
|
}
|
|
}
|
|
|
|
// DrawRow sets any given row of LEDs in the buffer
|
|
func (a *AIP1640Driver) DrawRow(row, data byte) {
|
|
if row >= 8 {
|
|
return
|
|
}
|
|
a.buffer[7-row] = data
|
|
}
|
|
|
|
// DrawMatrix sets the whole buffer
|
|
func (a *AIP1640Driver) DrawMatrix(data [8]byte) {
|
|
for i := 0; i < 8; i++ {
|
|
a.buffer[7-i] = data[i]
|
|
}
|
|
}
|
|
|
|
// sendCommand is an auxiliary function to send commands to the AIP1640Driver module
|
|
func (a *AIP1640Driver) sendCommand(cmd byte) error {
|
|
if err := a.pinData.Off(); err != nil {
|
|
return err
|
|
}
|
|
if err := a.send(cmd); err != nil {
|
|
return err
|
|
}
|
|
return a.pinData.On()
|
|
}
|
|
|
|
// sendData is an auxiliary function to send data to the AIP1640Driver module
|
|
func (a *AIP1640Driver) sendData(address byte, data byte) error {
|
|
if err := a.sendCommand(AIP1640DataCmd | AIP1640FixedAddr); err != nil {
|
|
return err
|
|
}
|
|
if err := a.pinData.Off(); err != nil {
|
|
return err
|
|
}
|
|
if err := a.send(AIP1640AddrCmd | address); err != nil {
|
|
return err
|
|
}
|
|
if err := a.send(data); err != nil {
|
|
return err
|
|
}
|
|
return a.pinData.On()
|
|
}
|
|
|
|
// send writes data on the module
|
|
func (a *AIP1640Driver) send(data byte) error {
|
|
for i := 0; i < 8; i++ {
|
|
if err := a.pinClock.Off(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if (data & 1) > 0 {
|
|
if err := a.pinData.On(); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if err := a.pinData.Off(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
data >>= 1
|
|
|
|
if err := a.pinClock.On(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|