Compare commits

..

No commits in common. "db44d3dbab15f23b1783bf90d8224209548a700b" and "8a5e11592cd3d99d610dd42b1ed5f29619c22c50" have entirely different histories.

18 changed files with 188 additions and 551 deletions

View File

@ -5,31 +5,23 @@
* while sleep deprived for a super constrained mcu
*
* some bugs fixed for defcon 32 on aug 6-7, 2024
* - don't remember what was fixed
*
* some bugs fixed for supercon on oct 15, 2024
* - fixed support for AW20054, which only supports 9 rows
* did this by respecting aw->rows
*
*
* driver assumptions:
* - rows and columns are as is ordered on the chip, lowest to highest
* - rows and columns are used in order on the chip, lowest to highest
* (if any are skipped, just skip this data in your buffer)
* - buffer size does not need to encompass all possible LEDs, only those
* which you have specified you are using.
* ensure sizeof(aw->fade) == aw->rows + aw->cols
* - duty cycle will be set automatically according to aw->cols
* - duty cycle will be set according to the column count
* - all AW20xxx chips will operate on the same i2c bus
* - a static data buffer is used
* - the only i2c write routine does not have register arguments
*
* driver notices:
* - updates only happen one column at a time, and are blocking
* (future version may implement a callback when each column is done)
* - this driver has not yet implemented the pattern controller
* - this driver has not yet implemented the GAIN register, except as
* a global configuration, so dimming only operates 8-bit
* - this driver has not yet implemented the GAIN register, so only operates 8-bit
* (will be implemented later to allow for beyond-8-bit operation)
* - this driver has not yet implemented FADEDIM mode
* - all transfers result in copies of data, which is wasteful
* (future version may transfer LED data directly from the buffer)
*
* if you need anything different, write it yourself
*/
@ -101,10 +93,10 @@ void aw20x_sleep(struct AW20x *aw, uint8_t sleep)
else aw->state &= ~AW20X_STATE_SLEEP_MASK;
// burn some cycles if we woke up
if (!sleep) AW20X_INIT_DELAY();
if (!sleep) PLATFORM_INIT_DELAY();
}
void aw20x_set_imax(struct AW20x *aw, uint8_t imax)
void aw20x_imax(struct AW20x *aw, uint8_t imax)
{
AW20X_SET_PAGE(AW20X_PAGE0_CONFIG);
@ -114,28 +106,26 @@ void aw20x_set_imax(struct AW20x *aw, uint8_t imax)
/*
* sends LED values to the chip
*/
void aw20x_set_fade(struct AW20x *aw)
void aw20x_commit_fade(struct AW20x *aw)
{
uint8_t c;
uint8_t row;
uint8_t offset;
// make sure we're on the fade page
AW20X_SET_PAGE(AW20X_PAGE2_FADE);
// don't touch the buffer until we are allowed
while (AW20X_I2C_busy());
row = offset = 0;
row = 0;
for (c = 0; c < aw->cols; c++) {
// write to chip
AW20X_I2C_writereg(aw->addr, offset, aw->fade + row, aw->rows);
AW20X_I2C_writereg(aw->addr, row, aw->fade + row, aw->rows);
while (AW20X_I2C_busy());
row += aw->rows;
offset += AW20X_MAX_ROWS;
row += AW20X_MAX_ROWS;
}
}
void aw20x_set_dim(struct AW20x *aw)
void aw20x_commit_dim(struct AW20x *aw)
{
// todo: implement
}
@ -145,11 +135,10 @@ void aw20x_set_dim(struct AW20x *aw)
* used when just using FADE and 8-bit mode
* to set initial and fine tune from IMAX the output current.
*/
void aw20x_set_dim_global(struct AW20x *aw, uint8_t dim)
void aw20x_commit_dim_global(struct AW20x *aw, uint8_t dim)
{
uint8_t i;
uint8_t row;
uint8_t offset;
uint8_t row = 0;
// ceil
if (dim > 0x3f) dim = 0x3f;
@ -163,13 +152,10 @@ void aw20x_set_dim_global(struct AW20x *aw, uint8_t dim)
for (i = 0; i <= aw->rows; i++) aw_buf[i] = dim;
// send buffer for each column
row = offset = 0;
for (i = 0; i < aw->cols; i++) {
AW20X_I2C_writereg(aw->addr, row, aw_buf, aw->rows);
while (AW20X_I2C_busy());
row += aw->rows;
offset += AW20X_MAX_ROWS;
row += AW20X_MAX_ROWS;
}
}
@ -186,19 +172,16 @@ void aw20x_led_on(struct AW20x *aw, uint8_t first, uint8_t last, uint8_t on_bit)
* enables LEDs based on user LED count, zero-indexed
* AW20036 would be 0-35, AW00054 would be 0-53, and so on
* for example, LEDs 8-12 on AW20054 would enable C0R8, C1R0, C1R1, C1R2
* all other LEDs are disabled
*
* todo:
* - read current state, and apply bitfields to the currently active state
* - allow bypassing the readback for faster operation (such as setting all LEDs on at startup)
* - make this more efficient (36 LEDs takes ~0.3ms on a 48MHz PIC!)
*/
void aw20x_led_enable_range(struct AW20x *aw, uint8_t first, uint8_t last)
void aw20x_led_enable(struct AW20x *aw, uint8_t first, uint8_t last)
{
uint8_t c, r;
uint8_t offset = 0;
uint8_t boff;
uint8_t *buf;
// make sure we're on the config page
AW20X_SET_PAGE(AW20X_PAGE0_CONFIG);
@ -206,29 +189,22 @@ void aw20x_led_enable_range(struct AW20x *aw, uint8_t first, uint8_t last)
while (AW20X_I2C_busy());
// bits are stored 6 bits per byte, 2 bytes per column, one bit for each row
// for a maximum of the AW20X_MAX_ROWS of LED on bits
// we only want to touch bits that exist on the chip and in the correct order
for (c = 0; c < aw->cols; c++) {
buf = &aw_buf[c*2];
boff = 0;
for (r = 0; r < AW20X_MAX_LEDON_BITS*2; r++) {
if (r >= aw->rows) break; // max bits to process
if (r == AW20X_MAX_LEDON_BITS) { // only this many bits per byte
boff += AW20X_MAX_LEDON_BITS;
buf++;
}
if (r+offset >= first) {
if (r+offset <= last) {
*buf |= (1 << r - boff);
boff = 0;
for (c = 0; c < (aw->cols * 2); c++) {
aw_buf[c] = 0;
for (r = 0; r < AW20X_MAX_LEDON_BITS; r++) {
if (r+boff >= first) {
if (r+boff <= last) {
aw_buf[c] |= (1 << r);
}
}
}
offset += aw->rows;
boff += AW20X_MAX_LEDON_BITS;
}
AW20X_I2C_writereg(aw->addr, AW20X_REG_LEDON0, aw_buf, c*2);
AW20X_I2C_writereg(aw->addr, AW20X_REG_LEDON0, aw_buf, c);
}
/*

View File

@ -13,7 +13,7 @@
#define AW20X_INIT_DELAY() { uint16_t zz = 1000; while(zz--); }
#define PLATFORM_INIT_DELAY() { uint16_t zz = 1000; while(zz--); }
// burn cycles for ~200us
#define AW20X_MAX_COLS 9
@ -169,11 +169,10 @@ enum aw20x_size {
typedef struct AW20x {
uint8_t addr;
uint8_t config; // settings for the chip
uint8_t hw_rows; // maximum hardware rows in your chip (108, 072, 036: 12, 054: 9)
uint8_t cols; // highest column used, 1-6
uint8_t rows; // highest row used, 1-12
uint8_t state; // keeps track of active page, and high bit is set if asleep
uint8_t cols; // highest column used by application, 1-9
uint8_t rows; // highest row used by application, 1-12
uint8_t pad[2];
uint8_t pad[3];
uint8_t *fade; // led buffer location for FADE (required), of size cols+rows
uint8_t *gain; // led buffer location for GAIN (optional), of size cols+rows
} AW20x;
@ -184,10 +183,10 @@ void aw20x_init(struct AW20x *aw, uint8_t addr, uint8_t cols, uint8_t rows, uint
void aw20x_sleep(struct AW20x *aw, uint8_t sleep);
void aw20x_set_fade(struct AW20x *aw);
void aw20x_set_dim_global(struct AW20x *aw, uint8_t dim);
void aw20x_commit_fade(struct AW20x *aw);
void aw20x_commit_dim_global(struct AW20x *aw, uint8_t dim);
void aw20x_led_enable_range(struct AW20x *aw, uint8_t first, uint8_t last);
void aw20x_led_enable(struct AW20x *aw, uint8_t first, uint8_t last);

View File

@ -5,26 +5,4 @@
* Author: true
*/
#include "lightsense.h"
uint8_t lsens_get_coarse()
{
return 0;
}
uint16_t lsens_get_fine()
{
return 0;
}
uint16_t lsens_get_dark_threshold()
{
return 0;
}
void lsens_set_dark_threshold(uint16_t threshold)
{
}

View File

@ -9,16 +9,5 @@
#define USER_HW_LIGHTSENSE_H_
#include <stdint.h>
uint8_t lsens_get_coarse();
uint16_t lsens_get_fine();
uint16_t lsens_get_dark_threshold();
void lsens_set_dark_threshold(uint16_t threshold);
#endif /* USER_HW_LIGHTSENSE_H_ */

View File

@ -8,11 +8,8 @@
#include <CH59x_common.h>
#include "rgbled.h"
#include "hsv2rgb.h"
#include "hw/aw20xxx.h"
#include "user_config.h"
#include "../hw/aw20xxx.h"
@ -24,7 +21,6 @@
/*
static const uint16_t pwm_cie_256in_1024out[] = {
0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
7, 8, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15,
@ -43,17 +39,12 @@ static const uint16_t pwm_cie_256in_1024out[] = {
734, 742, 751, 759, 768, 776, 785, 794, 802, 811, 820, 829, 838, 847, 857, 866,
875, 885, 894, 903, 913, 923, 932, 942, 952, 962, 972, 982, 992, 1002, 1013, 1023,
};
*/
AW20x awled;
static uint8_t awled_fade[AW20X_FADE_COUNT];
static uint8_t led_matrix_needs_update = 0;
struct color_rgb rgb_out[RGBLED_COUNT];
struct color_hsv hsv_out[RGBLED_COUNT];
static uint8_t led_matrix_updated = 0;
@ -67,45 +58,5 @@ void rgbled_init()
x = GetSysClock() / 16384;
while (x--);
// clear fade
memset(awled_fade, 0x00, sizeof(awled_fade));
// set up RGBLED chip
awled.fade = awled_fade;
aw20x_init(&awled, AW20X_ADDR_GND << 1, AW20X_COLS, AW20X_ROWS, AW20X_IMAX_13_3MA);
aw20x_set_dim_global(&awled, AW20X_DIM);
aw20x_set_fade(&awled);
aw20x_led_enable_range(&awled, 0, 23);
}
void rgbled_flag_update()
{
led_matrix_needs_update = 1;
}
void rgbled_send()
{
if (led_matrix_needs_update) {
led_matrix_needs_update = 0;
// leds off?
if ((uconf.flags & UCONF_FLAGS_LEDS_DISABLE) || !(uconf.flags & UCONF_FLAGS_LEDS_DISABLE)) {
// yes, clear the data
memset(awled_fade, 0x00, sizeof(awled_fade));
} else {
// render our data to output buffer
// todo
}
aw20x_set_fade(&awled);
}
}
void rgbled_runprog(uint8_t tick_ctr)
{
// run program
if (rgb_pgm[uconf.ledprog_rgb_idx].prog) {
rgb_pgm[uconf.ledprog_rgb_idx].prog(uconf.ledprog_rgb_data[uconf.ledprog_rgb_idx], tick_ctr);
}
}

View File

@ -20,7 +20,7 @@
#define RGBLED_COUNT 12
#define RGB_EDGE_COUNT 10
@ -31,17 +31,16 @@ typedef struct LedProgram {
extern const uint8_t rgb_map[RGBLED_COUNT];
extern const LedProgram rgb_pgm[6];
extern const uint8_t edge_map[10];
extern const LedProgram edge_pgm[6];
extern struct color_hsv hsv_out[RGBLED_COUNT];
extern color_hsv hsv_edge[RGB_EDGE_COUNT];
void rgbled_init();
void rgbled_send();
void rgbled_runprog(uint8_t tick_ctr);
void rgb_edge_update(uint8_t idx);

View File

@ -1,5 +1,5 @@
/*
* rgbled_prog.c
* $Id: rgbled_edge.c 500 2021-08-08 19:43:38Z true $
* begin 20210720 true
*
* programs to run to show neat shit on the LEDs
@ -24,16 +24,14 @@
#include "user_config.h"
const uint8_t rgb_map[RGBLED_COUNT] = {
3, 5, 7, 9, 0, 1,
2, 4, 6, 8, 1, 1
};
const uint8_t edge_map[10] = {3, 5, 7, 9, 0, 2, 4, 6, 8, 1};
static uint8_t timeout;
void rgb_solid(uint8_t *a, uint16_t tick)
void edge_solid(uint8_t *a, uint16_t tick)
{
// 1=bitfield, 2=timeout-set, 4=state, 5=hue, 6=sat, 7=val
// bitfield:
@ -80,20 +78,20 @@ void rgb_solid(uint8_t *a, uint16_t tick)
}
// update
hsv_out[0].h = hsv.h;
hsv_out[0].s = hsv.s;
hsv_out[0].v = hsv.v;
hsv_edge[0].h = hsv.h;
hsv_edge[0].s = hsv.s;
hsv_edge[0].v = hsv.v;
for (i = 1; i < RGBLED_COUNT; i++) {
hsv_out[i].h = hsv_out[0].h;
hsv_out[i].s = hsv_out[0].s;
hsv_out[i].v = hsv_out[0].v;
for (i = 1; i < RGB_EDGE_COUNT; i++) {
hsv_edge[i].h = hsv_edge[0].h;
hsv_edge[i].s = hsv_edge[0].s;
hsv_edge[i].v = hsv_edge[0].v;
}
}
// todo: improve fading smoothness by doing fadeout every callback instead of on timeout
// this can be done once LED bit depth is increased
void rgb_flicker(uint8_t *a, uint16_t tick)
void edge_flicker(uint8_t *a, uint16_t tick)
{
// 0=speed, 1=bitfield, 2=timeout-set, 4=state, 6=max-val, 7=min-val
// bitfield:
@ -120,8 +118,8 @@ void rgb_flicker(uint8_t *a, uint16_t tick)
}
// set constants
hsv_out[0].h = uconf.favcolor_hue * 6;
hsv_out[0].s = uconf.favcolor_sat;
hsv_edge[0].h = uconf.favcolor_hue * 6;
hsv_edge[0].s = uconf.favcolor_sat;
if (a[6]) max = a[6]; else max = 255;
@ -133,7 +131,7 @@ void rgb_flicker(uint8_t *a, uint16_t tick)
}
// process and update LEDs
for (i = 0; i < RGBLED_COUNT; i++) {
for (i = 0; i < RGB_EDGE_COUNT; i++) {
// compute new val on first round or if all-same flicker is disabled
if (!(a[1] & 0x08) || i == 0) {
new_val = u16_scale((prng_get16() & 0xff), 0, 255, min, max);
@ -144,39 +142,39 @@ void rgb_flicker(uint8_t *a, uint16_t tick)
if (a[1] & 0x02) {
// is it random?
if (a[1] & 0x04) {
i = prng_get16() % RGBLED_COUNT;
i = prng_get16() % RGB_EDGE_COUNT;
} else {
// nope, sequential
a[4]++;
a[4] %= RGBLED_COUNT;
i = a[4] % RGBLED_COUNT;
a[4] %= RGB_EDGE_COUNT;
i = a[4] % RGB_EDGE_COUNT;
// is it in reverse?
if (a[1] & 0x01) {
i = RGBLED_COUNT - 1 - i;
i = RGB_EDGE_COUNT - 1 - i;
}
// correct position
if (!(a[1] & 0x20)) {
i = rgb_map[i];
i = edge_map[i];
}
}
}
// apply
hsv_out[i].h = (a[1] & 0x40) ? (prng_get16() & 0x600) : hsv_out[0].h;
hsv_out[i].s = hsv_out[0].s;
hsv_out[i].v = new_val & 0xff;
hsv_edge[i].h = (a[1] & 0x40) ? (prng_get16() & 0x600) : hsv_edge[0].h;
hsv_edge[i].s = hsv_edge[0].s;
hsv_edge[i].v = new_val & 0xff;
// bail if only doing one LED
if (a[1] & 0x02) {
// but make sure to fade LEDs if needed
if (a[1] & 0x10) {
for (i = 0; i < RGBLED_COUNT; i++) {
if (hsv_out[i].v <= a[0]) {
hsv_out[i].v = 0;
for (i = 0; i < RGB_EDGE_COUNT; i++) {
if (hsv_edge[i].v <= a[0]) {
hsv_edge[i].v = 0;
} else {
hsv_out[i].v -= a[0];
hsv_edge[i].v -= a[0];
}
}
}
@ -185,9 +183,9 @@ void rgb_flicker(uint8_t *a, uint16_t tick)
}
}
uint8_t rgb_circles_divider = 0;
uint8_t rgb_circles_sec_ticks = 0;
void rgb_circles(uint8_t *a, uint16_t tick)
uint8_t edge_circles_divider = 0;
uint8_t edge_circles_sec_ticks = 0;
void edge_circles(uint8_t *a, uint16_t tick)
{
// 0=speed, 1=bitfield, 2=timeout-set, 4=state, 5=hue, 6=sat, 7=val
// bitfield:
@ -213,22 +211,22 @@ void rgb_circles(uint8_t *a, uint16_t tick)
uint8_t desatfade = a[1] & 0x20;
// fading
rgb_circles_divider++;
rgb_circles_divider %= 10;
if (!rgb_circles_divider && (a[1] & 0x02)) {
for (i = 0; i < RGBLED_COUNT; i++) {
if (hsv_out[i].v <= trailfade) {
hsv_out[i].v = 0;
edge_circles_divider++;
edge_circles_divider %= 10;
if (!edge_circles_divider && (a[1] & 0x02)) {
for (i = 0; i < RGB_EDGE_COUNT; i++) {
if (hsv_edge[i].v <= trailfade) {
hsv_edge[i].v = 0;
} else {
hsv_out[i].v -= trailfade;
hsv_edge[i].v -= trailfade;
}
if (desatfade) {
// fade to white too
if (hsv_out[i].s <= (trailfade >> 1)) {
hsv_out[i].s = 0;
if (hsv_edge[i].s <= (trailfade >> 1)) {
hsv_edge[i].s = 0;
} else {
hsv_out[i].s -= (trailfade >> 1);
hsv_edge[i].s -= (trailfade >> 1);
}
}
}
@ -266,9 +264,9 @@ void rgb_circles(uint8_t *a, uint16_t tick)
} else if (srate) {
// gradual offset mode
srate <<= 2;
rgb_circles_sec_ticks++;
if (rgb_circles_sec_ticks > srate) {
rgb_circles_sec_ticks = 0;
edge_circles_sec_ticks++;
if (edge_circles_sec_ticks > srate) {
edge_circles_sec_ticks = 0;
y += 9;
}
}
@ -309,30 +307,30 @@ void rgb_circles(uint8_t *a, uint16_t tick)
}
// set the next item
hsv_out[rgb_map[x]].h = h;
hsv_out[rgb_map[x]].s = s;
hsv_out[rgb_map[x]].v = v;
hsv_edge[edge_map[x]].h = h;
hsv_edge[edge_map[x]].s = s;
hsv_edge[edge_map[x]].v = v;
if (second && x != y) {
if (secval) v >>= 1;
hsv_out[rgb_map[y]].h = h2;
hsv_out[rgb_map[y]].s = s2;
hsv_out[rgb_map[y]].v = v;
hsv_edge[edge_map[y]].h = h2;
hsv_edge[edge_map[y]].s = s2;
hsv_edge[edge_map[y]].v = v;
}
// clear those that are on if trails are not enabled
if (!trail) {
for (i = 0; i < RGBLED_COUNT; i++) {
for (i = 0; i < RGB_EDGE_COUNT; i++) {
if (i != x || (second && (i != y))) {
hsv_out[rgb_map[i]].v = 0;
hsv_edge[edge_map[i]].v = 0;
}
}
}
}
uint8_t rgb_waving_divider = 0;
void rgb_waving(uint8_t *a, uint16_t tick)
uint8_t edge_waving_divider = 0;
void edge_waving(uint8_t *a, uint16_t tick)
{
// 0=wait-delay, 1=bitfield, 2=timeout-set, 456=work
// bitfield:
@ -347,22 +345,22 @@ void rgb_waving(uint8_t *a, uint16_t tick)
uint8_t trailfade = a[0] >> 4;
uint8_t desatfade = a[1] & 0x20;
rgb_waving_divider++;
rgb_waving_divider %= 10;
if (!rgb_waving_divider && (a[1] & 0x02)) {
for (i = 0; i < RGBLED_COUNT; i++) {
if (hsv_out[i].v <= trailfade) {
hsv_out[i].v = 0;
edge_waving_divider++;
edge_waving_divider %= 10;
if (!edge_waving_divider && (a[1] & 0x02)) {
for (i = 0; i < RGB_EDGE_COUNT; i++) {
if (hsv_edge[i].v <= trailfade) {
hsv_edge[i].v = 0;
} else {
hsv_out[i].v -= trailfade;
hsv_edge[i].v -= trailfade;
}
if (desatfade) {
// fade to white too
if (hsv_out[i].s <= (trailfade >> 1)) {
hsv_out[i].s = 0;
if (hsv_edge[i].s <= (trailfade >> 1)) {
hsv_edge[i].s = 0;
} else {
hsv_out[i].s -= (trailfade >> 1);
hsv_edge[i].s -= (trailfade >> 1);
}
}
}
@ -384,8 +382,8 @@ void rgb_waving(uint8_t *a, uint16_t tick)
// clear values if trails not enabled
if (!(a[1] & 0x02)) {
for (i = 0; i < RGBLED_COUNT; i++) {
hsv_out[i].v = 0;
for (i = 0; i < RGB_EDGE_COUNT; i++) {
hsv_edge[i].v = 0;
}
}
@ -400,13 +398,13 @@ void rgb_waving(uint8_t *a, uint16_t tick)
break;
}
case 1: { // moving down
hsv_out[rgb_map[ a[6]]].h = uconf.favcolor_hue * 6;
hsv_out[rgb_map[ a[6]]].s = uconf.favcolor_sat;
hsv_out[rgb_map[ a[6]]].v = uconf.favcolor_val;
hsv_edge[edge_map[ a[6]]].h = uconf.favcolor_hue * 6;
hsv_edge[edge_map[ a[6]]].s = uconf.favcolor_sat;
hsv_edge[edge_map[ a[6]]].v = uconf.favcolor_val;
hsv_out[rgb_map[9 - a[6]]].h = uconf.favcolor_hue * 6;
hsv_out[rgb_map[9 - a[6]]].s = uconf.favcolor_sat;
hsv_out[rgb_map[9 - a[6]]].v = uconf.favcolor_val;
hsv_edge[edge_map[9 - a[6]]].h = uconf.favcolor_hue * 6;
hsv_edge[edge_map[9 - a[6]]].s = uconf.favcolor_sat;
hsv_edge[edge_map[9 - a[6]]].v = uconf.favcolor_val;
a[6]++;
if (a[6] >= 5) {
@ -418,13 +416,13 @@ void rgb_waving(uint8_t *a, uint16_t tick)
break;
}
case 3: { // moving up
hsv_out[rgb_map[4 - a[6]]].h = uconf.favcolor_hue * 6;
hsv_out[rgb_map[4 - a[6]]].s = uconf.favcolor_sat;
hsv_out[rgb_map[4 - a[6]]].v = uconf.favcolor_val;
hsv_edge[edge_map[4 - a[6]]].h = uconf.favcolor_hue * 6;
hsv_edge[edge_map[4 - a[6]]].s = uconf.favcolor_sat;
hsv_edge[edge_map[4 - a[6]]].v = uconf.favcolor_val;
hsv_out[rgb_map[5 + a[6]]].h = uconf.favcolor_hue * 6;
hsv_out[rgb_map[5 + a[6]]].s = uconf.favcolor_sat;
hsv_out[rgb_map[5 + a[6]]].v = uconf.favcolor_val;
hsv_edge[edge_map[5 + a[6]]].h = uconf.favcolor_hue * 6;
hsv_edge[edge_map[5 + a[6]]].s = uconf.favcolor_sat;
hsv_edge[edge_map[5 + a[6]]].v = uconf.favcolor_val;
a[6]++;
if (a[6] >= 5) {
@ -438,7 +436,7 @@ void rgb_waving(uint8_t *a, uint16_t tick)
}
}
void rgb_rainbow(uint8_t *a, uint16_t tick)
void edge_rainbow(uint8_t *a, uint16_t tick)
{
// 0=angle-rate, 1=bitfield, 2=timeout-set, 45=angle-work, 6=sat, 7=val
// bitfield:
@ -480,18 +478,18 @@ void rgb_rainbow(uint8_t *a, uint16_t tick)
}
// apply to LEDs
for (i = 0; i < RGBLED_COUNT; i++) {
r = (a[1] & 0x01) ? i : RGBLED_COUNT - 1 - i;
hsv_out[rgb_map[r]].h = angle;
hsv_out[rgb_map[r]].s = a[6];
hsv_out[rgb_map[r]].v = a[7];
for (i = 0; i < RGB_EDGE_COUNT; i++) {
r = (a[1] & 0x01) ? i : RGB_EDGE_COUNT - 1 - i;
hsv_edge[edge_map[r]].h = angle;
hsv_edge[edge_map[r]].s = a[6];
hsv_edge[edge_map[r]].v = a[7];
angle += hoffset;
if (angle >= 0x600) angle -= 0x600;
}
}
void rgb_copmode(uint8_t *a, uint16_t tick)
void edge_copmode(uint8_t *a, uint16_t tick)
{
// 0=work, 1=bitfield, 2=timeout-set, 3=timeout-work, 4=work, 56=steps, 7=val
// bitfield:
@ -663,40 +661,40 @@ void rgb_copmode(uint8_t *a, uint16_t tick)
a[0] = (pattern << 6) | (iter & 0x3f);
// apply to LEDs
w = RGBLED_COUNT/2;
w = RGB_EDGE_COUNT/2;
for (i = 0; i < w; i++) {
hsv_out[rgb_map[i]].h = hsv.h;
hsv_out[rgb_map[i]].s = hsv.s;
hsv_out[rgb_map[i]].v = hsv.v;
hsv_edge[edge_map[i]].h = hsv.h;
hsv_edge[edge_map[i]].s = hsv.s;
hsv_edge[edge_map[i]].v = hsv.v;
hsv_out[rgb_map[i+w]].h = hsv2.h;
hsv_out[rgb_map[i+w]].s = hsv2.s;
hsv_out[rgb_map[i+w]].v = hsv.v;
hsv_edge[edge_map[i+w]].h = hsv2.h;
hsv_edge[edge_map[i+w]].s = hsv2.s;
hsv_edge[edge_map[i+w]].v = hsv.v;
}
}
void rgb_fade_from_center(uint8_t *a, uint16_t tick)
void edge_fade_from_center(uint8_t *a, uint16_t tick)
{
}
void rgb_staticbar(uint8_t *a, uint16_t tick)
void edge_staticbar(uint8_t *a, uint16_t tick)
{
}
void rgb_gravitycheck(uint8_t *a, uint16_t tick)
void edge_gravitycheck(uint8_t *a, uint16_t tick)
{
}
// implemented program table
const LedProgram rgb_pgm[6] = {
{"Solid Color", rgb_solid},
{"Flicker", rgb_flicker},
{"Circles", rgb_circles},
{"Waving", rgb_waving},
{"Rainbow", rgb_rainbow},
{"Cop Mode", rgb_copmode},
const LedProgram edge_pgm[6] = {
{"Solid Color", edge_solid},
{"Flicker", edge_flicker},
{"Circles", edge_circles},
{"Waving", edge_waving},
{"Rainbow", edge_rainbow},
{"Cop Mode", edge_copmode},
};

View File

@ -34,24 +34,13 @@
#include "misc/accel.h"
#include "ui/menu.h"
#include "ui/oled.h"
#include "global.h"
#include "port_intr.h"
#include "user_config.h"
// global settings
#define OLED_UPDATE_RATE 64 // framerate of OLED; (256*0.75) / OLED_UPDATE_RATE
// flags
#define FLAG_OLED_UPDATE (1 << 0)
#define FLAG_RGBLED_RUN_PROG (1 << 1)
const uint8_t vers[] = "241015a";
const uint8_t vers[] = "241013.01";
uint8_t cpu_use = 0;
uint8_t cpu_max = 0;
@ -65,13 +54,6 @@ uint32_t idle_time_menu;
uint32_t idle_time_still;
uint8_t idle_go_sleep;
static volatile uint8_t flags = 0;
static uint8_t st_tick = 0; // systick loop counter
static uint8_t oled_tick = 0; // oled framerate counter
void ch59x_xtal_conf()
@ -80,91 +62,6 @@ void ch59x_xtal_conf()
HSECFG_Capacitance(HSECap_14p);
}
void systick_init()
{
}
void oled_update_done()
{
int16_t a;
int8_t rot;
// reset oled callback, clear screen, and set default pixel mode and font size
oled.callback = 0;
if (!(menu->flags & MENU_FLAG_NO_AUTOCLS)) {
ssd1306_cls(&oled);
}
ssd1306fb_set_color(SSD1306_STATE_SET_PIXEL);
oled.state &= ~SSD1306_STATE_STR_HALFWIDTH;
// orientation / flipping flags
rot = accel_get_rotation(&accel);
if ((rot > (96+4)) || (rot < (32-4))) {
sysflags &= ~SYS_OLED_ROTATE_X;
} else if ((rot > (32+4)) && (rot < (96-4))) {
sysflags |= SYS_OLED_ROTATE_X;
}
if ((rot > (64+4)) && (rot < 124)) {
sysflags &= ~SYS_OLED_ROTATE_Y;
} else if ((rot > 4) && (rot < (64-4))) {
sysflags |= SYS_OLED_ROTATE_Y;
}
if ((rot < 21) || (rot > (64 + 24))) {
sysflags &= ~SYS_OLED_REVERSE_CHARS;
} else if (rot > 24 && rot < (64 + 21)){
sysflags |= SYS_OLED_REVERSE_CHARS;
}
#ifdef MENU_TIMEOUT_TO_NAMETAG
// root menu idle counting
if (menu == &menu_0) {
if (!idle_time_menu) {
idle_time_menu = uptime;
} else if ((uptime - idle_time_menu) >= MENU_TIMEOUT_TO_NAMETAG) {
// been at the root menu too long.
// return to nametag
menu_stop(0);
idle_time_menu = 0;
}
} else {
idle_time_menu = 0;
}
#endif
// do menu operations
menu_tick();
// calculate CPU usage
// note: we just consider missed ticks a percent.
// it's actually more like a tenth. fuck it.
// a = missed;
// todo: implement this
a = 0;
if (uconf.framemod == UCONF_FRAMERATE_HALF) {
// the above calculation is tied to framerate.
// so this will compensate for half framerate mode...
a >>= 1;
}
if (a > cpu_max) {
cpu_max = a;
}
cpu_use = a;
// reset missed interrupt counter
// missed = 0;
}
int main()
{
// configure clock
@ -199,85 +96,13 @@ int main()
// configure port-based interrupts (used for ch32sub interrupt)
port_intr_init();
// note that system clock speed is decreased after every use of I2C.
// configure system tick
systick_init();
// note that system clock speed is decreased after every use of I2C
while(1) {
// sleep when we're doing nothing
__WFI();
// only care about aux MCU when all other processing is done
ch32sub_process();
// send the last oled frame data
if (flags & FLAG_OLED_UPDATE) {
flags &= ~FLAG_OLED_UPDATE;
/*** oled ***/
if (oled.callback && !(oled.state & SSD1306_STATE_BUSY)) {
if (ssd1306_cb_get()) {
oled.callback();
}
}
// update
// only update this frame if we're not in the middle of starting up
if (uptime) {
// process other tasks
if (oled.state & SSD1306_STATE_INITIALIZED) {
oled.callback = oled_update_done;
}
ssd1306_update();
}
}
// render new OLED frame
if (flags & FLAG_RGBLED_RUN_PROG) {
flags &= ~FLAG_RGBLED_RUN_PROG;
rgbled_runprog(st_tick);
}
}
}
void SysTick_Handler(void)
{
st_tick++;
if (!st_tick) {
uptime++;
uptime_hour = (uint16_t)(uptime / 3600);
uptime_min = (uint8_t)((uptime / 60) % 60);
uptime_sec = (uint8_t)((uptime ) % 60);
}
// render and update RGBLED at 64Hz
if ((st_tick & 0x3) == 0x3) {
// make sure a valid program is selected
if (uconf.ledprog_rgb_idx > (sizeof(rgb_pgm) / sizeof(rgb_pgm[0]))) {
uconf.ledprog_rgb_idx = 0;
}
// send any rendered data now
rgbled_send();
// defer rendering
flags |= FLAG_RGBLED_RUN_PROG;
}
// render and update the oled during non-rgbled frames
else {
oled_tick++;
if (oled_tick >= OLED_UPDATE_RATE) {
oled_tick = 0;
flags |= FLAG_OLED_UPDATE;
}
}
// read accelerometer data
if ((st_tick & 0x7) == 0x7) {
accel_poll();
// sleep when we're doing nothing
__WFI();
}
}

View File

@ -10,14 +10,12 @@
#include "hw/lis2dw12_reg.h"
#include "comm/i2c.h"
#include "misc/i8atan2.h"
#include <stdio.h>
// user data
AccelData accel;
AccelData accel_last[4];
AccelData accel_smoothing;
int16_t movement;
@ -68,54 +66,17 @@ void accel_init()
lis2dw12_reset_get(&dev_ctx, &reset);
} while (reset);
// disable block update
// data in output registers is updated immediately; FIFO is disabled
lis2dw12_block_data_update_set(&dev_ctx, PROPERTY_DISABLE);
// configure scale, power mode
lis2dw12_full_scale_set(&dev_ctx, LIS2DW12_2g);
lis2dw12_power_mode_set(&dev_ctx, LIS2DW12_CONT_LOW_PWR_LOW_NOISE_4);
// configure filter chain
// low pass filter enabled for 6D (not currently used)
lis2dw12_filter_path_set(&dev_ctx, LIS2DW12_LPF_ON_OUT);
// digital LPF2 filter of output data
lis2dw12_filter_bandwidth_set(&dev_ctx, LIS2DW12_ODR_DIV_4);
lis2dw12_power_mode_set(&dev_ctx, LIS2DW12_SINGLE_LOW_PWR_LOW_NOISE_4);
// configure output data rate
lis2dw12_data_rate_set(&dev_ctx, LIS2DW12_XL_ODR_200Hz);
lis2dw12_data_rate_set(&dev_ctx, LIS2DW12_XL_ODR_100Hz);
}
void accel_poll()
int8_t accel_get_rotation()
{
uint8_t reg = 1;
uint16_t xyz[3];
while (reg) {
// read output only if new value is available
lis2dw12_flag_data_ready_get(&dev_ctx, &reg);
if (reg) {
// read acceleration data
memset(xyz, 0x00, 3 * sizeof(int16_t));
lis2dw12_acceleration_raw_get(&dev_ctx, xyz);
}
}
}
int8_t accel_get_rotation(struct AccelData *a)
{
int8_t nx, ny, ret;
nx = -a->x;
ny = a->y;
ret = i8atan2(nx, ny) >> 1;
if (ret < 0) {
ret += 128;
}
return ret;
return 0;
}
int16_t accel_get_movement()

View File

@ -32,9 +32,8 @@ extern uint16_t movement_worst;
void accel_init();
void accel_poll();
int8_t accel_get_rotation(struct AccelData *a);
int8_t accel_get_rotation();
int16_t accel_get_movement();

View File

@ -125,7 +125,7 @@ void menu_none_disp(uint8_t idx)
top = oled.height - ssd1306fb_get_font_height(font_table[uconf.font_idx].font) - 1;
// get rotation
rot = accel_get_rotation(&accel);
rot = accel_get_rotation();
// render modes
switch (uconf.nameconf & UCONF_NAME_DISP_MASK) {
@ -233,7 +233,7 @@ MENU_0_DISP_CHAR_ROTATE:
ssd1306fb_set_target(&oled);
if (uconf.flags & UCONF_FLAGS_SHOW_ACCEL_ANGLE) {
sprintf(txt, "%+3d", accel_get_rotation(&accel));
sprintf(txt, "%+3d", accel_get_rotation());
ssd1306fb_set_cursor(90, 0);
ssd1306fb_draw_str(font_DejaVu_Sans_Mono_Bold_11, txt, 1);
}

View File

@ -60,7 +60,7 @@ void menu_2_btn_next(uint8_t idx)
uint8_t *x;
uint8_t *s;
s = uconf.ledprog_rgb_data[uconf.ledprog_rgb_idx];
s = uconf.ledprog_edge_data[uconf.ledprog_edge_idx];
x = &s[prog_data_idx >> 1];
if (prog_data_idx & 0x01) {
@ -107,7 +107,7 @@ void menu_2_btn_prev(uint8_t idx)
uint8_t *x;
uint8_t *s;
s = uconf.ledprog_rgb_data[uconf.ledprog_rgb_idx];
s = uconf.ledprog_edge_data[uconf.ledprog_edge_idx];
x = &s[prog_data_idx >> 1];
if (prog_data_idx & 0x01) {
@ -243,7 +243,7 @@ void menu_2_disp(uint8_t idx)
case 0: {
ssd1306fb_draw_str(font_table[0].font, "Edge Program", 1);
ssd1306fb_set_cursor(16, 15);
ssd1306fb_draw_str(font_table[0].font, rgb_pgm[uconf.ledprog_rgb_idx].name, 1);
ssd1306fb_draw_str(font_table[0].font, edge_pgm[uconf.ledprog_edge_idx].name, 1);
goto MENU_2_DRAW_TEXT_DONE;
}
@ -251,7 +251,7 @@ void menu_2_disp(uint8_t idx)
uint8_t *s;
sprintf(txt, "Edge");
s = uconf.ledprog_rgb_data[uconf.ledprog_rgb_idx];
s = uconf.ledprog_edge_data[uconf.ledprog_edge_idx];
if (edit_mode == MENU_BTNSTYLE_MENU) {
ssd1306fb_draw_str(font_table[0].font, txt, 1);
@ -401,10 +401,10 @@ void menu_2_enter(uint8_t idx)
switch (idx) {
case 0: {
a = (sizeof(rgb_pgm) / sizeof(rgb_pgm[0]));
uconf.ledprog_rgb_idx++;
if (uconf.ledprog_rgb_idx >= a) {
uconf.ledprog_rgb_idx = 0;
a = (sizeof(edge_pgm) / sizeof(edge_pgm[0]));
uconf.ledprog_edge_idx++;
if (uconf.ledprog_edge_idx >= a) {
uconf.ledprog_edge_idx = 0;
}
break;
}

View File

@ -64,12 +64,12 @@ void menu_5_disp(uint8_t idx)
}
case 4: {
// constantly save value at this screen
uconf.lsens_dark_thresh = lsens_get_dark_threshold();
uconf.lsens_lo_thresh = lsens_get_lo_threshold();
// ensure LEDs are disabled when calibrating
uconf.flags |= UCONF_FLAGS_LEDS_DISABLE;
ssd1306fb_draw_str(font_table[0].font, "Recal Lightsense DARK RM!", 0);
sprintf(txt, "%d", uconf.lsens_dark_thresh);
sprintf(txt, "%d", uconf.lsens_lo_thresh);
break;
}
case 5: {
@ -131,7 +131,7 @@ void menu_5_enter(uint8_t idx)
}
case 4: {
// reset sensor threshold to recal value
lsens_set_dark_threshold(0xffff);
lsens_set_lo_threshold(0xffff);
break;
}
case 5: {

View File

@ -80,10 +80,9 @@ void menu_6_font_prev(uint8_t idx)
*/
}
void menu_6_accel_reset(uint8_t idx)
void menu_6_accel_reset()
{
// todo: figure out what this does
// movement_worst = 0;
movement_worst = 0;
}
void menu_6_btn_use()
@ -148,9 +147,9 @@ void menu_6_disp(uint8_t idx)
for (i = 0; i < 4; i++) {
ssd1306fb_set_cursor(led_pos[i][0], led_pos[i][1]);
sprintf(txt, "R%d h%03X", i + 1, hsv_out[rgb_map[i + 0]].h);
sprintf(txt, "R%d h%03X", i + 1, hsv_edge[edge_map[i + 0]].h);
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 1);
sprintf(txt, "s%02X v%02X", hsv_out[rgb_map[i + 0]].s, hsv_out[rgb_map[i + 0]].v);
sprintf(txt, "s%02X v%02X", hsv_edge[edge_map[i + 0]].s, hsv_edge[edge_map[i + 0]].v);
oled.cursor_x = led_pos[i][0];
oled.cursor_y += 7;
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 1);
@ -165,9 +164,9 @@ void menu_6_disp(uint8_t idx)
for (i = 0; i < 4; i++) {
ssd1306fb_set_cursor(led_pos[i][0], led_pos[i][1]);
sprintf(txt, "R%d h%03X", i + 5, hsv_out[rgb_map[i + 4]].h);
sprintf(txt, "R%d h%03X", i + 5, hsv_edge[edge_map[i + 4]].h);
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 1);
sprintf(txt, "s%02X v%02X", hsv_out[rgb_map[i + 4]].s, hsv_out[rgb_map[i + 4]].v);
sprintf(txt, "s%02X v%02X", hsv_edge[edge_map[i + 4]].s, hsv_edge[edge_map[i + 4]].v);
oled.cursor_x = led_pos[i][0];
oled.cursor_y += 7;
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 1);
@ -182,9 +181,9 @@ void menu_6_disp(uint8_t idx)
for (i = 0; i < 4; i++) {
ssd1306fb_set_cursor(led_pos[i][0], led_pos[i][1]);
sprintf(txt, "R%d h%03X", i + 5, hsv_out[rgb_map[i + 8]].h);
sprintf(txt, "R%d h%03X", i + 5, hsv_edge[edge_map[i + 8]].h);
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 1);
sprintf(txt, "s%02X v%02X", hsv_out[rgb_map[i + 8]].s, hsv_out[rgb_map[i + 8]].v);
sprintf(txt, "s%02X v%02X", hsv_edge[edge_map[i + 8]].s, hsv_edge[edge_map[i + 8]].v);
oled.cursor_x = led_pos[i][0];
oled.cursor_y += 7;
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 1);
@ -207,7 +206,7 @@ void menu_6_disp(uint8_t idx)
sprintf(txt, "m%i", abs(accel_get_movement()));
ssd1306fb_set_cursor(104, 10);
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 0);
sprintf(txt, "w%d", 0); // todo: fix this: movement_worst);
sprintf(txt, "w%d", movement_worst);
ssd1306fb_set_cursor(106, 17);
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 0);
@ -237,21 +236,18 @@ void menu_6_disp(uint8_t idx)
ssd1306fb_set_cursor(10, -1);
ssd1306fb_draw_str(font_Dialog_plain_8, "Light: ", 1);
oled.cursor_x = 39;
sprintf(txt, "%d lo, %02d + %d", lsens_get_dark_threshold(), lsens_get_coarse(), lsens_get_fine());
sprintf(txt, "%d lo, %02d + %d", lsens_get_lo_threshold(), lsens_get_hi(), lsens_get_lo());
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 0);
ssd1306fb_set_cursor(10, 7);
ssd1306fb_draw_str(font_Dialog_plain_8, "Temp: Batt:", 1);
oled.cursor_x = 42;
// todo: implement temperature sensing
// sprintf(txt, "%d.%dC", temp_degc, temp_degc_decimal);
sprintf(txt, "%d.%dC", temp_degc, temp_degc_decimal);
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 0);
oled.cursor_x = 98;
// battery reading support is not supported on this target
// fill this area in with something else
// sprintf(txt, "%d.%02dV", batt_volt, batt_mv);
sprintf(txt, "%d.%02dV", batt_volt, batt_mv);
ssd1306fb_draw_str(font_Dialog_plain_8, txt, 0);
ssd1306fb_set_cursor(10, 16);

View File

@ -1,15 +0,0 @@
/*
* oled.c
*
* Created on: Oct 15, 2024
* Author: true
*/
#include "oled.h"
void oled_init()
{
}

View File

@ -1,19 +0,0 @@
/*
* oled.h
*
* Created on: Oct 15, 2024
* Author: true
*/
#ifndef USER_UI_OLED_H_
#define USER_UI_OLED_H_
#include "hw/ssd1306.h"
#include <stdint.h>
#endif /* USER_UI_OLED_H_ */

View File

@ -57,15 +57,15 @@ static void uconf_defaults()
uconf.altcolor_sat = 240;
uconf.altcolor_val = 32;
uconf.ledprog_rgb_idx = 4;
uconf.ledprog_edge_idx = 4;
for (i = 0; i < 8; i++) {
uconf.ledprog_rgb[i] = 0;
uconf.ledprog_edge[i] = 0;
}
memcpy(uconf.ledprog_rgb_data, uconf_edge_defaults, sizeof(uconf_edge_defaults));
memcpy(uconf.ledprog_edge_data, uconf_edge_defaults, sizeof(uconf_edge_defaults));
uconf.lsens_dark_thresh = 0x6a0; // todo: figure out what this should be by testing
uconf.lsens_lo_thresh = 0x6a0;
uconf.sleep_timeout = 20 * 60;
uconf.checksum = checksum_gen((uint8_t *)&uconf, sizeof(uconf) - 2);
@ -87,7 +87,7 @@ static int8_t uconf_validate()
}
// fix any mistakes
if (uconf.ledprog_rgb_idx > (sizeof(rgb_pgm) / sizeof(rgb_pgm[0]))) uconf.ledprog_rgb_idx = 0;
if (uconf.ledprog_edge_idx > (sizeof(edge_pgm) / sizeof(edge_pgm[0]))) uconf.ledprog_edge_idx = 0;
return 0;
}

View File

@ -73,12 +73,12 @@ typedef struct UserConf {
uint8_t altcolor_hue;
uint8_t altcolor_sat;
uint8_t altcolor_val; // 48
uint8_t ledprog_rgb_idx;
uint8_t padding0; // 50
uint8_t ledprog_rgb[16]; // 66
uint8_t ledprog_rgb_data[16][8]; // 194
uint8_t padding1[54]; // 248
uint16_t lsens_dark_thresh; // 250
uint8_t ledprog_edge_idx;
uint8_t ledprog_eyes_idx; // 50
uint8_t ledprog_edge[16]; // 66
uint8_t ledprog_edge_data[16][8]; // 194
uint8_t padding[54]; // 248
uint16_t lsens_lo_thresh; // 250
uint16_t sleep_timeout; // 252
uint16_t tempcx10_offset; // 253-254
uint16_t checksum; // 255-256