parent
b7bb923962
commit
16de11fbc5
@ -0,0 +1,232 @@
|
|||||||
|
/*
|
||||||
|
* TWIlib.c
|
||||||
|
*
|
||||||
|
* Created: 6/01/2014 10:41:33 PM
|
||||||
|
* Author: Chris Herring
|
||||||
|
* http://www.chrisherring.net/all/tutorial-interrupt-driven-twi-interface-for-avr-part1/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include "TWIlib.h"
|
||||||
|
#include "util/delay.h"
|
||||||
|
|
||||||
|
void TWIInit()
|
||||||
|
{
|
||||||
|
TWIInfo.mode = Ready;
|
||||||
|
TWIInfo.errorCode = 0xFF;
|
||||||
|
TWIInfo.repStart = 0;
|
||||||
|
// Set pre-scalers (no pre-scaling)
|
||||||
|
TWSR = 0;
|
||||||
|
// Set bit rate
|
||||||
|
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
|
||||||
|
// Enable TWI and interrupt
|
||||||
|
TWCR = (1 << TWIE) | (1 << TWEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t isTWIReady()
|
||||||
|
{
|
||||||
|
if ( (TWIInfo.mode == Ready) | (TWIInfo.mode == RepeatedStartSent) )
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart)
|
||||||
|
{
|
||||||
|
if (dataLen <= TXMAXBUFLEN)
|
||||||
|
{
|
||||||
|
// Wait until ready
|
||||||
|
while (!isTWIReady()) {_delay_us(1);}
|
||||||
|
// Set repeated start mode
|
||||||
|
TWIInfo.repStart = repStart;
|
||||||
|
// Copy data into the transmit buffer
|
||||||
|
uint8_t *data = (uint8_t *)TXdata;
|
||||||
|
for (int i = 0; i < dataLen; i++)
|
||||||
|
{
|
||||||
|
TWITransmitBuffer[i] = data[i];
|
||||||
|
}
|
||||||
|
// Copy transmit info to global variables
|
||||||
|
TXBuffLen = dataLen;
|
||||||
|
TXBuffIndex = 0;
|
||||||
|
|
||||||
|
// If a repeated start has been sent, then devices are already listening for an address
|
||||||
|
// and another start does not need to be sent.
|
||||||
|
if (TWIInfo.mode == RepeatedStartSent)
|
||||||
|
{
|
||||||
|
TWIInfo.mode = Initializing;
|
||||||
|
TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
|
||||||
|
TWISendTransmit(); // Send the data
|
||||||
|
}
|
||||||
|
else // Otherwise, just send the normal start signal to begin transmission.
|
||||||
|
{
|
||||||
|
TWIInfo.mode = Initializing;
|
||||||
|
TWISendStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 1; // return an error if data length is longer than buffer
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t TWIReadData(uint8_t TWIaddr, uint8_t bytesToRead, uint8_t repStart)
|
||||||
|
{
|
||||||
|
// Check if number of bytes to read can fit in the RXbuffer
|
||||||
|
if (bytesToRead < RXMAXBUFLEN)
|
||||||
|
{
|
||||||
|
// Reset buffer index and set RXBuffLen to the number of bytes to read
|
||||||
|
RXBuffIndex = 0;
|
||||||
|
RXBuffLen = bytesToRead;
|
||||||
|
// Create the one value array for the address to be transmitted
|
||||||
|
uint8_t TXdata[1];
|
||||||
|
// Shift the address and AND a 1 into the read write bit (set to write mode)
|
||||||
|
TXdata[0] = (TWIaddr << 1) | 0x01;
|
||||||
|
// Use the TWITransmitData function to initialize the transfer and address the slave
|
||||||
|
TWITransmitData(TXdata, 1, repStart);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR (TWI_vect)
|
||||||
|
{
|
||||||
|
switch (TWI_STATUS)
|
||||||
|
{
|
||||||
|
// ----\/ ---- MASTER TRANSMITTER OR WRITING ADDRESS ----\/ ---- //
|
||||||
|
case TWI_MT_SLAW_ACK: // SLA+W transmitted and ACK received
|
||||||
|
// Set mode to Master Transmitter
|
||||||
|
TWIInfo.mode = MasterTransmitter;
|
||||||
|
case TWI_START_SENT: // Start condition has been transmitted
|
||||||
|
case TWI_MT_DATA_ACK: // Data byte has been transmitted, ACK received
|
||||||
|
if (TXBuffIndex < TXBuffLen) // If there is more data to send
|
||||||
|
{
|
||||||
|
TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
|
||||||
|
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||||
|
TWISendTransmit(); // Send the data
|
||||||
|
}
|
||||||
|
// This transmission is complete however do not release bus yet
|
||||||
|
else if (TWIInfo.repStart)
|
||||||
|
{
|
||||||
|
TWIInfo.errorCode = 0xFF;
|
||||||
|
TWISendStart();
|
||||||
|
}
|
||||||
|
// All transmissions are complete, exit
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TWIInfo.mode = Ready;
|
||||||
|
TWIInfo.errorCode = 0xFF;
|
||||||
|
TWISendStop();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// ----\/ ---- MASTER RECEIVER ----\/ ---- //
|
||||||
|
|
||||||
|
case TWI_MR_SLAR_ACK: // SLA+R has been transmitted, ACK has been received
|
||||||
|
// Switch to Master Receiver mode
|
||||||
|
TWIInfo.mode = MasterReceiver;
|
||||||
|
// If there is more than one byte to be read, receive data byte and return an ACK
|
||||||
|
if (RXBuffIndex < RXBuffLen-1)
|
||||||
|
{
|
||||||
|
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||||
|
TWISendACK();
|
||||||
|
}
|
||||||
|
// Otherwise when a data byte (the only data byte) is received, return NACK
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||||
|
TWISendNACK();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TWI_MR_DATA_ACK: // Data has been received, ACK has been transmitted.
|
||||||
|
|
||||||
|
/// -- HANDLE DATA BYTE --- ///
|
||||||
|
TWIReceiveBuffer[RXBuffIndex++] = TWDR;
|
||||||
|
// If there is more than one byte to be read, receive data byte and return an ACK
|
||||||
|
if (RXBuffIndex < RXBuffLen-1)
|
||||||
|
{
|
||||||
|
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||||
|
TWISendACK();
|
||||||
|
}
|
||||||
|
// Otherwise when a data byte (the only data byte) is received, return NACK
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||||
|
TWISendNACK();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TWI_MR_DATA_NACK: // Data byte has been received, NACK has been transmitted. End of transmission.
|
||||||
|
|
||||||
|
/// -- HANDLE DATA BYTE --- ///
|
||||||
|
TWIReceiveBuffer[RXBuffIndex++] = TWDR;
|
||||||
|
// This transmission is complete however do not release bus yet
|
||||||
|
if (TWIInfo.repStart)
|
||||||
|
{
|
||||||
|
TWIInfo.errorCode = 0xFF;
|
||||||
|
TWISendStart();
|
||||||
|
}
|
||||||
|
// All transmissions are complete, exit
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TWIInfo.mode = Ready;
|
||||||
|
TWIInfo.errorCode = 0xFF;
|
||||||
|
TWISendStop();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// ----\/ ---- MT and MR common ----\/ ---- //
|
||||||
|
|
||||||
|
case TWI_MR_SLAR_NACK: // SLA+R transmitted, NACK received
|
||||||
|
case TWI_MT_SLAW_NACK: // SLA+W transmitted, NACK received
|
||||||
|
case TWI_MT_DATA_NACK: // Data byte has been transmitted, NACK received
|
||||||
|
case TWI_LOST_ARBIT: // Arbitration has been lost
|
||||||
|
// Return error and send stop and set mode to ready
|
||||||
|
if (TWIInfo.repStart)
|
||||||
|
{
|
||||||
|
TWIInfo.errorCode = TWI_STATUS;
|
||||||
|
TWISendStart();
|
||||||
|
}
|
||||||
|
// All transmissions are complete, exit
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TWIInfo.mode = Ready;
|
||||||
|
TWIInfo.errorCode = TWI_STATUS;
|
||||||
|
TWISendStop();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TWI_REP_START_SENT: // Repeated start has been transmitted
|
||||||
|
// Set the mode but DO NOT clear TWINT as the next data is not yet ready
|
||||||
|
TWIInfo.mode = RepeatedStartSent;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// ----\/ ---- SLAVE RECEIVER ----\/ ---- //
|
||||||
|
|
||||||
|
// TODO IMPLEMENT SLAVE RECEIVER FUNCTIONALITY
|
||||||
|
|
||||||
|
// ----\/ ---- SLAVE TRANSMITTER ----\/ ---- //
|
||||||
|
|
||||||
|
// TODO IMPLEMENT SLAVE TRANSMITTER FUNCTIONALITY
|
||||||
|
|
||||||
|
// ----\/ ---- MISCELLANEOUS STATES ----\/ ---- //
|
||||||
|
case TWI_NO_RELEVANT_INFO: // It is not really possible to get into this ISR on this condition
|
||||||
|
// Rather, it is there to be manually set between operations
|
||||||
|
break;
|
||||||
|
case TWI_ILLEGAL_START_STOP: // Illegal START/STOP, abort and return error
|
||||||
|
TWIInfo.errorCode = TWI_ILLEGAL_START_STOP;
|
||||||
|
TWIInfo.mode = Ready;
|
||||||
|
TWISendStop();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* TWIlib.h
|
||||||
|
*
|
||||||
|
* Created: 6/01/2014 10:38:42 PM
|
||||||
|
* Author: Chris Herring
|
||||||
|
* http://www.chrisherring.net/all/tutorial-interrupt-driven-twi-interface-for-avr-part1/
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TWILIB_H_
|
||||||
|
#define TWILIB_H_
|
||||||
|
// TWI bit rate (was 100000)
|
||||||
|
#define TWI_FREQ 400000
|
||||||
|
// Get TWI status
|
||||||
|
#define TWI_STATUS (TWSR & 0xF8)
|
||||||
|
// Transmit buffer length
|
||||||
|
#define TXMAXBUFLEN 20
|
||||||
|
// Receive buffer length
|
||||||
|
#define RXMAXBUFLEN 20
|
||||||
|
// Global transmit buffer
|
||||||
|
uint8_t TWITransmitBuffer[TXMAXBUFLEN];
|
||||||
|
// Global receive buffer
|
||||||
|
volatile uint8_t TWIReceiveBuffer[RXMAXBUFLEN];
|
||||||
|
// Buffer indexes
|
||||||
|
volatile int TXBuffIndex; // Index of the transmit buffer. Is volatile, can change at any time.
|
||||||
|
int RXBuffIndex; // Current index in the receive buffer
|
||||||
|
// Buffer lengths
|
||||||
|
int TXBuffLen; // The total length of the transmit buffer
|
||||||
|
int RXBuffLen; // The total number of bytes to read (should be less than RXMAXBUFFLEN)
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
Ready,
|
||||||
|
Initializing,
|
||||||
|
RepeatedStartSent,
|
||||||
|
MasterTransmitter,
|
||||||
|
MasterReceiver,
|
||||||
|
SlaceTransmitter,
|
||||||
|
SlaveReciever
|
||||||
|
} TWIMode;
|
||||||
|
|
||||||
|
typedef struct TWIInfoStruct{
|
||||||
|
TWIMode mode;
|
||||||
|
uint8_t errorCode;
|
||||||
|
uint8_t repStart;
|
||||||
|
}TWIInfoStruct;
|
||||||
|
TWIInfoStruct TWIInfo;
|
||||||
|
|
||||||
|
|
||||||
|
// TWI Status Codes
|
||||||
|
#define TWI_START_SENT 0x08 // Start sent
|
||||||
|
#define TWI_REP_START_SENT 0x10 // Repeated Start sent
|
||||||
|
// Master Transmitter Mode
|
||||||
|
#define TWI_MT_SLAW_ACK 0x18 // SLA+W sent and ACK received
|
||||||
|
#define TWI_MT_SLAW_NACK 0x20 // SLA+W sent and NACK received
|
||||||
|
#define TWI_MT_DATA_ACK 0x28 // DATA sent and ACK received
|
||||||
|
#define TWI_MT_DATA_NACK 0x30 // DATA sent and NACK received
|
||||||
|
// Master Receiver Mode
|
||||||
|
#define TWI_MR_SLAR_ACK 0x40 // SLA+R sent, ACK received
|
||||||
|
#define TWI_MR_SLAR_NACK 0x48 // SLA+R sent, NACK received
|
||||||
|
#define TWI_MR_DATA_ACK 0x50 // Data received, ACK returned
|
||||||
|
#define TWI_MR_DATA_NACK 0x58 // Data received, NACK returned
|
||||||
|
|
||||||
|
// Miscellaneous States
|
||||||
|
#define TWI_LOST_ARBIT 0x38 // Arbitration has been lost
|
||||||
|
#define TWI_NO_RELEVANT_INFO 0xF8 // No relevant information available
|
||||||
|
#define TWI_ILLEGAL_START_STOP 0x00 // Illegal START or STOP condition has been detected
|
||||||
|
#define TWI_SUCCESS 0xFF // Successful transfer, this state is impossible from TWSR as bit2 is 0 and read only
|
||||||
|
|
||||||
|
|
||||||
|
#define TWISendStart() (TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(1<<TWIE)) // Send the START signal, enable interrupts and TWI, clear TWINT flag to resume transfer.
|
||||||
|
#define TWISendStop() (TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN)|(1<<TWIE)) // Send the STOP signal, enable interrupts and TWI, clear TWINT flag.
|
||||||
|
#define TWISendTransmit() (TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)) // Used to resume a transfer, clear TWINT and ensure that TWI and interrupts are enabled.
|
||||||
|
#define TWISendACK() (TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)|(1<<TWEA)) // FOR MR mode. Resume a transfer, ensure that TWI and interrupts are enabled and respond with an ACK if the device is addressed as a slave or after it receives a byte.
|
||||||
|
#define TWISendNACK() (TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)) // FOR MR mode. Resume a transfer, ensure that TWI and interrupts are enabled but DO NOT respond with an ACK if the device is addressed as a slave or after it receives a byte.
|
||||||
|
|
||||||
|
// Function declarations
|
||||||
|
uint8_t TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart);
|
||||||
|
void TWIInit(void);
|
||||||
|
uint8_t TWIReadData(uint8_t TWIaddr, uint8_t bytesToRead, uint8_t repStart);
|
||||||
|
uint8_t isTWIReady(void);
|
||||||
|
|
||||||
|
#endif // TWICOMMS_H_
|
@ -0,0 +1,357 @@
|
|||||||
|
/* Copyright 2017 Jason Williams
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "is31fl3731.h"
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "TWIlib.h"
|
||||||
|
#include "progmem.h"
|
||||||
|
|
||||||
|
// This is a 7-bit address, that gets left-shifted and bit 0
|
||||||
|
// set to 0 for write, 1 for read (as per I2C protocol)
|
||||||
|
// The address will vary depending on your wiring:
|
||||||
|
// 0b1110100 AD <-> GND
|
||||||
|
// 0b1110111 AD <-> VCC
|
||||||
|
// 0b1110101 AD <-> SCL
|
||||||
|
// 0b1110110 AD <-> SDA
|
||||||
|
#define ISSI_ADDR_DEFAULT 0x74
|
||||||
|
|
||||||
|
#define ISSI_REG_CONFIG 0x00
|
||||||
|
#define ISSI_REG_CONFIG_PICTUREMODE 0x00
|
||||||
|
#define ISSI_REG_CONFIG_AUTOPLAYMODE 0x08
|
||||||
|
#define ISSI_REG_CONFIG_AUDIOPLAYMODE 0x18
|
||||||
|
|
||||||
|
#define ISSI_CONF_PICTUREMODE 0x00
|
||||||
|
#define ISSI_CONF_AUTOFRAMEMODE 0x04
|
||||||
|
#define ISSI_CONF_AUDIOMODE 0x08
|
||||||
|
|
||||||
|
#define ISSI_REG_PICTUREFRAME 0x01
|
||||||
|
|
||||||
|
#define ISSI_REG_SHUTDOWN 0x0A
|
||||||
|
#define ISSI_REG_AUDIOSYNC 0x06
|
||||||
|
|
||||||
|
#define ISSI_COMMANDREGISTER 0xFD
|
||||||
|
#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine'
|
||||||
|
|
||||||
|
// Transfer buffer for TWITransmitData()
|
||||||
|
uint8_t g_twi_transfer_buffer[TXMAXBUFLEN];
|
||||||
|
|
||||||
|
// These buffers match the IS31FL3731 PWM registers 0x24-0xB3.
|
||||||
|
// Storing them like this is optimal for I2C transfers to the registers.
|
||||||
|
// We could optimize this and take out the unused registers from these
|
||||||
|
// buffers and the transfers in IS31FL3731_write_pwm_buffer() but it's
|
||||||
|
// probably not worth the extra complexity.
|
||||||
|
uint8_t g_pwm_buffer[DRIVER_COUNT][144];
|
||||||
|
bool g_pwm_buffer_update_required = false;
|
||||||
|
|
||||||
|
uint8_t g_led_control_registers[DRIVER_COUNT][18] = { { 0 }, { 0 } };
|
||||||
|
bool g_led_control_registers_update_required = false;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t red_register;
|
||||||
|
uint8_t red_bit;
|
||||||
|
uint8_t green_register;
|
||||||
|
uint8_t green_bit;
|
||||||
|
uint8_t blue_register;
|
||||||
|
uint8_t blue_bit;
|
||||||
|
} led_control_bitmask;
|
||||||
|
|
||||||
|
// This is the bit pattern in the LED control registers
|
||||||
|
// (for matrix A, add one to register for matrix B)
|
||||||
|
//
|
||||||
|
// reg - b7 b6 b5 b4 b3 b2 b1 b0
|
||||||
|
// 0x00 - R08,R07,R06,R05,R04,R03,R02,R01
|
||||||
|
// 0x02 - G08,G07,G06,G05,G04,G03,G02,R00
|
||||||
|
// 0x04 - B08,B07,B06,B05,B04,B03,G01,G00
|
||||||
|
// 0x06 - - , - , - , - , - ,B02,B01,B00
|
||||||
|
// 0x08 - - , - , - , - , - , - , - , -
|
||||||
|
// 0x0A - B17,B16,B15, - , - , - , - , -
|
||||||
|
// 0x0C - G17,G16,B14,B13,B12,B11,B10,B09
|
||||||
|
// 0x0E - R17,G15,G14,G13,G12,G11,G10,G09
|
||||||
|
// 0x10 - R16,R15,R14,R13,R12,R11,R10,R09
|
||||||
|
|
||||||
|
const led_control_bitmask g_led_control_bitmask[18] =
|
||||||
|
{
|
||||||
|
{ 0x02, 0, 0x04, 0, 0x06, 0 }, // R00,G00,B00
|
||||||
|
{ 0x00, 0, 0x04, 1, 0x06, 1 }, // R01,G01,B01
|
||||||
|
{ 0x00, 1, 0x02, 1, 0x06, 2 }, // R02,G02,B02
|
||||||
|
{ 0x00, 2, 0x02, 2, 0x04, 2 }, // R03,G03,B03
|
||||||
|
{ 0x00, 3, 0x02, 3, 0x04, 3 }, // R04,G04,B04
|
||||||
|
{ 0x00, 4, 0x02, 4, 0x04, 4 }, // R05,G05,B05
|
||||||
|
{ 0x00, 5, 0x02, 5, 0x04, 5 }, // R06,G06,B06
|
||||||
|
{ 0x00, 6, 0x02, 6, 0x04, 6 }, // R07,G07,B07
|
||||||
|
{ 0x00, 7, 0x02, 7, 0x04, 7 }, // R08,G08,B08
|
||||||
|
|
||||||
|
{ 0x10, 0, 0x0E, 0, 0x0C, 0 }, // R09,G09,B09
|
||||||
|
{ 0x10, 1, 0x0E, 1, 0x0C, 1 }, // R10,G10,B10
|
||||||
|
{ 0x10, 2, 0x0E, 2, 0x0C, 2 }, // R11,G11,B11
|
||||||
|
{ 0x10, 3, 0x0E, 3, 0x0C, 3 }, // R12,G12,B12
|
||||||
|
{ 0x10, 4, 0x0E, 4, 0x0C, 4 }, // R13,G13,B13
|
||||||
|
{ 0x10, 5, 0x0E, 5, 0x0C, 5 }, // R14,G14,B14
|
||||||
|
{ 0x10, 6, 0x0E, 6, 0x0A, 5 }, // R15,G15,B15
|
||||||
|
{ 0x10, 7, 0x0C, 6, 0x0A, 6 }, // R16,G16,B16
|
||||||
|
{ 0x0E, 7, 0x0C, 7, 0x0A, 7 }, // R17,G17,B17
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t g_map_control_index_to_register[2][18][3] PROGMEM = {
|
||||||
|
{
|
||||||
|
{0x34, 0x44, 0x54}, // 00
|
||||||
|
{0x24, 0x45, 0x55}, // 01
|
||||||
|
{0x25, 0x35, 0x56}, // 02
|
||||||
|
{0x26, 0x36, 0x46}, // 03
|
||||||
|
{0x27, 0x37, 0x47}, // 04
|
||||||
|
{0x28, 0x38, 0x48}, // 05
|
||||||
|
{0x29, 0x39, 0x49}, // 06
|
||||||
|
{0x2a, 0x3a, 0x4a}, // 07
|
||||||
|
{0x2b, 0x3b, 0x4b}, // 08
|
||||||
|
|
||||||
|
{0xa4, 0x94, 0x84}, // 09
|
||||||
|
{0xa5, 0x95, 0x85}, // 10
|
||||||
|
{0xa6, 0x96, 0x86}, // 11
|
||||||
|
{0xa7, 0x97, 0x87}, // 12
|
||||||
|
{0xa8, 0x98, 0x88}, // 13
|
||||||
|
{0xa9, 0x99, 0x89}, // 14
|
||||||
|
{0xaa, 0x9a, 0x79}, // 15
|
||||||
|
{0xab, 0x8a, 0x7a}, // 16
|
||||||
|
{0x9b, 0x8b, 0x7b} // 17
|
||||||
|
}, {
|
||||||
|
{0x34 + 8, 0x44 + 8, 0x54 + 8}, // 00
|
||||||
|
{0x24 + 8, 0x45 + 8, 0x55 + 8}, // 01
|
||||||
|
{0x25 + 8, 0x35 + 8, 0x56 + 8}, // 02
|
||||||
|
{0x26 + 8, 0x36 + 8, 0x46 + 8}, // 03
|
||||||
|
{0x27 + 8, 0x37 + 8, 0x47 + 8}, // 04
|
||||||
|
{0x28 + 8, 0x38 + 8, 0x48 + 8}, // 05
|
||||||
|
{0x29 + 8, 0x39 + 8, 0x49 + 8}, // 06
|
||||||
|
{0x2a + 8, 0x3a + 8, 0x4a + 8}, // 07
|
||||||
|
{0x2b + 8, 0x3b + 8, 0x4b + 8}, // 08
|
||||||
|
|
||||||
|
{0xa4 + 8, 0x94 + 8, 0x84 + 8}, // 09
|
||||||
|
{0xa5 + 8, 0x95 + 8, 0x85 + 8}, // 10
|
||||||
|
{0xa6 + 8, 0x96 + 8, 0x86 + 8}, // 11
|
||||||
|
{0xa7 + 8, 0x97 + 8, 0x87 + 8}, // 12
|
||||||
|
{0xa8 + 8, 0x98 + 8, 0x88 + 8}, // 13
|
||||||
|
{0xa9 + 8, 0x99 + 8, 0x89 + 8}, // 14
|
||||||
|
{0xaa + 8, 0x9a + 8, 0x79 + 8}, // 15
|
||||||
|
{0xab + 8, 0x8a + 8, 0x7a + 8}, // 16
|
||||||
|
{0x9b + 8, 0x8b + 8, 0x7b + 8} // 17
|
||||||
|
}};
|
||||||
|
|
||||||
|
void IS31FL3731_write_register( uint8_t addr, uint8_t reg, uint8_t data )
|
||||||
|
{
|
||||||
|
g_twi_transfer_buffer[0] = (addr << 1) | 0x00;
|
||||||
|
g_twi_transfer_buffer[1] = reg;
|
||||||
|
g_twi_transfer_buffer[2] = data;
|
||||||
|
|
||||||
|
// Set the error code to have no relevant information
|
||||||
|
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||||
|
// Continuously attempt to transmit data until a successful transmission occurs
|
||||||
|
//while ( TWIInfo.errorCode != 0xFF )
|
||||||
|
//{
|
||||||
|
TWITransmitData( g_twi_transfer_buffer, 3, 0 );
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IS31FL3731_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer )
|
||||||
|
{
|
||||||
|
// assumes bank is already selected
|
||||||
|
|
||||||
|
// transmit PWM registers in 9 transfers of 16 bytes
|
||||||
|
// g_twi_transfer_buffer[] is 20 bytes
|
||||||
|
|
||||||
|
// set the I2C address
|
||||||
|
g_twi_transfer_buffer[0] = (addr << 1) | 0x00;
|
||||||
|
|
||||||
|
// iterate over the pwm_buffer contents at 16 byte intervals
|
||||||
|
for ( int i = 0; i < 144; i += 16 )
|
||||||
|
{
|
||||||
|
// set the first register, e.g. 0x24, 0x34, 0x44, etc.
|
||||||
|
g_twi_transfer_buffer[1] = 0x24 + i;
|
||||||
|
// copy the data from i to i+15
|
||||||
|
// device will auto-increment register for data after the first byte
|
||||||
|
// thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer
|
||||||
|
for ( int j = 0; j < 16; j++ )
|
||||||
|
{
|
||||||
|
g_twi_transfer_buffer[2 + j] = pwm_buffer[i + j];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the error code to have no relevant information
|
||||||
|
TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
|
||||||
|
// Continuously attempt to transmit data until a successful transmission occurs
|
||||||
|
while ( TWIInfo.errorCode != 0xFF )
|
||||||
|
{
|
||||||
|
TWITransmitData( g_twi_transfer_buffer, 16 + 2, 0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IS31FL3731_init( uint8_t addr )
|
||||||
|
{
|
||||||
|
// In order to avoid the LEDs being driven with garbage data
|
||||||
|
// in the LED driver's PWM registers, first enable software shutdown,
|
||||||
|
// then set up the mode and other settings, clear the PWM registers,
|
||||||
|
// then disable software shutdown.
|
||||||
|
|
||||||
|
// select "function register" bank
|
||||||
|
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG );
|
||||||
|
|
||||||
|
// enable software shutdown
|
||||||
|
IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x00 );
|
||||||
|
// this delay was copied from other drivers, might not be needed
|
||||||
|
_delay_ms( 10 );
|
||||||
|
|
||||||
|
// picture mode
|
||||||
|
IS31FL3731_write_register( addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE );
|
||||||
|
// display frame 0
|
||||||
|
IS31FL3731_write_register( addr, ISSI_REG_PICTUREFRAME, 0x00 );
|
||||||
|
// audio sync off
|
||||||
|
IS31FL3731_write_register( addr, ISSI_REG_AUDIOSYNC, 0x00 );
|
||||||
|
|
||||||
|
// select bank 0
|
||||||
|
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 );
|
||||||
|
|
||||||
|
// turn off all LEDs in the LED control register
|
||||||
|
for ( int i = 0x00; i <= 0x11; i++ )
|
||||||
|
{
|
||||||
|
IS31FL3731_write_register( addr, i, 0x00 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// turn off all LEDs in the blink control register (not really needed)
|
||||||
|
for ( int i = 0x12; i <= 0x23; i++ )
|
||||||
|
{
|
||||||
|
IS31FL3731_write_register( addr, i, 0x00 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// set PWM on all LEDs to 0
|
||||||
|
for ( int i = 0x24; i <= 0xB3; i++ )
|
||||||
|
{
|
||||||
|
IS31FL3731_write_register( addr, i, 0x00 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// select "function register" bank
|
||||||
|
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG );
|
||||||
|
|
||||||
|
// disable software shutdown
|
||||||
|
IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x01 );
|
||||||
|
|
||||||
|
// select bank 0 and leave it selected.
|
||||||
|
// most usage after initialization is just writing PWM buffers in bank 0
|
||||||
|
// as there's not much point in double-buffering
|
||||||
|
IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void map_index_to_led( uint8_t index, is31_led *led ) {
|
||||||
|
//led = , sizeof(struct is31_led));
|
||||||
|
// led->driver = addr->driver;
|
||||||
|
// led->matrix = addr->matrix;
|
||||||
|
// led->modifier = addr->modifier;
|
||||||
|
// led->control_index = addr->control_index;
|
||||||
|
// led->matrix_co.raw = addr->matrix_co.raw;
|
||||||
|
// led->driver = (pgm_read_byte(addr) >> 6) && 0b11;
|
||||||
|
// led->matrix = (pgm_read_byte(addr) >> 4) && 0b1;
|
||||||
|
// led->modifier = (pgm_read_byte(addr) >> 3) && 0b1;
|
||||||
|
// led->control_index = pgm_read_byte(addr+1);
|
||||||
|
// led->matrix_co.raw = pgm_read_byte(addr+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IS31FL3731_set_color( int index, uint8_t red, uint8_t green, uint8_t blue )
|
||||||
|
{
|
||||||
|
if ( index >= 0 && index < DRIVER_LED_TOTAL )
|
||||||
|
{
|
||||||
|
is31_led led = g_is31_leds[index];
|
||||||
|
//map_index_to_led(index, &led);
|
||||||
|
|
||||||
|
// Subtract 0x24 to get the second index of g_pwm_buffer
|
||||||
|
g_pwm_buffer[led.driver][ pgm_read_byte(&g_map_control_index_to_register[led.matrix][led.control_index][0]) - 0x24] = red;
|
||||||
|
g_pwm_buffer[led.driver][ pgm_read_byte(&g_map_control_index_to_register[led.matrix][led.control_index][1]) - 0x24] = green;
|
||||||
|
g_pwm_buffer[led.driver][ pgm_read_byte(&g_map_control_index_to_register[led.matrix][led.control_index][2]) - 0x24] = blue;
|
||||||
|
g_pwm_buffer_update_required = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IS31FL3731_set_color_all( uint8_t red, uint8_t green, uint8_t blue )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < DRIVER_LED_TOTAL; i++ )
|
||||||
|
{
|
||||||
|
IS31FL3731_set_color( i, red, green, blue );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IS31FL3731_set_led_control_register( uint8_t index, bool red, bool green, bool blue )
|
||||||
|
{
|
||||||
|
is31_led led = g_is31_leds[index];
|
||||||
|
// map_index_to_led(index, &led);
|
||||||
|
|
||||||
|
led_control_bitmask bitmask = g_led_control_bitmask[led.control_index];
|
||||||
|
|
||||||
|
// Matrix A and B registers are interleaved.
|
||||||
|
// Add 1 to Matrix A register to get Matrix B register
|
||||||
|
if ( red )
|
||||||
|
{
|
||||||
|
g_led_control_registers[led.driver][bitmask.red_register+led.matrix] |= (1<<bitmask.red_bit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_led_control_registers[led.driver][bitmask.red_register+led.matrix] &= ~(1<<bitmask.red_bit);
|
||||||
|
}
|
||||||
|
if ( green )
|
||||||
|
{
|
||||||
|
g_led_control_registers[led.driver][bitmask.green_register+led.matrix] |= (1<<bitmask.green_bit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_led_control_registers[led.driver][bitmask.green_register+led.matrix] &= ~(1<<bitmask.green_bit);
|
||||||
|
}
|
||||||
|
if ( blue )
|
||||||
|
{
|
||||||
|
g_led_control_registers[led.driver][bitmask.blue_register+led.matrix] |= (1<<bitmask.blue_bit);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_led_control_registers[led.driver][bitmask.blue_register+led.matrix] &= ~(1<<bitmask.blue_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_led_control_registers_update_required = true;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void IS31FL3731_update_pwm_buffers( uint8_t addr1, uint8_t addr2 )
|
||||||
|
{
|
||||||
|
if ( g_pwm_buffer_update_required )
|
||||||
|
{
|
||||||
|
IS31FL3731_write_pwm_buffer( addr1, g_pwm_buffer[0] );
|
||||||
|
IS31FL3731_write_pwm_buffer( addr2, g_pwm_buffer[1] );
|
||||||
|
}
|
||||||
|
g_pwm_buffer_update_required = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IS31FL3731_update_led_control_registers( uint8_t addr1, uint8_t addr2 )
|
||||||
|
{
|
||||||
|
if ( g_led_control_registers_update_required )
|
||||||
|
{
|
||||||
|
for ( int i=0; i<18; i++ )
|
||||||
|
{
|
||||||
|
IS31FL3731_write_register(addr1, i, g_led_control_registers[0][i] );
|
||||||
|
IS31FL3731_write_register(addr2, i, g_led_control_registers[1][i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,64 @@
|
|||||||
|
/* Copyright 2017 Jason Williams
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef IS31FL3731_DRIVER_H
|
||||||
|
#define IS31FL3731_DRIVER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct Point {
|
||||||
|
uint8_t x;
|
||||||
|
uint8_t y;
|
||||||
|
} __attribute__((packed)) Point;
|
||||||
|
|
||||||
|
typedef struct is31_led {
|
||||||
|
uint8_t driver:2;
|
||||||
|
uint8_t matrix:1;
|
||||||
|
uint8_t modifier:1;
|
||||||
|
uint8_t control_index;
|
||||||
|
union {
|
||||||
|
uint8_t raw;
|
||||||
|
struct {
|
||||||
|
uint8_t row:4; // 16 max
|
||||||
|
uint8_t col:4; // 16 max
|
||||||
|
};
|
||||||
|
} matrix_co;
|
||||||
|
Point point;
|
||||||
|
} __attribute__((packed)) is31_led;
|
||||||
|
|
||||||
|
extern const is31_led g_is31_leds[DRIVER_LED_TOTAL];
|
||||||
|
|
||||||
|
void map_index_to_led( uint8_t index, is31_led *led );
|
||||||
|
|
||||||
|
void IS31FL3731_init( uint8_t addr );
|
||||||
|
void IS31FL3731_write_register( uint8_t addr, uint8_t reg, uint8_t data );
|
||||||
|
void IS31FL3731_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer );
|
||||||
|
|
||||||
|
void IS31FL3731_set_color( int index, uint8_t red, uint8_t green, uint8_t blue );
|
||||||
|
void IS31FL3731_set_color_all( uint8_t red, uint8_t green, uint8_t blue );
|
||||||
|
|
||||||
|
void IS31FL3731_set_led_control_register( uint8_t index, bool red, bool green, bool blue );
|
||||||
|
|
||||||
|
// This should not be called from an interrupt
|
||||||
|
// (eg. from a timer interrupt).
|
||||||
|
// Call this while idle (in between matrix scans).
|
||||||
|
// If the buffer is dirty, it will update the driver with the buffer.
|
||||||
|
void IS31FL3731_update_pwm_buffers( uint8_t addr1, uint8_t addr2 );
|
||||||
|
void IS31FL3731_update_led_control_registers( uint8_t addr1, uint8_t addr2 );
|
||||||
|
|
||||||
|
#endif // IS31FL3731_DRIVER_H
|
@ -0,0 +1,87 @@
|
|||||||
|
/* Copyright 2017 Jason Williams
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "color.h"
|
||||||
|
#include "led_tables.h"
|
||||||
|
#include "progmem.h"
|
||||||
|
|
||||||
|
RGB hsv_to_rgb( HSV hsv )
|
||||||
|
{
|
||||||
|
RGB rgb;
|
||||||
|
uint8_t region, p, q, t;
|
||||||
|
uint16_t h, s, v, remainder;
|
||||||
|
|
||||||
|
if ( hsv.s == 0 )
|
||||||
|
{
|
||||||
|
rgb.r = hsv.v;
|
||||||
|
rgb.g = hsv.v;
|
||||||
|
rgb.b = hsv.v;
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = hsv.h;
|
||||||
|
s = hsv.s;
|
||||||
|
v = hsv.v;
|
||||||
|
|
||||||
|
region = h / 43;
|
||||||
|
remainder = (h - (region * 43)) * 6;
|
||||||
|
|
||||||
|
p = (v * (255 - s)) >> 8;
|
||||||
|
q = (v * (255 - ((s * remainder) >> 8))) >> 8;
|
||||||
|
t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
|
||||||
|
|
||||||
|
switch ( region )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
rgb.r = v;
|
||||||
|
rgb.g = t;
|
||||||
|
rgb.b = p;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rgb.r = q;
|
||||||
|
rgb.g = v;
|
||||||
|
rgb.b = p;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rgb.r = p;
|
||||||
|
rgb.g = v;
|
||||||
|
rgb.b = t;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
rgb.r = p;
|
||||||
|
rgb.g = q;
|
||||||
|
rgb.b = v;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
rgb.r = t;
|
||||||
|
rgb.g = p;
|
||||||
|
rgb.b = v;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rgb.r = v;
|
||||||
|
rgb.g = p;
|
||||||
|
rgb.b = q;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rgb.r = pgm_read_byte( &CIE1931_CURVE[rgb.r] );
|
||||||
|
rgb.g = pgm_read_byte( &CIE1931_CURVE[rgb.g] );
|
||||||
|
rgb.b = pgm_read_byte( &CIE1931_CURVE[rgb.b] );
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,55 @@
|
|||||||
|
/* Copyright 2017 Jason Williams
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef COLOR_H
|
||||||
|
#define COLOR_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define PACKED __attribute__ ((__packed__))
|
||||||
|
#else
|
||||||
|
#define PACKED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma pack( push, 1 )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct PACKED
|
||||||
|
{
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
} RGB;
|
||||||
|
|
||||||
|
typedef struct PACKED
|
||||||
|
{
|
||||||
|
uint8_t h;
|
||||||
|
uint8_t s;
|
||||||
|
uint8_t v;
|
||||||
|
} HSV;
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#pragma pack( pop )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RGB hsv_to_rgb( HSV hsv );
|
||||||
|
|
||||||
|
#endif // COLOR_H
|
@ -0,0 +1,44 @@
|
|||||||
|
/* Copyright 2017 Jack Humbert
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RGB_H
|
||||||
|
#define RGB_H
|
||||||
|
|
||||||
|
__attribute__((weak))
|
||||||
|
void rgblight_toggle(void) {};
|
||||||
|
|
||||||
|
__attribute__((weak))
|
||||||
|
void rgblight_step(void) {};
|
||||||
|
|
||||||
|
__attribute__((weak))
|
||||||
|
void rgblight_increase_hue(void) {};
|
||||||
|
|
||||||
|
__attribute__((weak))
|
||||||
|
void rgblight_decrease_hue(void) {};
|
||||||
|
|
||||||
|
__attribute__((weak))
|
||||||
|
void rgblight_increase_sat(void) {};
|
||||||
|
|
||||||
|
__attribute__((weak))
|
||||||
|
void rgblight_decrease_sat(void) {};
|
||||||
|
|
||||||
|
__attribute__((weak))
|
||||||
|
void rgblight_increase_val(void) {};
|
||||||
|
|
||||||
|
__attribute__((weak))
|
||||||
|
void rgblight_decrease_val(void) {};
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,1056 @@
|
|||||||
|
/* Copyright 2017 Jason Williams
|
||||||
|
* Copyright 2017 Jack Humbert
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "rgb_matrix.h"
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include "TWIlib.h"
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include "progmem.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "eeprom.h"
|
||||||
|
#include "lufa.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#define BACKLIGHT_EFFECT_MAX 17
|
||||||
|
|
||||||
|
rgb_matrix_config g_config = {
|
||||||
|
.enabled = 1,
|
||||||
|
.brightness = 255,
|
||||||
|
.effect = 7,
|
||||||
|
.color_1 = { .h = 130, .s = 255, .v = 255 },
|
||||||
|
.color_2 = { .h = 70, .s = 255, .v = 255 },
|
||||||
|
.caps_lock_indicator = { .color = { .h = 0, .s = 0, .v = 255 }, .index = 255 },
|
||||||
|
.layer_1_indicator = { .color = { .h = 0, .s = 0, .v = 255 }, .index = 255 },
|
||||||
|
.layer_2_indicator = { .color = { .h = 0, .s = 0, .v = 255 }, .index = 255 },
|
||||||
|
.layer_3_indicator = { .color = { .h = 0, .s = 0, .v = 255 }, .index = 255 },
|
||||||
|
};
|
||||||
|
|
||||||
|
bool g_suspend_state = false;
|
||||||
|
uint8_t g_indicator_state = 0;
|
||||||
|
|
||||||
|
// Global tick at 20 Hz
|
||||||
|
uint32_t g_tick = 0;
|
||||||
|
|
||||||
|
// Ticks since this key was last hit.
|
||||||
|
uint8_t g_key_hit[DRIVER_LED_TOTAL];
|
||||||
|
|
||||||
|
// Ticks since any key was last hit.
|
||||||
|
uint32_t g_any_key_hit = 0;
|
||||||
|
|
||||||
|
#ifndef PI
|
||||||
|
#define PI 3.14159265
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Last led hit
|
||||||
|
#define LED_HITS_TO_REMEMBER 8
|
||||||
|
uint8_t g_last_led_hit[LED_HITS_TO_REMEMBER] = {255};
|
||||||
|
uint8_t g_last_led_count = 0;
|
||||||
|
|
||||||
|
|
||||||
|
void map_row_column_to_led( uint8_t row, uint8_t column, uint8_t *led_i, uint8_t *led_count)
|
||||||
|
{
|
||||||
|
is31_led led;
|
||||||
|
*led_count = 0;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
|
||||||
|
// map_index_to_led(i, &led);
|
||||||
|
led = g_is31_leds[i];
|
||||||
|
if (row == led.matrix_co.row && column == led.matrix_co.col) {
|
||||||
|
led_i[*led_count] = i;
|
||||||
|
(*led_count)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void backlight_update_pwm_buffers(void)
|
||||||
|
{
|
||||||
|
IS31FL3731_update_pwm_buffers( DRIVER_ADDR_1, DRIVER_ADDR_2 );
|
||||||
|
IS31FL3731_update_led_control_registers( DRIVER_ADDR_1, DRIVER_ADDR_2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_set_color( int index, uint8_t red, uint8_t green, uint8_t blue )
|
||||||
|
{
|
||||||
|
IS31FL3731_set_color( index, red, green, blue );
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_set_color_all( uint8_t red, uint8_t green, uint8_t blue )
|
||||||
|
{
|
||||||
|
IS31FL3731_set_color_all( red, green, blue );
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_set_key_hit(uint8_t row, uint8_t column)
|
||||||
|
{
|
||||||
|
uint8_t led[8], led_count;
|
||||||
|
map_row_column_to_led(row,column,led,&led_count);
|
||||||
|
if (led_count > 0) {
|
||||||
|
for (uint8_t i = LED_HITS_TO_REMEMBER; i > 1; i--) {
|
||||||
|
g_last_led_hit[i - 1] = g_last_led_hit[i - 2];
|
||||||
|
}
|
||||||
|
g_last_led_hit[0] = led[0];
|
||||||
|
g_last_led_count = MIN(LED_HITS_TO_REMEMBER, g_last_led_count + 1);
|
||||||
|
}
|
||||||
|
for(uint8_t i = 0; i < led_count; i++)
|
||||||
|
g_key_hit[led[i]] = 0;
|
||||||
|
g_any_key_hit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_unset_key_hit(uint8_t row, uint8_t column)
|
||||||
|
{
|
||||||
|
uint8_t led[8], led_count;
|
||||||
|
map_row_column_to_led(row,column,led,&led_count);
|
||||||
|
for(uint8_t i = 0; i < led_count; i++)
|
||||||
|
g_key_hit[led[i]] = 255;
|
||||||
|
|
||||||
|
g_any_key_hit = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is (F_CPU/1024) / 20 Hz
|
||||||
|
// = 15625 Hz / 20 Hz
|
||||||
|
// = 781
|
||||||
|
// #define TIMER3_TOP 781
|
||||||
|
|
||||||
|
void backlight_timer_init(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
static uint8_t backlight_timer_is_init = 0;
|
||||||
|
if ( backlight_timer_is_init )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
backlight_timer_is_init = 1;
|
||||||
|
|
||||||
|
// Timer 3 setup
|
||||||
|
//TCCR3B = _BV(WGM32) | // CTC mode OCR3A as TOP
|
||||||
|
// _BV(CS32) | _BV(CS30); // prescale by /1024
|
||||||
|
// Set TOP value
|
||||||
|
//uint8_t sreg = SREG;
|
||||||
|
//cli();
|
||||||
|
|
||||||
|
//OCR3AH = (TIMER3_TOP >> 8) & 0xff;
|
||||||
|
//OCR3AL = TIMER3_TOP & 0xff;
|
||||||
|
//SREG = sreg;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_timer_enable(void)
|
||||||
|
{
|
||||||
|
//TIMSK3 |= _BV(OCIE3A);
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_timer_disable(void)
|
||||||
|
{
|
||||||
|
//TIMSK3 &= ~_BV(OCIE3A);
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_set_suspend_state(bool state)
|
||||||
|
{
|
||||||
|
g_suspend_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_set_indicator_state(uint8_t state)
|
||||||
|
{
|
||||||
|
g_indicator_state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_rgb_test(void)
|
||||||
|
{
|
||||||
|
// Mask out bits 4 and 5
|
||||||
|
// This 2-bit value will stay the same for 16 ticks.
|
||||||
|
switch ( (g_tick & 0x30) >> 4 )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
backlight_set_color_all( 20, 0, 0 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
backlight_set_color_all( 0, 20, 0 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
backlight_set_color_all( 0, 0, 20 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
backlight_set_color_all( 20, 20, 20 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This tests the LEDs
|
||||||
|
// Note that it will change the LED control registers
|
||||||
|
// in the LED drivers, and leave them in an invalid
|
||||||
|
// state for other backlight effects.
|
||||||
|
// ONLY USE THIS FOR TESTING LEDS!
|
||||||
|
void backlight_effect_single_LED_test(void)
|
||||||
|
{
|
||||||
|
static uint8_t color = 0; // 0,1,2 for R,G,B
|
||||||
|
static uint8_t row = 0;
|
||||||
|
static uint8_t column = 0;
|
||||||
|
|
||||||
|
static uint8_t tick = 0;
|
||||||
|
tick++;
|
||||||
|
|
||||||
|
if ( tick > 2 )
|
||||||
|
{
|
||||||
|
tick = 0;
|
||||||
|
column++;
|
||||||
|
}
|
||||||
|
if ( column > MATRIX_COLS )
|
||||||
|
{
|
||||||
|
column = 0;
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
if ( row > MATRIX_ROWS )
|
||||||
|
{
|
||||||
|
row = 0;
|
||||||
|
color++;
|
||||||
|
}
|
||||||
|
if ( color > 2 )
|
||||||
|
{
|
||||||
|
color = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t led[8], led_count;
|
||||||
|
map_row_column_to_led(row,column,led,&led_count);
|
||||||
|
for(uint8_t i = 0; i < led_count; i++) {
|
||||||
|
backlight_set_color_all( 40, 40, 40 );
|
||||||
|
backlight_test_led( led[i], color==0, color==1, color==2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All LEDs off
|
||||||
|
void backlight_effect_all_off(void)
|
||||||
|
{
|
||||||
|
backlight_set_color_all( 0, 0, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solid color
|
||||||
|
void backlight_effect_solid_color(void)
|
||||||
|
{
|
||||||
|
HSV hsv = { .h = g_config.color_1.h, .s = g_config.color_1.s, .v = g_config.brightness };
|
||||||
|
RGB rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color_all( rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_solid_reactive(void)
|
||||||
|
{
|
||||||
|
// Relies on hue being 8-bit and wrapping
|
||||||
|
for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
|
||||||
|
{
|
||||||
|
uint16_t offset2 = g_key_hit[i]<<2;
|
||||||
|
offset2 = (offset2<=130) ? (130-offset2) : 0;
|
||||||
|
|
||||||
|
HSV hsv = { .h = g_config.color_1.h+offset2, .s = 255, .v = g_config.brightness };
|
||||||
|
RGB rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// alphas = color1, mods = color2
|
||||||
|
void backlight_effect_alphas_mods(void)
|
||||||
|
{
|
||||||
|
RGB rgb1 = hsv_to_rgb( (HSV){ .h = g_config.color_1.h, .s = g_config.color_1.s, .v = g_config.brightness } );
|
||||||
|
RGB rgb2 = hsv_to_rgb( (HSV){ .h = g_config.color_2.h, .s = g_config.color_2.s, .v = g_config.brightness } );
|
||||||
|
|
||||||
|
is31_led led;
|
||||||
|
for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
|
||||||
|
led = g_is31_leds[i];
|
||||||
|
if ( led.matrix_co.raw < 0xFF ) {
|
||||||
|
if ( led.modifier )
|
||||||
|
{
|
||||||
|
backlight_set_color( i, rgb2.r, rgb2.g, rgb2.b );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backlight_set_color( i, rgb1.r, rgb1.g, rgb1.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_gradient_up_down(void)
|
||||||
|
{
|
||||||
|
int16_t h1 = g_config.color_1.h;
|
||||||
|
int16_t h2 = g_config.color_2.h;
|
||||||
|
int16_t deltaH = h2 - h1;
|
||||||
|
|
||||||
|
// Take the shortest path between hues
|
||||||
|
if ( deltaH > 127 )
|
||||||
|
{
|
||||||
|
deltaH -= 256;
|
||||||
|
}
|
||||||
|
else if ( deltaH < -127 )
|
||||||
|
{
|
||||||
|
deltaH += 256;
|
||||||
|
}
|
||||||
|
// Divide delta by 4, this gives the delta per row
|
||||||
|
deltaH /= 4;
|
||||||
|
|
||||||
|
int16_t s1 = g_config.color_1.s;
|
||||||
|
int16_t s2 = g_config.color_2.s;
|
||||||
|
int16_t deltaS = ( s2 - s1 ) / 4;
|
||||||
|
|
||||||
|
HSV hsv = { .h = 0, .s = 255, .v = g_config.brightness };
|
||||||
|
RGB rgb;
|
||||||
|
Point point;
|
||||||
|
for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
|
||||||
|
{
|
||||||
|
// map_led_to_point( i, &point );
|
||||||
|
point = g_is31_leds[i].point;
|
||||||
|
// The y range will be 0..64, map this to 0..4
|
||||||
|
uint8_t y = (point.y>>4);
|
||||||
|
// Relies on hue being 8-bit and wrapping
|
||||||
|
hsv.h = g_config.color_1.h + ( deltaH * y );
|
||||||
|
hsv.s = g_config.color_1.s + ( deltaS * y );
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_raindrops(bool initialize)
|
||||||
|
{
|
||||||
|
int16_t h1 = g_config.color_1.h;
|
||||||
|
int16_t h2 = g_config.color_2.h;
|
||||||
|
int16_t deltaH = h2 - h1;
|
||||||
|
deltaH /= 4;
|
||||||
|
|
||||||
|
// Take the shortest path between hues
|
||||||
|
if ( deltaH > 127 )
|
||||||
|
{
|
||||||
|
deltaH -= 256;
|
||||||
|
}
|
||||||
|
else if ( deltaH < -127 )
|
||||||
|
{
|
||||||
|
deltaH += 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t s1 = g_config.color_1.s;
|
||||||
|
int16_t s2 = g_config.color_2.s;
|
||||||
|
int16_t deltaS = ( s2 - s1 ) / 4;
|
||||||
|
|
||||||
|
HSV hsv;
|
||||||
|
RGB rgb;
|
||||||
|
|
||||||
|
// Change one LED every tick
|
||||||
|
uint8_t led_to_change = ( g_tick & 0x000 ) == 0 ? rand() % DRIVER_LED_TOTAL : 255;
|
||||||
|
|
||||||
|
for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
|
||||||
|
{
|
||||||
|
// If initialize, all get set to random colors
|
||||||
|
// If not, all but one will stay the same as before.
|
||||||
|
if ( initialize || i == led_to_change )
|
||||||
|
{
|
||||||
|
hsv.h = h1 + ( deltaH * ( rand() & 0x03 ) );
|
||||||
|
hsv.s = s1 + ( deltaS * ( rand() & 0x03 ) );
|
||||||
|
// Override brightness with global brightness control
|
||||||
|
hsv.v = g_config.brightness;;
|
||||||
|
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_cycle_all(void)
|
||||||
|
{
|
||||||
|
uint8_t offset = g_tick & 0xFF;
|
||||||
|
|
||||||
|
is31_led led;
|
||||||
|
|
||||||
|
// Relies on hue being 8-bit and wrapping
|
||||||
|
for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
|
||||||
|
{
|
||||||
|
// map_index_to_led(i, &led);
|
||||||
|
led = g_is31_leds[i];
|
||||||
|
if (led.matrix_co.raw < 0xFF) {
|
||||||
|
uint16_t offset2 = g_key_hit[i]<<2;
|
||||||
|
offset2 = (offset2<=63) ? (63-offset2) : 0;
|
||||||
|
|
||||||
|
HSV hsv = { .h = offset+offset2, .s = 255, .v = g_config.brightness };
|
||||||
|
RGB rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_cycle_left_right(void)
|
||||||
|
{
|
||||||
|
uint8_t offset = g_tick & 0xFF;
|
||||||
|
HSV hsv = { .h = 0, .s = 255, .v = g_config.brightness };
|
||||||
|
RGB rgb;
|
||||||
|
Point point;
|
||||||
|
is31_led led;
|
||||||
|
for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
|
||||||
|
{
|
||||||
|
// map_index_to_led(i, &led);
|
||||||
|
led = g_is31_leds[i];
|
||||||
|
if (led.matrix_co.raw < 0xFF) {
|
||||||
|
uint16_t offset2 = g_key_hit[i]<<2;
|
||||||
|
offset2 = (offset2<=63) ? (63-offset2) : 0;
|
||||||
|
|
||||||
|
// map_led_to_point( i, &point );
|
||||||
|
point = g_is31_leds[i].point;
|
||||||
|
// Relies on hue being 8-bit and wrapping
|
||||||
|
hsv.h = point.x + offset + offset2;
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_cycle_up_down(void)
|
||||||
|
{
|
||||||
|
uint8_t offset = g_tick & 0xFF;
|
||||||
|
HSV hsv = { .h = 0, .s = 255, .v = g_config.brightness };
|
||||||
|
RGB rgb;
|
||||||
|
Point point;
|
||||||
|
is31_led led;
|
||||||
|
for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
|
||||||
|
{
|
||||||
|
// map_index_to_led(i, &led);
|
||||||
|
led = g_is31_leds[i];
|
||||||
|
if (led.matrix_co.raw < 0xFF) {
|
||||||
|
uint16_t offset2 = g_key_hit[i]<<2;
|
||||||
|
offset2 = (offset2<=63) ? (63-offset2) : 0;
|
||||||
|
|
||||||
|
// map_led_to_point( i, &point );
|
||||||
|
point = g_is31_leds[i].point;
|
||||||
|
// Relies on hue being 8-bit and wrapping
|
||||||
|
hsv.h = point.y + offset + offset2;
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void backlight_effect_dual_beacon(void) {
|
||||||
|
HSV hsv = { .h = g_config.color_1.h, .s = g_config.color_1.s, .v = g_config.brightness };
|
||||||
|
RGB rgb;
|
||||||
|
is31_led led;
|
||||||
|
for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
|
||||||
|
led = g_is31_leds[i];
|
||||||
|
hsv.h = ((led.point.y - 32.0)* cos(g_tick * PI / 128) / 32 + (led.point.x - 112.0) * sin(g_tick * PI / 128) / (112)) * (g_config.color_2.h - g_config.color_1.h) + g_config.color_1.h;
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_rainbow_beacon(void) {
|
||||||
|
HSV hsv = { .h = g_config.color_1.h, .s = g_config.color_1.s, .v = g_config.brightness };
|
||||||
|
RGB rgb;
|
||||||
|
is31_led led;
|
||||||
|
for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
|
||||||
|
led = g_is31_leds[i];
|
||||||
|
hsv.h = 1.5 * (led.point.y - 32.0)* cos(g_tick * PI / 128) + 1.5 * (led.point.x - 112.0) * sin(g_tick * PI / 128) + g_config.color_1.h;
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_rainbow_pinwheels(void) {
|
||||||
|
HSV hsv = { .h = g_config.color_1.h, .s = g_config.color_1.s, .v = g_config.brightness };
|
||||||
|
RGB rgb;
|
||||||
|
is31_led led;
|
||||||
|
for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
|
||||||
|
led = g_is31_leds[i];
|
||||||
|
hsv.h = 2 * (led.point.y - 32.0)* cos(g_tick * PI / 128) + 2 * (66 - abs(led.point.x - 112.0)) * sin(g_tick * PI / 128) + g_config.color_1.h;
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_rainbow_moving_chevron(void) {
|
||||||
|
HSV hsv = { .h = g_config.color_1.h, .s = g_config.color_1.s, .v = g_config.brightness };
|
||||||
|
RGB rgb;
|
||||||
|
is31_led led;
|
||||||
|
for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
|
||||||
|
led = g_is31_leds[i];
|
||||||
|
// uint8_t r = g_tick;
|
||||||
|
uint8_t r = 32;
|
||||||
|
hsv.h = 1.5 * abs(led.point.y - 32.0)* sin(r * PI / 128) + 1.5 * (led.point.x - (g_tick / 256.0 * 224)) * cos(r * PI / 128) + g_config.color_1.h;
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void backlight_effect_jellybean_raindrops( bool initialize )
|
||||||
|
{
|
||||||
|
HSV hsv;
|
||||||
|
RGB rgb;
|
||||||
|
|
||||||
|
// Change one LED every tick
|
||||||
|
uint8_t led_to_change = ( g_tick & 0x000 ) == 0 ? rand() % DRIVER_LED_TOTAL : 255;
|
||||||
|
|
||||||
|
for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
|
||||||
|
{
|
||||||
|
// If initialize, all get set to random colors
|
||||||
|
// If not, all but one will stay the same as before.
|
||||||
|
if ( initialize || i == led_to_change )
|
||||||
|
{
|
||||||
|
hsv.h = rand() & 0xFF;
|
||||||
|
hsv.s = rand() & 0xFF;
|
||||||
|
// Override brightness with global brightness control
|
||||||
|
hsv.v = g_config.brightness;;
|
||||||
|
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_multisplash(void) {
|
||||||
|
// if (g_any_key_hit < 0xFF) {
|
||||||
|
HSV hsv = { .h = g_config.color_1.h, .s = g_config.color_1.s, .v = g_config.brightness };
|
||||||
|
RGB rgb;
|
||||||
|
is31_led led;
|
||||||
|
for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
|
||||||
|
led = g_is31_leds[i];
|
||||||
|
uint16_t c = 0, d = 0;
|
||||||
|
is31_led last_led;
|
||||||
|
// if (g_last_led_count) {
|
||||||
|
for (uint8_t last_i = 0; last_i < g_last_led_count; last_i++) {
|
||||||
|
last_led = g_is31_leds[g_last_led_hit[last_i]];
|
||||||
|
uint16_t dist = (uint16_t)sqrt(pow(led.point.x - last_led.point.x, 2) + pow(led.point.y - last_led.point.y, 2));
|
||||||
|
uint16_t effect = (g_key_hit[g_last_led_hit[last_i]] << 2) - dist;
|
||||||
|
c += MIN(MAX(effect, 0), 255);
|
||||||
|
d += 255 - MIN(MAX(effect, 0), 255);
|
||||||
|
}
|
||||||
|
// } else {
|
||||||
|
// d = 255;
|
||||||
|
// }
|
||||||
|
hsv.h = (g_config.color_1.h + c) % 256;
|
||||||
|
hsv.v = MAX(MIN(d, 255), 0);
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
// } else {
|
||||||
|
// backlight_set_color_all( 0, 0, 0 );
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void backlight_effect_splash(void) {
|
||||||
|
g_last_led_count = MIN(g_last_led_count, 1);
|
||||||
|
backlight_effect_multisplash();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void backlight_effect_solid_multisplash(void) {
|
||||||
|
// if (g_any_key_hit < 0xFF) {
|
||||||
|
HSV hsv = { .h = g_config.color_1.h, .s = g_config.color_1.s, .v = g_config.brightness };
|
||||||
|
RGB rgb;
|
||||||
|
is31_led led;
|
||||||
|
for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
|
||||||
|
led = g_is31_leds[i];
|
||||||
|
uint16_t d = 0;
|
||||||
|
is31_led last_led;
|
||||||
|
// if (g_last_led_count) {
|
||||||
|
for (uint8_t last_i = 0; last_i < g_last_led_count; last_i++) {
|
||||||
|
last_led = g_is31_leds[g_last_led_hit[last_i]];
|
||||||
|
uint16_t dist = (uint16_t)sqrt(pow(led.point.x - last_led.point.x, 2) + pow(led.point.y - last_led.point.y, 2));
|
||||||
|
uint16_t effect = (g_key_hit[g_last_led_hit[last_i]] << 2) - dist;
|
||||||
|
d += 255 - MIN(MAX(effect, 0), 255);
|
||||||
|
}
|
||||||
|
// } else {
|
||||||
|
// d = 255;
|
||||||
|
// }
|
||||||
|
hsv.v = MAX(MIN(d, 255), 0);
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
// } else {
|
||||||
|
// backlight_set_color_all( 0, 0, 0 );
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void backlight_effect_solid_splash(void) {
|
||||||
|
g_last_led_count = MIN(g_last_led_count, 1);
|
||||||
|
backlight_effect_solid_multisplash();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_custom(void)
|
||||||
|
{
|
||||||
|
HSV hsv;
|
||||||
|
RGB rgb;
|
||||||
|
for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
|
||||||
|
{
|
||||||
|
backlight_get_key_color(i, &hsv);
|
||||||
|
// Override brightness with global brightness control
|
||||||
|
hsv.v = g_config.brightness;
|
||||||
|
rgb = hsv_to_rgb( hsv );
|
||||||
|
backlight_set_color( i, rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_indicators_set_colors( uint8_t index, HSV hsv )
|
||||||
|
{
|
||||||
|
RGB rgb = hsv_to_rgb( hsv );
|
||||||
|
if ( index == 254 )
|
||||||
|
{
|
||||||
|
backlight_set_color_all( rgb.r, rgb.g, rgb.b );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backlight_set_color( index, rgb.r, rgb.g, rgb.b );
|
||||||
|
|
||||||
|
// If the spacebar LED is the indicator,
|
||||||
|
// do the same for the spacebar stabilizers
|
||||||
|
if ( index == 36+0 ) // LC0
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_ZEAL65
|
||||||
|
backlight_set_color( 36+7, rgb.r, rgb.g, rgb.b ); // LC7
|
||||||
|
backlight_set_color( 54+14, rgb.r, rgb.g, rgb.b ); // LD14
|
||||||
|
#else
|
||||||
|
backlight_set_color( 36+6, rgb.r, rgb.g, rgb.b ); // LC6
|
||||||
|
backlight_set_color( 54+13, rgb.r, rgb.g, rgb.b ); // LD13
|
||||||
|
if ( g_config.use_7u_spacebar )
|
||||||
|
{
|
||||||
|
backlight_set_color( 54+14, rgb.r, rgb.g, rgb.b ); // LD14
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This runs after another backlight effect and replaces
|
||||||
|
// colors already set
|
||||||
|
void backlight_effect_indicators(void)
|
||||||
|
{
|
||||||
|
if ( g_config.caps_lock_indicator.index != 255 &&
|
||||||
|
( g_indicator_state & (1<<USB_LED_CAPS_LOCK) ) )
|
||||||
|
{
|
||||||
|
backlight_effect_indicators_set_colors( g_config.caps_lock_indicator.index, g_config.caps_lock_indicator.color );
|
||||||
|
}
|
||||||
|
|
||||||
|
// This if/else if structure allows higher layers to
|
||||||
|
// override lower ones. If we set layer 3's indicator
|
||||||
|
// to none, then it will NOT show layer 2 or layer 1
|
||||||
|
// indicators, even if those layers are on via the
|
||||||
|
// MO13/MO23 Fn combo magic.
|
||||||
|
//
|
||||||
|
// Basically we want to handle the case where layer 3 is
|
||||||
|
// still the backlight configuration layer and we don't
|
||||||
|
// want "all LEDs" indicators hiding the backlight effect,
|
||||||
|
// but still allow end users to do whatever they want.
|
||||||
|
if ( IS_LAYER_ON(3) )
|
||||||
|
{
|
||||||
|
if ( g_config.layer_3_indicator.index != 255 )
|
||||||
|
{
|
||||||
|
backlight_effect_indicators_set_colors( g_config.layer_3_indicator.index, g_config.layer_3_indicator.color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( IS_LAYER_ON(2) )
|
||||||
|
{
|
||||||
|
if ( g_config.layer_2_indicator.index != 255 )
|
||||||
|
{
|
||||||
|
backlight_effect_indicators_set_colors( g_config.layer_2_indicator.index, g_config.layer_2_indicator.color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( IS_LAYER_ON(1) )
|
||||||
|
{
|
||||||
|
if ( g_config.layer_1_indicator.index != 255 )
|
||||||
|
{
|
||||||
|
backlight_effect_indicators_set_colors( g_config.layer_1_indicator.index, g_config.layer_1_indicator.color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_rgb_task(void) {
|
||||||
|
if (!g_config.enabled) {
|
||||||
|
backlight_effect_all_off();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// delay 1 second before driving LEDs or doing anything else
|
||||||
|
static uint8_t startup_tick = 0;
|
||||||
|
if ( startup_tick < 20 )
|
||||||
|
{
|
||||||
|
startup_tick++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_tick++;
|
||||||
|
|
||||||
|
if ( g_any_key_hit < 0xFFFFFFFF )
|
||||||
|
{
|
||||||
|
g_any_key_hit++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int led = 0; led < DRIVER_LED_TOTAL; led++ )
|
||||||
|
{
|
||||||
|
if ( g_key_hit[led] < 255 )
|
||||||
|
{
|
||||||
|
if (g_key_hit[led] == 254)
|
||||||
|
g_last_led_count = MAX(g_last_led_count - 1, 0);
|
||||||
|
g_key_hit[led]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Factory default magic value
|
||||||
|
if ( g_config.effect == 255 )
|
||||||
|
{
|
||||||
|
backlight_effect_rgb_test();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ideally we would also stop sending zeros to the LED driver PWM buffers
|
||||||
|
// while suspended and just do a software shutdown. This is a cheap hack for now.
|
||||||
|
bool suspend_backlight = ((g_suspend_state && g_config.disable_when_usb_suspended) ||
|
||||||
|
(g_config.disable_after_timeout > 0 && g_any_key_hit > g_config.disable_after_timeout * 60 * 20));
|
||||||
|
uint8_t effect = suspend_backlight ? 0 : g_config.effect;
|
||||||
|
|
||||||
|
// Keep track of the effect used last time,
|
||||||
|
// detect change in effect, so each effect can
|
||||||
|
// have an optional initialization.
|
||||||
|
static uint8_t effect_last = 255;
|
||||||
|
bool initialize = effect != effect_last;
|
||||||
|
effect_last = effect;
|
||||||
|
|
||||||
|
// this gets ticked at 20 Hz.
|
||||||
|
// each effect can opt to do calculations
|
||||||
|
// and/or request PWM buffer updates.
|
||||||
|
switch ( effect )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
backlight_effect_solid_color();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
backlight_effect_solid_reactive();
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
backlight_effect_alphas_mods();
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
backlight_effect_dual_beacon();
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
backlight_effect_gradient_up_down();
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
backlight_effect_raindrops( initialize );
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
backlight_effect_cycle_all();
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
backlight_effect_cycle_left_right();
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
backlight_effect_cycle_up_down();
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
backlight_effect_rainbow_beacon();
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
backlight_effect_rainbow_pinwheels();
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
backlight_effect_rainbow_moving_chevron();
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
backlight_effect_jellybean_raindrops( initialize );
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
backlight_effect_splash();
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
backlight_effect_multisplash();
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
backlight_effect_solid_splash();
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
backlight_effect_solid_multisplash();
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
default:
|
||||||
|
backlight_effect_custom();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! suspend_backlight )
|
||||||
|
{
|
||||||
|
backlight_effect_indicators();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// void backlight_set_indicator_index( uint8_t *index, uint8_t row, uint8_t column )
|
||||||
|
// {
|
||||||
|
// if ( row >= MATRIX_ROWS )
|
||||||
|
// {
|
||||||
|
// // Special value, 255=none, 254=all
|
||||||
|
// *index = row;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// // This needs updated to something like
|
||||||
|
// // uint8_t led[8], led_count;
|
||||||
|
// // map_row_column_to_led(row,column,led,&led_count);
|
||||||
|
// // for(uint8_t i = 0; i < led_count; i++)
|
||||||
|
// map_row_column_to_led( row, column, index );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
void backlight_config_load(void)
|
||||||
|
{
|
||||||
|
eeprom_read_block( &g_config, EEPROM_BACKLIGHT_CONFIG_ADDR, sizeof(rgb_matrix_config) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_config_save(void)
|
||||||
|
{
|
||||||
|
eeprom_update_block( &g_config, EEPROM_BACKLIGHT_CONFIG_ADDR, sizeof(rgb_matrix_config) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_init_drivers(void)
|
||||||
|
{
|
||||||
|
//sei();
|
||||||
|
|
||||||
|
// Initialize TWI
|
||||||
|
TWIInit();
|
||||||
|
IS31FL3731_init( DRIVER_ADDR_1 );
|
||||||
|
IS31FL3731_init( DRIVER_ADDR_2 );
|
||||||
|
|
||||||
|
for ( int index = 0; index < DRIVER_LED_TOTAL; index++ )
|
||||||
|
{
|
||||||
|
bool enabled = true;
|
||||||
|
// This only caches it for later
|
||||||
|
IS31FL3731_set_led_control_register( index, enabled, enabled, enabled );
|
||||||
|
}
|
||||||
|
// This actually updates the LED drivers
|
||||||
|
IS31FL3731_update_led_control_registers( DRIVER_ADDR_1, DRIVER_ADDR_2 );
|
||||||
|
|
||||||
|
// TODO: put the 1 second startup delay here?
|
||||||
|
|
||||||
|
// clear the key hits
|
||||||
|
for ( int led=0; led<DRIVER_LED_TOTAL; led++ )
|
||||||
|
{
|
||||||
|
g_key_hit[led] = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deals with the messy details of incrementing an integer
|
||||||
|
uint8_t increment( uint8_t value, uint8_t step, uint8_t min, uint8_t max )
|
||||||
|
{
|
||||||
|
int16_t new_value = value;
|
||||||
|
new_value += step;
|
||||||
|
return MIN( MAX( new_value, min ), max );
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t decrement( uint8_t value, uint8_t step, uint8_t min, uint8_t max )
|
||||||
|
{
|
||||||
|
int16_t new_value = value;
|
||||||
|
new_value -= step;
|
||||||
|
return MIN( MAX( new_value, min ), max );
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_increase(void)
|
||||||
|
{
|
||||||
|
g_config.effect = increment( g_config.effect, 1, 0, BACKLIGHT_EFFECT_MAX );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_effect_decrease(void)
|
||||||
|
{
|
||||||
|
g_config.effect = decrement( g_config.effect, 1, 0, BACKLIGHT_EFFECT_MAX );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_brightness_increase(void)
|
||||||
|
{
|
||||||
|
g_config.brightness = increment( g_config.brightness, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_brightness_decrease(void)
|
||||||
|
{
|
||||||
|
g_config.brightness = decrement( g_config.brightness, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_color_1_hue_increase(void)
|
||||||
|
{
|
||||||
|
g_config.color_1.h = increment( g_config.color_1.h, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_color_1_hue_decrease(void)
|
||||||
|
{
|
||||||
|
g_config.color_1.h = decrement( g_config.color_1.h, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_color_1_sat_increase(void)
|
||||||
|
{
|
||||||
|
g_config.color_1.s = increment( g_config.color_1.s, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_color_1_sat_decrease(void)
|
||||||
|
{
|
||||||
|
g_config.color_1.s = decrement( g_config.color_1.s, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_color_2_hue_increase(void)
|
||||||
|
{
|
||||||
|
g_config.color_2.h = increment( g_config.color_2.h, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_color_2_hue_decrease(void)
|
||||||
|
{
|
||||||
|
g_config.color_2.h = decrement( g_config.color_2.h, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_color_2_sat_increase(void)
|
||||||
|
{
|
||||||
|
g_config.color_2.s = increment( g_config.color_2.s, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_color_2_sat_decrease(void)
|
||||||
|
{
|
||||||
|
g_config.color_2.s = decrement( g_config.color_2.s, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *backlight_get_custom_key_color_eeprom_address( uint8_t led )
|
||||||
|
{
|
||||||
|
// 3 bytes per color
|
||||||
|
return EEPROM_BACKLIGHT_KEY_COLOR_ADDR + ( led * 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_get_key_color( uint8_t led, HSV *hsv )
|
||||||
|
{
|
||||||
|
void *address = backlight_get_custom_key_color_eeprom_address( led );
|
||||||
|
hsv->h = eeprom_read_byte(address);
|
||||||
|
hsv->s = eeprom_read_byte(address+1);
|
||||||
|
hsv->v = eeprom_read_byte(address+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_set_key_color( uint8_t row, uint8_t column, HSV hsv )
|
||||||
|
{
|
||||||
|
uint8_t led[8], led_count;
|
||||||
|
map_row_column_to_led(row,column,led,&led_count);
|
||||||
|
for(uint8_t i = 0; i < led_count; i++) {
|
||||||
|
if ( led[i] < DRIVER_LED_TOTAL )
|
||||||
|
{
|
||||||
|
void *address = backlight_get_custom_key_color_eeprom_address(led[i]);
|
||||||
|
eeprom_update_byte(address, hsv.h);
|
||||||
|
eeprom_update_byte(address+1, hsv.s);
|
||||||
|
eeprom_update_byte(address+2, hsv.v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_test_led( uint8_t index, bool red, bool green, bool blue )
|
||||||
|
{
|
||||||
|
for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
|
||||||
|
{
|
||||||
|
if ( i == index )
|
||||||
|
{
|
||||||
|
IS31FL3731_set_led_control_register( i, red, green, blue );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IS31FL3731_set_led_control_register( i, false, false, false );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t backlight_get_tick(void)
|
||||||
|
{
|
||||||
|
return g_tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
void backlight_debug_led( bool state )
|
||||||
|
{
|
||||||
|
// if (state)
|
||||||
|
// {
|
||||||
|
// // Output high.
|
||||||
|
// DDRD |= (1<<6);
|
||||||
|
// PORTD |= (1<<6);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// // Output low.
|
||||||
|
// DDRD &= ~(1<<6);
|
||||||
|
// PORTD &= ~(1<<6);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void rgblight_toggle(void) {
|
||||||
|
g_config.enabled ^= 1;
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rgblight_step(void) {
|
||||||
|
g_config.effect = (g_config.effect + 1) % (BACKLIGHT_EFFECT_MAX + 1);
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rgblight_increase_hue(void) {
|
||||||
|
backlight_color_1_hue_increase();
|
||||||
|
backlight_color_2_hue_increase();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rgblight_decrease_hue(void) {
|
||||||
|
backlight_color_1_hue_decrease();
|
||||||
|
backlight_color_2_hue_decrease();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rgblight_increase_sat(void) {
|
||||||
|
backlight_color_1_sat_increase();
|
||||||
|
backlight_color_2_sat_increase();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rgblight_decrease_sat(void) {
|
||||||
|
backlight_color_1_sat_decrease();
|
||||||
|
backlight_color_2_sat_decrease();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rgblight_increase_val(void) {
|
||||||
|
g_config.color_1.v = increment( g_config.color_1.s, 8, 0, 255 );
|
||||||
|
g_config.color_2.v = increment( g_config.color_1.s, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rgblight_decrease_val(void) {
|
||||||
|
g_config.color_1.v = decrement( g_config.color_1.s, 8, 0, 255 );
|
||||||
|
g_config.color_2.v = decrement( g_config.color_1.s, 8, 0, 255 );
|
||||||
|
backlight_config_save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rgblight_mode(uint8_t mode) {
|
||||||
|
g_config.effect = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rgblight_get_mode(void) {
|
||||||
|
return g_config.effect;
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
/* Copyright 2017 Jason Williams
|
||||||
|
* Copyright 2017 Jack Humbert
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RGB_MATRIX_H
|
||||||
|
#define RGB_MATRIX_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "color.h"
|
||||||
|
#include "is31fl3731.h"
|
||||||
|
#include "quantum.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
HSV color;
|
||||||
|
uint8_t index;
|
||||||
|
} zeal_indicator;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
bool enabled:1; // |
|
||||||
|
bool use_split_left_shift:1; // |
|
||||||
|
bool use_split_right_shift:1; // |
|
||||||
|
bool use_7u_spacebar:1; // |
|
||||||
|
bool use_iso_enter:1; // |
|
||||||
|
bool disable_when_usb_suspended:1; // |
|
||||||
|
bool __pad6:1; // |
|
||||||
|
bool __pad7:1; // 1 byte
|
||||||
|
uint8_t disable_after_timeout; // 1 byte
|
||||||
|
uint8_t brightness; // 1 byte
|
||||||
|
uint8_t effect; // 1 byte
|
||||||
|
HSV color_1; // 3 bytes
|
||||||
|
HSV color_2; // 3 bytes
|
||||||
|
zeal_indicator caps_lock_indicator; // 4 bytes
|
||||||
|
zeal_indicator layer_1_indicator; // 4 bytes
|
||||||
|
zeal_indicator layer_2_indicator; // 4 bytes
|
||||||
|
zeal_indicator layer_3_indicator; // 4 bytes
|
||||||
|
uint16_t alphas_mods[5]; // 10 bytes
|
||||||
|
} rgb_matrix_config; // = 36 bytes
|
||||||
|
|
||||||
|
#define EEPROM_BACKLIGHT_CONFIG_ADDR ((void*)35)
|
||||||
|
// rgb_matrix_config uses 36 bytes
|
||||||
|
// 35+36=71
|
||||||
|
#define EEPROM_BACKLIGHT_KEY_COLOR_ADDR ((void*)71)
|
||||||
|
|
||||||
|
|
||||||
|
void backlight_effect_single_LED_test(void);
|
||||||
|
|
||||||
|
void backlight_config_set_alphas_mods( uint16_t *value );
|
||||||
|
void backlight_config_load(void);
|
||||||
|
void backlight_config_save(void);
|
||||||
|
|
||||||
|
void backlight_init_drivers(void);
|
||||||
|
|
||||||
|
void backlight_timer_init(void);
|
||||||
|
void backlight_timer_enable(void);
|
||||||
|
void backlight_timer_disable(void);
|
||||||
|
|
||||||
|
void backlight_set_suspend_state(bool state);
|
||||||
|
void backlight_set_indicator_state(uint8_t state);
|
||||||
|
|
||||||
|
|
||||||
|
void backlight_rgb_task(void);
|
||||||
|
|
||||||
|
// This should not be called from an interrupt
|
||||||
|
// (eg. from a timer interrupt).
|
||||||
|
// Call this while idle (in between matrix scans).
|
||||||
|
// If the buffer is dirty, it will update the driver with the buffer.
|
||||||
|
void backlight_update_pwm_buffers(void);
|
||||||
|
|
||||||
|
void backlight_set_key_hit(uint8_t row, uint8_t col);
|
||||||
|
void backlight_unset_key_hit(uint8_t row, uint8_t col);
|
||||||
|
|
||||||
|
void backlight_effect_increase(void);
|
||||||
|
void backlight_effect_decrease(void);
|
||||||
|
|
||||||
|
void backlight_brightness_increase(void);
|
||||||
|
void backlight_brightness_decrease(void);
|
||||||
|
|
||||||
|
void backlight_color_1_hue_increase(void);
|
||||||
|
void backlight_color_1_hue_decrease(void);
|
||||||
|
void backlight_color_1_sat_increase(void);
|
||||||
|
void backlight_color_1_sat_decrease(void);
|
||||||
|
void backlight_color_2_hue_increase(void);
|
||||||
|
void backlight_color_2_hue_decrease(void);
|
||||||
|
void backlight_color_2_sat_increase(void);
|
||||||
|
void backlight_color_2_sat_decrease(void);
|
||||||
|
|
||||||
|
void *backlight_get_key_color_eeprom_address(uint8_t led);
|
||||||
|
void backlight_get_key_color( uint8_t led, HSV *hsv );
|
||||||
|
void backlight_set_key_color( uint8_t row, uint8_t column, HSV hsv );
|
||||||
|
|
||||||
|
void backlight_test_led( uint8_t index, bool red, bool green, bool blue );
|
||||||
|
uint32_t backlight_get_tick(void);
|
||||||
|
void backlight_debug_led(bool state);
|
||||||
|
|
||||||
|
void rgblight_toggle(void);
|
||||||
|
void rgblight_step(void);
|
||||||
|
void rgblight_increase_hue(void);
|
||||||
|
void rgblight_decrease_hue(void);
|
||||||
|
void rgblight_increase_sat(void);
|
||||||
|
void rgblight_decrease_sat(void);
|
||||||
|
void rgblight_increase_val(void);
|
||||||
|
void rgblight_decrease_val(void);
|
||||||
|
void rgblight_mode(uint8_t mode);
|
||||||
|
uint32_t rgblight_get_mode(void);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in new issue