Secfest2026BadgeCode/hardware_test/.pio/libdeps/rp2040_usb/Adafruit IS31FL3731 Library/Adafruit_IS31FL3731.cpp

274 lines
8.4 KiB
C++

#include <Adafruit_IS31FL3731.h>
#ifndef _swap_int16_t
#define _swap_int16_t(a, b) \
{ \
int16_t t = a; \
a = b; \
b = t; \
}
#endif
/**************************************************************************/
/*!
@brief Constructor for breakout version
@param width Desired width of led display
@param height Desired height of led display
*/
/**************************************************************************/
Adafruit_IS31FL3731::Adafruit_IS31FL3731(uint8_t width, uint8_t height)
: Adafruit_GFX(width, height) {}
/**************************************************************************/
/*!
@brief Constructor for FeatherWing version (15x7 LEDs)
*/
/**************************************************************************/
Adafruit_IS31FL3731_Wing::Adafruit_IS31FL3731_Wing(void)
: Adafruit_IS31FL3731(15, 7) {}
/**************************************************************************/
/*!
@brief Initialize hardware and clear display
@param addr The I2C address we expect to find the chip at
@param theWire The TwoWire I2C bus device to use, defaults to &Wire
@returns True on success, false if chip isnt found
*/
/**************************************************************************/
bool Adafruit_IS31FL3731::begin(uint8_t addr, TwoWire *theWire) {
if (_i2c_dev) {
delete _i2c_dev;
}
_i2c_dev = new Adafruit_I2CDevice(addr, theWire);
if (!_i2c_dev->begin()) {
return false;
}
_i2c_dev->setSpeed(400000);
_frame = 0;
// shutdown
writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_SHUTDOWN, 0x00);
delay(10);
// out of shutdown
writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_SHUTDOWN, 0x01);
// picture mode
writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_CONFIG,
ISSI_REG_CONFIG_PICTUREMODE);
displayFrame(_frame);
// all LEDs on & 0 PWM
clear(); // set each led to 0 PWM
for (uint8_t f = 0; f < 8; f++) {
for (uint8_t i = 0; i <= 0x11; i++)
writeRegister8(f, i, 0xff); // each 8 LEDs on
}
audioSync(false);
return true;
}
/**************************************************************************/
/*!
@brief Sets all LEDs on & 0 PWM for current frame.
*/
/**************************************************************************/
void Adafruit_IS31FL3731::clear(void) {
selectBank(_frame);
uint8_t erasebuf[25];
memset(erasebuf, 0, 25);
for (uint8_t i = 0; i < 6; i++) {
erasebuf[0] = 0x24 + i * 24;
_i2c_dev->write(erasebuf, 25);
}
}
/**************************************************************************/
/*!
@brief Low level accesssor - sets a 8-bit PWM pixel value to a bank location
does not handle rotation, x/y or any rearrangements!
@param lednum The offset into the bank that corresponds to the LED
@param bank The bank/frame we will set the data in
@param pwm brightnes, from 0 (off) to 255 (max on)
*/
/**************************************************************************/
void Adafruit_IS31FL3731::setLEDPWM(uint8_t lednum, uint8_t pwm, uint8_t bank) {
if (lednum >= 144)
return;
writeRegister8(bank, 0x24 + lednum, pwm);
}
/**************************************************************************/
/*!
@brief Adafruit GFX low level accesssor - sets a 8-bit PWM pixel value
handles rotation and pixel arrangement, unlike setLEDPWM
@param x The x position, starting with 0 for left-most side
@param y The y position, starting with 0 for top-most side
@param color Despite being a 16-bit value, takes 0 (off) to 255 (max on)
*/
/**************************************************************************/
void Adafruit_IS31FL3731_Wing::drawPixel(int16_t x, int16_t y, uint16_t color) {
// check rotation, move pixel around if necessary
switch (getRotation()) {
case 1:
_swap_int16_t(x, y);
x = 15 - x - 1;
break;
case 2:
x = 15 - x - 1;
y = 7 - y - 1;
break;
case 3:
_swap_int16_t(x, y);
y = 9 - y - 1;
break;
}
// charlie wing is smaller:
if ((x < 0) || (x >= 16) || (y < 0) || (y >= 7))
return;
if (x > 7) {
x = 15 - x;
y += 8;
} else {
y = 7 - y;
}
_swap_int16_t(x, y);
if (color > 255)
color = 255; // PWM 8bit max
setLEDPWM(x + y * 16, color, _frame);
return;
}
/**************************************************************************/
/*!
@brief Adafruit GFX low level accesssor - sets a 8-bit PWM pixel value
handles rotation and pixel arrangement, unlike setLEDPWM
@param x The x position, starting with 0 for left-most side
@param y The y position, starting with 0 for top-most side
@param color Despite being a 16-bit value, takes 0 (off) to 255 (max on)
*/
/**************************************************************************/
void Adafruit_IS31FL3731::drawPixel(int16_t x, int16_t y, uint16_t color) {
// check rotation, move pixel around if necessary
switch (getRotation()) {
case 1:
_swap_int16_t(x, y);
x = 16 - x - 1;
break;
case 2:
x = 16 - x - 1;
y = 9 - y - 1;
break;
case 3:
_swap_int16_t(x, y);
y = 9 - y - 1;
break;
}
if ((x < 0) || (x >= 16))
return;
if ((y < 0) || (y >= 9))
return;
if (color > 255)
color = 255; // PWM 8bit max
setLEDPWM(x + y * 16, color, _frame);
return;
}
/**************************************************************************/
/*!
@brief Set's this object's frame tracker (does not talk to the chip)
@param frame Ranges from 0 - 7 for the 8 frames
*/
/**************************************************************************/
void Adafruit_IS31FL3731::setFrame(uint8_t frame) { _frame = frame; }
/**************************************************************************/
/*!
@brief Have the chip set the display to the contents of a frame
@param frame Ranges from 0 - 7 for the 8 frames
*/
/**************************************************************************/
void Adafruit_IS31FL3731::displayFrame(uint8_t frame) {
if (frame > 7)
frame = 0;
writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_PICTUREFRAME, frame);
}
/**************************************************************************/
/*!
@brief Switch to a given bank in the chip memory for future reads
@param bank The IS31 bank to switch to
@returns False if I2C command failed to be ack'd
*/
/**************************************************************************/
bool Adafruit_IS31FL3731::selectBank(uint8_t bank) {
uint8_t cmd[2] = {ISSI_COMMANDREGISTER, bank};
return _i2c_dev->write(cmd, 2);
}
/**************************************************************************/
/*!
@brief Enable the audio 'sync' for brightness pulsing (not really tested)
@param sync True to enable, False to disable
*/
/**************************************************************************/
void Adafruit_IS31FL3731::audioSync(bool sync) {
if (sync) {
writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_AUDIOSYNC, 0x1);
} else {
writeRegister8(ISSI_BANK_FUNCTIONREG, ISSI_REG_AUDIOSYNC, 0x0);
}
}
/**************************************************************************/
/*!
@brief Write one byte to a register located in a given bank
@param bank The IS31 bank to write the register location
@param reg the offset into the bank to write
@param data The byte value
@returns False if I2C command failed to be ack'd
*/
/**************************************************************************/
bool Adafruit_IS31FL3731::writeRegister8(uint8_t bank, uint8_t reg,
uint8_t data) {
selectBank(bank);
uint8_t cmd[2] = {reg, data};
return _i2c_dev->write(cmd, 2);
}
/**************************************************************************/
/*!
@brief Read one byte from a register located in a given bank
@param bank The IS31 bank to read the register location
@param reg the offset into the bank to read
@return 1 byte value
*/
/**************************************************************************/
uint8_t Adafruit_IS31FL3731::readRegister8(uint8_t bank, uint8_t reg) {
uint8_t val = 0xFF;
selectBank(bank);
_i2c_dev->write_then_read(&reg, 1, &val, 1);
return val;
}