Select Git revision
dispatcher.h
Forked from
card10 / firmware
Source project has a limited visibility.
-
rahix authored
This change allows cleaner loading of payloads and is a preparation for the proper implementation/use of hardware_reset(). Signed-off-by:
Rahix <rahix@rahix.de>
rahix authoredThis change allows cleaner loading of payloads and is a preparation for the proper implementation/use of hardware_reset(). Signed-off-by:
Rahix <rahix@rahix.de>
leds.c 7.13 KiB
#include "gpio.h"
#include "portexpander.h"
#include "max32665.h"
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#define NUM_LEDS 15
#define DEFAULT_DIM_TOP 1
#define DEFAULT_DIM_BOTTOM 8
#define MAX_DIM 8
static const gpio_cfg_t rgb_dat_pin = {
PORT_1, PIN_14, GPIO_FUNC_OUT, GPIO_PAD_NONE
};
static const gpio_cfg_t rgb_clk_pin = {
PORT_1, PIN_15, GPIO_FUNC_OUT, GPIO_PAD_NONE
};
static uint8_t leds[NUM_LEDS][3];
static uint8_t gamma_table[3][256];
static uint8_t active_groups;
static uint8_t bottom_dim; //index 11-14
static uint8_t top_dim; //index 0-10
static bool powersave;
static long powerup_wait_cycles = 500;
/***** Functions *****/
// *****************************************************************************
typedef struct {
float r; // a fraction between 0 and 1
float g; // a fraction between 0 and 1
float b; // a fraction between 0 and 1
} rgb;
typedef struct {
float h; // angle in degrees
float s; // a fraction between 0 and 1
float v; // a fraction between 0 and 1
} hsv;
#if 0
static hsv rgb2hsv(rgb in)
{
hsv out;
float min, max, delta;
min = in.r < in.g ? in.r : in.g;
min = min < in.b ? min : in.b;
max = in.r > in.g ? in.r : in.g;
max = max > in.b ? max : in.b;
out.v = max; // v
delta = max - min;
if (delta < 0.00001)
{
out.s = 0;
out.h = 0; // undefined, maybe nan?
return out;
}
if( max > 0.0 ) { // NOTE: if Max is == 0, this divide would cause a crash
out.s = (delta / max); // s
} else {
// if max is 0, then r = g = b = 0
// s = 0, h is undefined
out.s = 0.0;
out.h = 0.0; // its now undefined
return out;
}
if( in.r >= max ) // > is bogus, just keeps compilor happy
out.h = ( in.g - in.b ) / delta; // between yellow & magenta
else
if( in.g >= max )
out.h = 2.0 + ( in.b - in.r ) / delta; // between cyan & yellow
else
out.h = 4.0 + ( in.r - in.g ) / delta; // between magenta & cyan
out.h *= 60.0; // degrees
if( out.h < 0.0 )
out.h += 360.0;
return out;
}
#endif
static rgb hsv2rgb(hsv in)
{
float hh, p, q, t, ff;
long i;
rgb out;
if (in.s <= 0.0) { // < is bogus, just shuts up warnings
out.r = in.v;
out.g = in.v;
out.b = in.v;
return out;
}
hh = in.h;
if (hh >= 360.0)
hh = 0.0;
hh /= 60.0;
i = (long)hh;
ff = hh - i;
p = in.v * (1.0 - in.s);
q = in.v * (1.0 - (in.s * ff));
t = in.v * (1.0 - (in.s * (1.0 - ff)));
switch (i) {
case 0:
out.r = in.v;
out.g = t;
out.b = p;
break;
case 1:
out.r = q;
out.g = in.v;
out.b = p;
break;
case 2:
out.r = p;
out.g = in.v;
out.b = t;
break;
case 3:
out.r = p;
out.g = q;
out.b = in.v;
break;
case 4:
out.r = t;
out.g = p;
out.b = in.v;
break;
case 5:
default:
out.r = in.v;
out.g = p;
out.b = q;
break;
}
return out;
}
static void shift(uint8_t data)
{
for (int i = 0; i < 8; i++) {
if (data & 0x80) {
GPIO_OutSet(&rgb_dat_pin);
} else {
GPIO_OutClr(&rgb_dat_pin);
}
GPIO_OutClr(&rgb_clk_pin);
//TMR_Delay(MXC_TMR0, MSEC(1), 0);
GPIO_OutSet(&rgb_clk_pin);
//TMR_Delay(MXC_TMR0, MSEC(1), 0);
data <<= 1;
}
}
static void leds_start(void)
{
shift(0x00);
shift(0x00);
shift(0x00);
shift(0x00);
}
static void leds_shift(uint8_t r, uint8_t g, uint8_t b, uint8_t dim)
{
shift(0xE0 | (dim & 0x1F));
shift(b);
shift(g);
shift(r);
}
static void leds_stop(void)
{
shift(0xFF);
shift(0xFF);
shift(0xFF);
shift(0xFF);
}
static uint8_t led_to_dim_value(uint8_t led)
{
return (led < 11) ? top_dim : bottom_dim;
}
void leds_set_dim_top(uint8_t value)
{
top_dim = (value > MAX_DIM) ? MAX_DIM : value;
}
void leds_set_dim_bottom(uint8_t value)
{
bottom_dim = (value > MAX_DIM) ? MAX_DIM : value;
}
void leds_prep(uint8_t led, uint8_t r, uint8_t g, uint8_t b)
{
leds[led][0] = r;
leds[led][1] = g;
leds[led][2] = b;
}
void leds_get_rgb(uint8_t led, uint8_t *rgb)
{
rgb[0] = leds[led][0];
rgb[1] = leds[led][1];
rgb[2] = leds[led][2];
}
#if 0
//don't use, is buggy
void leds_set_autodim(uint8_t led, uint8_t r, uint8_t g, uint8_t b)
{
if(led==NUM_LEDS){
leds_set(led,r,g,b);
return;
}
leds[led][3] = max(r,max(g,b));
float gain = (float)255/leds[led][3]; //might cause rounding->overflow errors might debug later idk~
leds[led][0] = (uint8_t)(r*gain);
leds[led][1] = (uint8_t)(g*gain);
leds[led][2] = (uint8_t)(b*gain);
}
#endif
void leds_prep_hsv(uint8_t led, float h, float s, float v)
{
hsv in = { h, s, v };
rgb out = hsv2rgb(in);
leds[led][0] = out.r * 255;
leds[led][1] = out.g * 255;
leds[led][2] = out.b * 255;
}
static bool is_led_on(uint8_t led) // scheduled to be on after next update
{
if (!led_to_dim_value(led)) {
return false;
}
for (int i = 0; i < 3; i++) {
if (leds[led][i] != 0) {
return true;
}
}
return false;
}
static uint8_t led_to_group(uint8_t led)
{
if (led == 14) {
return 1;
} else if (led >= 11) {
return 2;
}
return 3;
}
static uint8_t
check_privilege(void) //returns number of hierarchical groups with power
{
for (int i = 0; i < NUM_LEDS; i++) {
if (is_led_on(i)) {
return led_to_group(i);
}
}
return 0;
}
static uint8_t power_pin_conversion(uint8_t group)
{
if (group == 2) {
return 1;
}
if (group == 1) {
return 2;
}
return 0;
}
static void power_all(void)
{
portexpander_out_clr(PIN_0 | PIN_1 | PIN_2);
}
void leds_update_power(void)
{
if (!powersave) {
return;
}
uint8_t new_groups =
check_privilege(); //there must be a prettier way to do this but meh
if (new_groups == active_groups) {
return;
}
uint8_t out_val = 0;
for (int i = new_groups; i < 3; ++i) {
out_val |= (1 << power_pin_conversion(i));
}
portexpander_out_put(PIN_0 | PIN_1 | PIN_2, out_val);
if (active_groups < new_groups) {
for (int i = 0; i < powerup_wait_cycles; i++) {
__NOP();
}
}
active_groups = new_groups;
}
void leds_powersave(bool eco)
{
powersave = eco;
if (!powersave) {
power_all();
} else {
leds_update_power();
}
}
void leds_update(void)
{
leds_start();
for (int i = NUM_LEDS - 1; i >= 0; i--) {
leds_shift(
gamma_table[0][leds[i][0]],
gamma_table[1][leds[i][1]],
gamma_table[2][leds[i][2]],
led_to_dim_value(i)
);
}
leds_stop();
}
void leds_flashlight(bool power)
{
portexpander_out_put(PIN_7, (power) ? 0 : 1);
}
void leds_set_gamma_table(uint8_t rgb_channel, uint8_t table[256])
{
for (int i = 0; i < 256; i++) {
gamma_table[rgb_channel][i] = table[i];
}
}
void leds_init(void)
{
GPIO_Config(&rgb_clk_pin);
GPIO_Config(&rgb_dat_pin);
GPIO_OutSet(&rgb_clk_pin);
GPIO_OutClr(&rgb_dat_pin);
memset(leds, 0, sizeof(leds));
powersave = TRUE;
top_dim = DEFAULT_DIM_TOP;
bottom_dim = DEFAULT_DIM_BOTTOM;
for (int i = 0; i < NUM_LEDS; i++) {
for (int j = 0; j < 3; j++) {
leds[i][j] = 0;
}
}
for (int i = 0; i < 256; i++) {
for (int j = 0; j < 3; j++) {
int k = (i * (1 + i) + 255) >> 8;
gamma_table[j][i] = (k * (k + 1) + 255) >> 8;
}
}
leds_update();
}