From f4430bb7f2bcef62e6563f9c436b9a24d4482532 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 7 Apr 2023 17:06:08 -0600 Subject: merging gchart's changes, part 1... + added Sofirn LT1S Pro + added Sofirn SC21 Pro + added Wurkkos TS10 + added Wurkkos TS25 * small changes to other models * improved dual voltage support + added attiny1616 flashing python script w/ pymcuprog These changes are incomplete. It does not yet include: - extended simple UI - t1616 WDT reset detection - gchart's OUTPUT_MUX code (I plan to rewrite the entire tint system) --- bin/flash-1616.py | 76 +++++++++++++ hwdef-Sofirn_LT1S-Pro.h | 114 ++++++++++++++++++++ hwdef-Wurkkos_TS10.h | 117 ++++++++++++++++++++ hwdef-Wurkkos_TS25.h | 119 +++++++++++++++++++++ spaghetti-monster/anduril/BRANDS | 1 + spaghetti-monster/anduril/MODELS | 4 + spaghetti-monster/anduril/aux-leds.c | 11 ++ .../anduril/cfg-mateminco-mt35-mini.h | 5 + spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.c | 22 ++++ spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 90 ++++++++++++++++ spaghetti-monster/anduril/cfg-sofirn-sc21-pro.h | 10 ++ spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h | 6 ++ spaghetti-monster/anduril/cfg-wurkkos-ts10.h | 82 ++++++++++++++ spaghetti-monster/anduril/cfg-wurkkos-ts25.h | 78 ++++++++++++++ 14 files changed, 735 insertions(+) create mode 100644 bin/flash-1616.py create mode 100644 hwdef-Sofirn_LT1S-Pro.h create mode 100644 hwdef-Wurkkos_TS10.h create mode 100644 hwdef-Wurkkos_TS25.h create mode 100644 spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.c create mode 100644 spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h create mode 100644 spaghetti-monster/anduril/cfg-sofirn-sc21-pro.h create mode 100644 spaghetti-monster/anduril/cfg-wurkkos-ts10.h create mode 100644 spaghetti-monster/anduril/cfg-wurkkos-ts25.h diff --git a/bin/flash-1616.py b/bin/flash-1616.py new file mode 100644 index 0000000..6b3e2ee --- /dev/null +++ b/bin/flash-1616.py @@ -0,0 +1,76 @@ +# Use with Python3, make sure to have the pymcuprog module installed (via pip) + +# Read out the pymcuprog version +from pymcuprog.version import VERSION as pymcuprog_version +print("pymcuprog version {}".format(pymcuprog_version)) + + +# List out the available ports +import serial.tools.list_ports as ls; +#ports = ls.comports() +ports = [] +for p in ls.comports(): + if "COM" in p.device or "USB" in p.device: + ports.append(p) + +if len(ports) == 0: + print("No serial ports found, exiting") + exit() +elif len(ports) == 1: + print("Found one serial port:", ports[0].device, "-", ports[0].description) + port = ports[0].device +else: # found more than one serial port + print("Found multiple serial ports:") + for p in ports: + print(" *", p.device, "-", p.description) + print("Which serial port would you like to use? (default: " + ports[0].device + ") ", end="") + port = input() + if not port: + port = ports[0].device + + +import sys +args = sys.argv +if len(args) == 1: # only the program name, no arguements: ask for the hex file + print("Which hex file would you like to flash? ", end="") + hexfile = input() +else: + hexfile = args[1] + + +# pymcuprog uses the Python logging module +import logging +logging.basicConfig(format="%(levelname)s: %(message)s", level=logging.WARNING) + +# Configure the session +from pymcuprog.backend import SessionConfig +sessionconfig = SessionConfig("attiny1616") + +# Instantiate Serial transport (only 1 tool connected) +from pymcuprog.toolconnection import ToolSerialConnection +transport = ToolSerialConnection(serialport=port) + +# Instantiate backend +from pymcuprog.backend import Backend +backend = Backend() + +# Connect to tool using transport +backend.connect_to_tool(transport) + +# Start the session +backend.start_session(sessionconfig) + +# Read the target device_id +device_id = backend.read_device_id() +print("Device ID is {0:06X}".format(int.from_bytes(device_id, byteorder="little"))) + +# Erase the device, write the hexfile, and verify the write +backend.erase() +print("Memories erased.") +print("Writing hex file to the device... ") +backend.write_hex_to_target(hexfile) +print("Writing complete.") +print("Verifying the write... ") +verify_status = backend.verify_hex(hexfile) +if verify_status is True: + print("Verification successful!") \ No newline at end of file diff --git a/hwdef-Sofirn_LT1S-Pro.h b/hwdef-Sofirn_LT1S-Pro.h new file mode 100644 index 0000000..ce6ee3a --- /dev/null +++ b/hwdef-Sofirn_LT1S-Pro.h @@ -0,0 +1,114 @@ +#ifndef HWDEF_SOFIRN_LT1S_PRO_H +#define HWDEF_SOFIRN_LT1S_PRO_H + +/* BLF LT1S Pro driver layout using the Attiny1616 + +Driver pinout: + * eSwitch: PA5 + * Aux LED: PB5 + * WW PWM: PB0 (TCA0 WO0) + * CW PWM: PB1 (TCA0 WO1) + * Red PWM: PB2 (TCA0 WO2) + * Voltage: VCC + +*/ + + +#define LAYOUT_DEFINED + +#ifdef ATTINY +#undef ATTINY +#endif +#define ATTINY 1616 +#include + +#define PWM_CHANNELS 1 + +#ifndef SWITCH_PIN +#define SWITCH_PIN PIN5_bp +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN2CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS +#endif + + +// usually PWM1_LVL would be a hardware register, but we need to abstract +// it out to a soft brightness value, in order to handle tint ramping +// (this allows smooth thermal regulation to work, and makes things +// otherwise simpler and easier) +uint8_t PWM1_LVL; + +// warm tint channel +#ifndef PWM1_PIN +#define PWM1_PIN PB0 // +#define TINT1_LVL TCA0.SINGLE.CMP0 // CMP1 is the output compare register for PB0 +#endif + +// cold tint channel +#ifndef PWM2_PIN +#define PWM2_PIN PB1 // +#define TINT2_LVL TCA0.SINGLE.CMP1 // CMP0 is the output compare register for PB1 +#endif + +// red channel +#ifndef PWM3_PIN +#define PWM3_PIN PB0 // +#define PWM3_LVL TCA0.SINGLE.CMP2 // CMP2 is the output compare register for PB2 +#endif + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + + +// lighted button +#ifndef AUXLED_PIN +#define AUXLED_PIN PIN5_bp +#define AUXLED_PORT PORTB +#endif + + +// with so many pins, doing this all with #ifdefs gets awkward... +// ... so just hardcode it in each hwdef file instead +inline void hwdef_setup() { + + // set up the system clock to run at 10 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + + //VPORTA.DIR = ...; + VPORTB.DIR = PIN0_bm | PIN1_bm | PIN2_bm | PIN5_bm; // Outputs: Aux LED and PWMs + //VPORTC.DIR = ...; + + // enable pullups on the unused pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + PORTA.PIN1CTRL = PORT_PULLUPEN_bm; + PORTA.PIN2CTRL = PORT_PULLUPEN_bm; + PORTA.PIN3CTRL = PORT_PULLUPEN_bm; + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch + PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // warm tint channel + //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // cold tint channel + //PORTB.PIN2CTRL = PORT_PULLUPEN_bm; // red LEDs + PORTB.PIN3CTRL = PORT_PULLUPEN_bm; + PORTB.PIN4CTRL = PORT_PULLUPEN_bm; + //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED + + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + + // set up the PWM + // TODO: add references to MCU documentation + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_CMP2EN_bm | TCA_SINGLE_WGMODE_DSBOTTOM_gc; + TCA0.SINGLE.PER = 255; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; +} + + +#endif diff --git a/hwdef-Wurkkos_TS10.h b/hwdef-Wurkkos_TS10.h new file mode 100644 index 0000000..6cfe050 --- /dev/null +++ b/hwdef-Wurkkos_TS10.h @@ -0,0 +1,117 @@ +#ifndef HWDEF_BLF_Q8_T1616_H +#define HWDEF_BLF_Q8_T1616_H + +/* BLF Q8 driver layout using the Attiny1616 + +Driver pinout: + * eSwitch: PA5 + * Aux LED: PB5 + * PWM FET: PB0 (TCA0 WO0) + * PWM 1x7135: PB1 (TCA0 WO1) + * Voltage: VCC + +*/ + + +#define LAYOUT_DEFINED + +#ifdef ATTINY +#undef ATTINY +#endif +#define ATTINY 1616 +#include + +#define PWM_CHANNELS 2 +#define PWM_BITS 16 +#define PWM_TOP 255 +#define USE_DYN_PWM + +#ifndef SWITCH_PIN +#define SWITCH_PIN PIN5_bp +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN2CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS +#endif + + +// 7135 channel +#ifndef PWM1_PIN +#define PWM1_PIN PB1 // +#define PWM1_LVL TCA0.SINGLE.CMP1BUF // CMP1 is the output compare register for PB1 +#endif + +// FET channel +#ifndef PWM2_PIN +#define PWM2_PIN PB0 // +#define PWM2_LVL TCA0.SINGLE.CMP0BUF // CMP0 is the output compare register for PB0 +#endif + +// PWM parameters of both channels are tied together because they share a counter +#define PWM1_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM +// not necessary when double-buffered "BUF" registers are used +#define PWM1_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment +#define PWM1_PHASE_RESET_OFF // force reset while shutting off +#define PWM1_PHASE_RESET_ON // force reset while turning on + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + + +// lighted button +#ifndef AUXLED_PIN +#define AUXLED_PIN PIN5_bp +#define AUXLED_PORT PORTB +#endif + + +// with so many pins, doing this all with #ifdefs gets awkward... +// ... so just hardcode it in each hwdef file instead +inline void hwdef_setup() { + + // set up the system clock to run at 10 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + + //VPORTA.DIR = ...; + VPORTB.DIR = PIN0_bm | PIN1_bm | PIN5_bm; // Outputs: Aux LED and PWMs + //VPORTC.DIR = ...; + + // enable pullups on the unused pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + PORTA.PIN1CTRL = PORT_PULLUPEN_bm; + PORTA.PIN2CTRL = PORT_PULLUPEN_bm; + PORTA.PIN3CTRL = PORT_PULLUPEN_bm; + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch + PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // FET channel + //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // 7135 channel + PORTB.PIN2CTRL = PORT_PULLUPEN_bm; + PORTB.PIN3CTRL = PORT_PULLUPEN_bm; + PORTB.PIN4CTRL = PORT_PULLUPEN_bm; + //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED + + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + + // set up the PWM + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf + // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm + // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm + // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm + // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc + // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc + // See the manual for other pins, clocks, configs, portmux, etc + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_WGMODE_DSBOTTOM_gc; + PWM1_TOP = PWM_TOP; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; +} + + +#endif diff --git a/hwdef-Wurkkos_TS25.h b/hwdef-Wurkkos_TS25.h new file mode 100644 index 0000000..cadd366 --- /dev/null +++ b/hwdef-Wurkkos_TS25.h @@ -0,0 +1,119 @@ +#ifndef HWDEF_WURKKOS_TS25_T1616_H +#define HWDEF_WURKKOS_TS25_T1616_H + +/* BLF Q8 driver layout using the Attiny1616 + +Driver pinout: + * eSwitch: PA5 + * PWM FET: PB0 (TCA0 WO0) + * PWM 1x7135: PB1 (TCA0 WO1) + * Voltage: VCC + * Aux Blue: PC1 + * Aux Red: PC2 + * Aux Green: PC3 + +*/ + + +#define LAYOUT_DEFINED + +#ifdef ATTINY +#undef ATTINY +#endif +#define ATTINY 1616 +#include + +#define PWM_CHANNELS 2 +#define PWM_BITS 16 +#define PWM_TOP 255 +#define USE_DYN_PWM + +#ifndef SWITCH_PIN +#define SWITCH_PIN PIN5_bp +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN2CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS +#endif + + +// 7135 channel +#ifndef PWM1_PIN +#define PWM1_PIN PB1 // +#define PWM1_LVL TCA0.SINGLE.CMP1BUF // CMP1 is the output compare register for PB1 +#endif + +// FET channel +#ifndef PWM2_PIN +#define PWM2_PIN PB0 // +#define PWM2_LVL TCA0.SINGLE.CMP0BUF // CMP0 is the output compare register for PB0 +#endif + +// PWM parameters of both channels are tied together because they share a counter +#define PWM1_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM +// not necessary when double-buffered "BUF" registers are used +#define PWM1_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment +#define PWM1_PHASE_RESET_OFF // force reset while shutting off +#define PWM1_PHASE_RESET_ON // force reset while turning on + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + + +// this driver allows for aux LEDs under the optic +#define AUXLED_B_PIN PIN1_bp // pin 1 +#define AUXLED_R_PIN PIN2_bp // pin 2 +#define AUXLED_G_PIN PIN3_bp // pin 3 +#define AUXLED_RGB_PORT PORTC // PORTA or PORTB or PORTC + + +// with so many pins, doing this all with #ifdefs gets awkward... +// ... so just hardcode it in each hwdef file instead +inline void hwdef_setup() { + + // set up the system clock to run at 10 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + + //VPORTA.DIR = ...; + VPORTB.DIR = PIN0_bm | PIN1_bm; // Outputs: PWMs + VPORTC.DIR = PIN1_bm | PIN2_bm | PIN3_bm; + + // enable pullups on the unused pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + PORTA.PIN1CTRL = PORT_PULLUPEN_bm; + PORTA.PIN2CTRL = PORT_PULLUPEN_bm; + PORTA.PIN3CTRL = PORT_PULLUPEN_bm; + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch + PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // FET channel + //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // 7135 channel + PORTB.PIN2CTRL = PORT_PULLUPEN_bm; + PORTB.PIN3CTRL = PORT_PULLUPEN_bm; + PORTB.PIN4CTRL = PORT_PULLUPEN_bm; + PORTB.PIN5CTRL = PORT_PULLUPEN_bm; + + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; + //PORTC.PIN1CTRL = PORT_PULLUPEN_bm; // RGB Aux + //PORTC.PIN2CTRL = PORT_PULLUPEN_bm; // RGB Aux + //PORTC.PIN3CTRL = PORT_PULLUPEN_bm; // RGB Aux + + // set up the PWM + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf + // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm + // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm + // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm + // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc + // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc + // See the manual for other pins, clocks, configs, portmux, etc + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_WGMODE_DSBOTTOM_gc; + PWM1_TOP = PWM_TOP; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; +} + + +#endif diff --git a/spaghetti-monster/anduril/BRANDS b/spaghetti-monster/anduril/BRANDS index 4e73002..059f311 100644 --- a/spaghetti-monster/anduril/BRANDS +++ b/spaghetti-monster/anduril/BRANDS @@ -7,4 +7,5 @@ Lumintop 0300 - 0399 Fireflies 0400 - 0499 Mateminco 0500 - 0599 Sofirn 0600 - 0699 +Wurkkos 0700 - 0799 gChart 1600 - 1699 diff --git a/spaghetti-monster/anduril/MODELS b/spaghetti-monster/anduril/MODELS index 3071b60..dfe1190 100644 --- a/spaghetti-monster/anduril/MODELS +++ b/spaghetti-monster/anduril/MODELS @@ -59,7 +59,11 @@ Model Name MCU 0614 sofirn-sp36-t1616 attiny1616 0621 blf-lantern attiny85 0622 blf-lantern-t1616 attiny1616 +0623 sofirn-lt1s-pro attiny1616 0631 sofirn-sp10-pro attiny1616 +0632 sofirn-sc21-pro attiny1616 +0714 wurkkos-ts10 attiny1616 +0715 wurkkos-ts25 attiny1616 1618 gchart-fet1-t1616 attiny1616 Duplicates: diff --git a/spaghetti-monster/anduril/aux-leds.c b/spaghetti-monster/anduril/aux-leds.c index a3b905e..bb184f9 100644 --- a/spaghetti-monster/anduril/aux-leds.c +++ b/spaghetti-monster/anduril/aux-leds.c @@ -27,14 +27,21 @@ void indicator_led_update(uint8_t mode, uint8_t tick) { //uint8_t volts = voltage; // save a few bytes by caching volatile value // turn off when battery is too low + #ifdef DUAL_VOLTAGE_FLOOR + if (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) + || (voltage < DUAL_VOLTAGE_LOW_LOW)) { + #else if (voltage < VOLTAGE_LOW) { + #endif indicator_led(0); } //#ifdef USE_INDICATOR_LOW_BAT_WARNING + #ifndef DUAL_VOLTAGE_FLOOR // this isn't set up for dual-voltage lights like the Sofirn SP10 Pro // fast blink a warning when battery is low but not critical else if (voltage < VOLTAGE_RED) { indicator_led(mode & (((tick & 0b0010)>>1) - 3)); } + #endif //#endif // normal steady output, 0/1/2 = off / low / high else if ((mode & 0b00001111) < 3) { @@ -96,7 +103,11 @@ void rgb_led_update(uint8_t mode, uint8_t arg) { // turn off aux LEDs when battery is empty // (but if voltage==0, that means we just booted and don't know yet) uint8_t volts = voltage; // save a few bytes by caching volatile value + #ifdef DUAL_VOLTAGE_FLOOR + if ((volts) && (((voltage < VOLTAGE_LOW) && (voltage > DUAL_VOLTAGE_FLOOR)) || (voltage < DUAL_VOLTAGE_LOW_LOW))) { + #else if ((volts) && (volts < VOLTAGE_LOW)) { + #endif rgb_led_set(0); #ifdef USE_BUTTON_LED button_led_set(0); diff --git a/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h b/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h index c5b40e2..d7264a2 100644 --- a/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h +++ b/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h @@ -51,4 +51,9 @@ #define USE_SIMPLE_UI_RAMPING_TOGGLE // too big, turn off extra features +//#undef USE_SOS_MODE +//#undef USE_RAMP_AFTER_MOON_CONFIG +//#undef USE_RAMP_SPEED_CONFIG +//#undef USE_VOLTAGE_CORRECTION +//#undef USE_2C_STYLE_CONFIG #undef USE_TACTICAL_MODE diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.c b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.c new file mode 100644 index 0000000..571bbdc --- /dev/null +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.c @@ -0,0 +1,22 @@ +// this is inserted into fsm-ramping.c :: set_level() +// (it overrides part of the function, but not all of it) +uint8_t output_mux; // pre-define this variable since the overrides file gets included before the ramp-mode.h file +inline void set_level_override(uint8_t level) { + if (level == 0) { // off + TINT1_LVL = 0; // disable the first white channel + TINT2_LVL = 0; // disable the second white channel + PWM3_LVL = 0; // disable the red LEDs + } else { + level --; + + if (output_mux == 0) { // main white LEDs + PWM3_LVL = 0; // disable the red LEDs + PWM1_LVL = PWM_GET(pwm1_levels, level); // get the PWM value + update_tint(); // set the warm-cool level balance + } else { // red LEDs + TINT1_LVL = 0; // disable the first white channel + TINT2_LVL = 0; // disable the second white channel + PWM3_LVL = PWM_GET(pwm1_levels, level); // set the red LED PWM + } + } +} \ No newline at end of file diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h new file mode 100644 index 0000000..4e5993b --- /dev/null +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -0,0 +1,90 @@ +// Sofirn LT1S Pro +#define MODEL_NUMBER "0623" +#include "hwdef-Sofirn_LT1S-Pro.h" +// ATTINY: 1616 +// this model requires some special code +#define OVERRIDES_FILE cfg-sofirn-lt1s-pro.c +#define OVERRIDE_SET_LEVEL +inline void set_level_override(uint8_t level); + +// uses 4C action while On to switch between white and red channels (overrides lockout action) +#define USE_OUTPUT_MUX + +// the button lights up +#define USE_INDICATOR_LED +// the button is visible while main LEDs are on +#define USE_INDICATOR_LED_WHILE_RAMPING +// off mode: high (1) +// lockout: blinking (3) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) + +// the lantern has two PWM channels, but they drive different sets of emitters +// (one channel for warm emitters, one channel for cold) +// so enable a special ramping mode which changes tint instead of brightness +#define USE_TINT_RAMPING +// how much to increase total brightness at middle tint +// (0 = 100% brightness, 64 = 200% brightness) +#define TINT_RAMPING_CORRECTION 10 // 115% + +#ifdef RAMP_LENGTH +#undef RAMP_LENGTH +#endif + +// level_calc.py 1 150 7135 1 30 800 +#define RAMP_LENGTH 150 +#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,11,11,12,13,13,14,15,15,16,17,18,18,19,20,21,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,43,44,45,46,48,49,50,51,53,54,56,57,58,60,61,63,64,66,67,69,70,72,74,75,77,79,80,82,84,85,87,89,91,93,95,97,98,100,102,104,106,108,111,113,115,117,119,121,124,126,128,130,133,135,137,140,142,145,147,150,152,155,157,160,163,165,168,171,173,176,179,182,185,188,190,193,196,199,202,205,209,212,215,218,221,224,228,231,234,238,241,245,248,251,255 +#define MAX_1x7135 65 +#define HALFSPEED_LEVEL 256 // red LEDs use a QX7138 chip which has max PWM speed of 10 kHz, so never run faster than halfspeed +#define QUARTERSPEED_LEVEL 5 + +// the default of 26 looks a bit flat, so increase it +#define CANDLE_AMPLITUDE 40 + +// override default ramp style +#undef RAMP_STYLE +#define RAMP_STYLE 1 // 0 = smooth, 1 = stepped +// set floor and ceiling as far apart as possible +// because this lantern isn't overpowered +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 150 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 5 + +// LT1S can handle heat well, so don't limit simple mode +#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR +#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL +#define SIMPLE_UI_STEPS RAMP_DISCRETE_STEPS + +// Allow 3C in Simple UI for switching between smooth and stepped ramping +#define USE_SIMPLE_UI_RAMPING_TOGGLE + +// allow Aux Config and Strobe Modes in Simple UI +#define USE_EXTENDED_SIMPLE_UI + +// enable 2 click turbo (Anduril 1 style) +#define DEFAULT_2C_STYLE 1 + +#define USE_SOS_MODE +#define USE_SOS_MODE_IN_BLINKY_GROUP + +// the sensor (attiny) is nowhere near the emitters +// so thermal regulation can't work +#ifdef USE_THERMAL_REGULATION +#undef USE_THERMAL_REGULATION +#endif + +// don't blink while ramping +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif +#ifdef BLINK_AT_RAMP_FLOOR +#undef BLINK_AT_RAMP_FLOOR +#endif +#ifdef BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_CEIL +#endif + +#ifndef USE_SOFT_FACTORY_RESET +#define USE_SOFT_FACTORY_RESET +#endif \ No newline at end of file diff --git a/spaghetti-monster/anduril/cfg-sofirn-sc21-pro.h b/spaghetti-monster/anduril/cfg-sofirn-sc21-pro.h new file mode 100644 index 0000000..cee8172 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-sofirn-sc21-pro.h @@ -0,0 +1,10 @@ +// Sofirn SC21 Pro - same setup as a Wurkkos TS10, but with the aux indicator on while ramping +#include "cfg-wurkkos-ts10.h" +#undef MODEL_NUMBER +#define MODEL_NUMBER "0632" +// ATTINY: 1616 + +// turn on the aux LED while main LED is on +#ifndef USE_INDICATOR_LED_WHILE_RAMPING +#define USE_INDICATOR_LED_WHILE_RAMPING +#endif diff --git a/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h b/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h index bcfc80e..c1f1ed8 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h @@ -3,7 +3,13 @@ #include "hwdef-Sofirn_SP10-Pro.h" // ATTINY: 1616 +// don't blink during the ramp or at the ceiling +#ifdef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_MIDDLE +#endif +#ifdef BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_CEIL +#endif #define USE_DYNAMIC_UNDERCLOCKING diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts10.h b/spaghetti-monster/anduril/cfg-wurkkos-ts10.h new file mode 100644 index 0000000..6f92abf --- /dev/null +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts10.h @@ -0,0 +1,82 @@ +// Wurkkos TS10 (originally used Sofirn SP36-t1616 firmware) config options for Anduril using the Attiny1616 +// same as the BLF Q8 T1616, mostly (added Dynamic PWM) +#define MODEL_NUMBER "0714" +#include "hwdef-Wurkkos_TS10.h" +// ATTINY: 1616 + +// uses forward-facing aux LEDs +#define USE_INDICATOR_LED +// don't turn on the aux LEDs while main LEDs are on +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif +// the high button LED mode on this light uses too much power, default to low +// off mode: low (1) +// lockout: blinking (3) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) + +// voltage readings were a little high with the Q8 value +#undef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V, not 0.35V + +/* +// copied from Emisar D4 ramp +// ../../bin/level_calc.py 1 65 7135 1 0.8 150 +// ... mixed with this: +// ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 +#define RAMP_LENGTH 150 +#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 +#define MAX_1x7135 65 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 5 +*/ +// level 1 by hand, for the rest +// level_calc.py 7.01 2 149 7135 3 0.5 125 FET 1 10 1200 --pwm dyn:63:2048:255 +#define RAMP_LENGTH 150 +#define USE_DYN_PWM +#define PWM1_LEVELS 1,3,3,4,5,6,7,8,9,10,12,13,14,16,17,19,20,22,24,25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,64,67,70,72,75,77,80,82,85,87,89,91,93,95,96,98,99,100,100,101,100,100,99,97,95,93,90,86,82,87,91,96,100,106,111,116,122,128,134,141,147,155,162,169,177,186,194,203,213,222,232,243,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,6,7,9,11,12,14,16,18,20,22,24,27,29,31,34,37,39,42,45,48,51,54,57,61,64,68,72,75,79,83,88,92,97,101,106,111,116,121,126,132,138,144,150,156,162,169,176,183,190,197,205,213,221,229,237,246,255 +#define PWM_TOPS 2047,2047,1198,1322,1584,1676,1701,1691,1662,1622,1774,1703,1631,1692,1613,1639,1558,1564,1559,1478,1464,1444,1420,1392,1361,1329,1331,1293,1256,1246,1207,1192,1152,1133,1094,1074,1035,1013,991,954,932,897,875,842,820,790,760,731,704,678,646,622,593,566,534,510,478,452,423,393,364,338,310,280,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#define MAX_1x7135 90 +#define HALFSPEED_LEVEL 2 +#define QUARTERSPEED_LEVEL 2 + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 120 +// 10 28 46 [65] 83 101 120 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 + +// at Wurkkos's request, reduce the Simple UI ceiling a little bit +#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR +#define SIMPLE_UI_CEIL 144 +#define SIMPLE_UI_STEPS 5 + +// enable 2 click turbo (Anduril 1 style) +#define DEFAULT_2C_STYLE 1 + +// enable SOS in the blinkies group +#define USE_SOS_MODE +#define USE_SOS_MODE_IN_BLINKY_GROUP + +// Allow 3C in Simple UI for switching between smooth and stepped ramping +#define USE_SIMPLE_UI_RAMPING_TOGGLE + +// allow Aux Config and Strobe Modes in Simple UI +#define USE_EXTENDED_SIMPLE_UI + +// enable factory reset on 13H without loosening tailcap +#define USE_SOFT_FACTORY_RESET + +// stop panicking at ~55% power +#define THERM_FASTER_LEVEL 130 // throttle back faster when high + +// don't blink during the ramp or at the ceiling +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif +#ifdef BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_CEIL +#endif \ No newline at end of file diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts25.h b/spaghetti-monster/anduril/cfg-wurkkos-ts25.h new file mode 100644 index 0000000..a339cdb --- /dev/null +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts25.h @@ -0,0 +1,78 @@ +// Wurkkos TS25, modelled after the TS10 but with RGB Aux +#define MODEL_NUMBER "0715" +#include "hwdef-Wurkkos_TS25.h" +// ATTINY: 1616 + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + +// don't turn on the aux LEDs while main LEDs are on +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif + +// voltage readings were a little high with the Q8 value +#undef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V, not 0.35V + +/* +// copied from Emisar D4 ramp +// ../../bin/level_calc.py 1 65 7135 1 0.8 150 +// ... mixed with this: +// ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 +#define RAMP_LENGTH 150 +#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 +#define MAX_1x7135 65 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 5 +*/ +// level 1 by hand, for the rest +// level_calc.py 7.01 2 149 7135 3 0.5 125 FET 1 10 1200 --pwm dyn:63:2048:255 +#define RAMP_LENGTH 150 +#define USE_DYN_PWM +#define PWM1_LEVELS 1,3,3,4,5,6,7,8,9,10,12,13,14,16,17,19,20,22,24,25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,64,67,70,72,75,77,80,82,85,87,89,91,93,95,96,98,99,100,100,101,100,100,99,97,95,93,90,86,82,87,91,96,100,106,111,116,122,128,134,141,147,155,162,169,177,186,194,203,213,222,232,243,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,6,7,9,11,12,14,16,18,20,22,24,27,29,31,34,37,39,42,45,48,51,54,57,61,64,68,72,75,79,83,88,92,97,101,106,111,116,121,126,132,138,144,150,156,162,169,176,183,190,197,205,213,221,229,237,246,255 +#define PWM_TOPS 2047,2047,1198,1322,1584,1676,1701,1691,1662,1622,1774,1703,1631,1692,1613,1639,1558,1564,1559,1478,1464,1444,1420,1392,1361,1329,1331,1293,1256,1246,1207,1192,1152,1133,1094,1074,1035,1013,991,954,932,897,875,842,820,790,760,731,704,678,646,622,593,566,534,510,478,452,423,393,364,338,310,280,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#define MAX_1x7135 90 +#define HALFSPEED_LEVEL 2 +#define QUARTERSPEED_LEVEL 2 + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 120 +// 10 28 46 [65] 83 101 120 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 + +// at Wurkkos's request, reduce the Simple UI ceiling a little bit +#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR +#define SIMPLE_UI_CEIL 135 +#define SIMPLE_UI_STEPS 5 + +// enable 2 click turbo (Anduril 1 style) +#define DEFAULT_2C_STYLE 1 + +// enable SOS in the blinkies group +#define USE_SOS_MODE +#define USE_SOS_MODE_IN_BLINKY_GROUP + +// Allow 3C in Simple UI for switching between smooth and stepped ramping +#define USE_SIMPLE_UI_RAMPING_TOGGLE + +// allow Aux Config and Strobe Modes in Simple UI +#define USE_EXTENDED_SIMPLE_UI + +// enable factory reset on 13H without loosening tailcap +#define USE_SOFT_FACTORY_RESET + +// stop panicking at ~55% power +#define THERM_FASTER_LEVEL 130 // throttle back faster when high + +// don't blink during the ramp or at the ceiling +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif +#ifdef BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_CEIL +#endif \ No newline at end of file -- cgit v1.2.3 From 55541be4a505da3df7d1a2b8bf3b5295b0af58f7 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 13 Apr 2023 20:38:25 -0600 Subject: refactor progress checkpoint ... got Sofirn LT1S Pro and Emisar D4v2 working with the new channel mode system ... but there's a lot more left to do --- hwdef-Emisar_D4v2.h | 97 +++-- hwdef-Sofirn_LT1S-Pro.c | 67 ++++ hwdef-Sofirn_LT1S-Pro.h | 109 ++++-- spaghetti-monster/anduril/anduril.c | 39 +- spaghetti-monster/anduril/build-all.sh | 4 +- spaghetti-monster/anduril/candle-mode.c | 2 +- spaghetti-monster/anduril/cfg-emisar-d4v2-219.h | 13 +- spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h | 23 +- spaghetti-monster/anduril/cfg-emisar-d4v2.h | 21 +- spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 41 +-- spaghetti-monster/anduril/channel-modes.c | 146 ++++++++ spaghetti-monster/anduril/channel-modes.h | 20 + spaghetti-monster/anduril/factory-reset.c | 50 +-- spaghetti-monster/anduril/factory-reset.h | 26 +- spaghetti-monster/anduril/hank-cfg.h | 7 +- spaghetti-monster/anduril/load-save-config-fsm.h | 30 +- spaghetti-monster/anduril/load-save-config.c | 44 ++- spaghetti-monster/anduril/off-mode.c | 10 +- spaghetti-monster/anduril/ramp-mode.c | 55 ++- spaghetti-monster/anduril/ramp-mode.h | 15 + spaghetti-monster/anduril/strobe-modes.c | 30 +- spaghetti-monster/anduril/strobe-modes.h | 7 + spaghetti-monster/anduril/tint-ramping.c | 23 +- spaghetti-monster/anduril/tint-ramping.h | 22 +- spaghetti-monster/fsm-main.c | 1 + spaghetti-monster/fsm-misc.h | 5 + spaghetti-monster/fsm-ramping.c | 422 ++++++++++++++-------- spaghetti-monster/fsm-ramping.h | 196 +++++----- spaghetti-monster/fsm-states.h | 2 +- 29 files changed, 1019 insertions(+), 508 deletions(-) create mode 100644 hwdef-Sofirn_LT1S-Pro.c create mode 100644 spaghetti-monster/anduril/channel-modes.c create mode 100644 spaghetti-monster/anduril/channel-modes.h diff --git a/hwdef-Emisar_D4v2.h b/hwdef-Emisar_D4v2.h index e118ed5..51e30f8 100644 --- a/hwdef-Emisar_D4v2.h +++ b/hwdef-Emisar_D4v2.h @@ -1,7 +1,8 @@ -#ifndef HWDEF_EMISAR_D4V2_H -#define HWDEF_EMISAR_D4V2_H +#pragma once -/* Emisar D4v2 driver layout (attiny1634) +/* hwdef for Emisar D4v2 (attiny1634) + * Copyright (C) 2019 Selene ToyKeeper + * SPDX-License-Identifier: GPL-3.0-or-later * * Pin / Name / Function * 1 PA6 FET PWM (PWM1B) @@ -33,6 +34,16 @@ #define ATTINY 1634 #include +// TODO: add aux red and aux blue as disabled channel modes, +// so they can be used for the police strobe? +#define NUM_CHANNEL_MODES 1 +#define DEFAULT_CHANNEL_MODE 0 +#define SET_LEVEL_MODES set_level_2ch_stacked +#define GRADUAL_TICK_MODES gradual_tick_2ch_stacked +// no special handlers needed, can use common handlers +#define USE_SET_LEVEL_2CH_STACKED +#define USE_GRADUAL_TICK_2CH_STACKED + #define PWM_CHANNELS 2 #define SWITCH_PIN PA2 // pin 5 @@ -41,12 +52,17 @@ #define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] #define SWITCH_PORT PINA // PINA or PINB or PINC -#define PWM1_PIN PB3 // pin 16, 1x7135 PWM -#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 +#define LOW_PWM_PIN PB3 // pin 16, 1x7135 PWM +#define LOW_PWM_LVL OCR1A // OCR1A is the output compare register for PB3 +#define PWM1_BITS 8 -#define PWM2_PIN PA6 // pin 1, FET PWM -#define PWM2_LVL OCR1B // OCR1B is the output compare register for PB1 +#define HIGH_PWM_PIN PA6 // pin 1, FET PWM +#define HIGH_PWM_LVL OCR1B // OCR1B is the output compare register for PB1 +#define PWM2_BITS 8 +// only using 8-bit on this light +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t #define ADC_PRSCL 0x07 // clk/128 @@ -68,37 +84,46 @@ #define BUTTON_LED_DDR DDRA // for all "PA" pins #define BUTTON_LED_PUE PUEA // for all "PA" pins -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS +// it also has an independent LED in the button +#define USE_BUTTON_LED +// the aux LEDs are front-facing, so turn them off while main LEDs are on +// TODO: the whole "indicator LED" thing needs to be refactored into +// "aux LED(s)" and "button LED(s)" since they work a bit differently +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif + inline void hwdef_setup() { - // enable output ports - // 7135 - DDRB = (1 << PWM1_PIN); - // FET, aux R/G/B, button LED - DDRA = (1 << PWM2_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - | (1 << BUTTON_LED_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - TCCR1A = (0< +// channel modes: +// * 0. warm/cool white blend +// * 1. auto 3ch blend (red -> warm -> cool by ramp level) +// * 2. red only +// * 3. red + white blend +#define NUM_CHANNEL_MODES 4 +//#define CHANNEL_MODES_ENABLED 1,1,1,1 +#define CHANNEL_MODES_ENABLED 0b00001111 +#define CM_WHITE 0 +#define CM_AUTO 1 +#define CM_RED 2 +#define CM_WHITE_RED 3 + +// TODO: blend mode should enable this automatically? +#define USE_CHANNEL_MODES +// TODO: blend mode should enable this automatically? +#define USE_CHANNEL_MODE_ARGS +// TODO: or maybe if args are defined, the USE_ should be auto-set? +#define CHANNEL_MODE_ARGS 128,0,0,255 +#define SET_LEVEL_MODES set_level_2ch_blend, \ + set_level_auto_3ch_blend, \ + set_level_1ch, \ + set_level_red_white_blend +// TODO: gradual ticking for thermal regulation +#define GRADUAL_TICK_MODES gradual_tick_2ch_blend, \ + gradual_tick_auto_3ch_blend, \ + gradual_tick_1ch, \ + gradual_tick_red_white_blend +// can use some of the common handlers +#define USE_SET_LEVEL_2CH_BLEND +//#define USE_SET_LEVEL_AUTO_3CH_BLEND +#define USE_SET_LEVEL_1CH +//#define USE_SET_LEVEL_RED_WHITE_BLEND +// TODO: +//#define USE_GRADUAL_TICK_2CH_BLEND +//#define USE_GRADUAL_TICK_AUTO_3CH_BLEND +//#define USE_GRADUAL_TICK_1CH +//#define USE_GRADUAL_TICK_RED_WHITE_BLEND + +#define DEFAULT_CHANNEL_MODE CM_AUTO + +#define FACTORY_RESET_WARN_CHANNEL CM_RED +#define FACTORY_RESET_SUCCESS_CHANNEL CM_WHITE + +#define POLICE_COLOR_STROBE_CH1 CM_RED +#define POLICE_COLOR_STROBE_CH2 CM_WHITE + +// TODO: remove this as soon as it's not needed #define PWM_CHANNELS 1 -#ifndef SWITCH_PIN #define SWITCH_PIN PIN5_bp #define SWITCH_PORT VPORTA.IN #define SWITCH_ISC_REG PORTA.PIN2CTRL #define SWITCH_VECT PORTA_PORT_vect #define SWITCH_INTFLG VPORTA.INTFLAGS -#endif - -// usually PWM1_LVL would be a hardware register, but we need to abstract -// it out to a soft brightness value, in order to handle tint ramping -// (this allows smooth thermal regulation to work, and makes things -// otherwise simpler and easier) -uint8_t PWM1_LVL; // warm tint channel -#ifndef PWM1_PIN -#define PWM1_PIN PB0 // -#define TINT1_LVL TCA0.SINGLE.CMP0 // CMP1 is the output compare register for PB0 -#endif +#define WARM_PWM_PIN PB0 +#define WARM_PWM_LVL TCA0.SINGLE.CMP0 // CMP1 is the output compare register for PB0 // cold tint channel -#ifndef PWM2_PIN -#define PWM2_PIN PB1 // -#define TINT2_LVL TCA0.SINGLE.CMP1 // CMP0 is the output compare register for PB1 -#endif +#define COOL_PWM_PIN PB1 +#define COOL_PWM_LVL TCA0.SINGLE.CMP1 // CMP0 is the output compare register for PB1 // red channel -#ifndef PWM3_PIN -#define PWM3_PIN PB0 // -#define PWM3_LVL TCA0.SINGLE.CMP2 // CMP2 is the output compare register for PB2 -#endif +#define RED_PWM_PIN PB0 // +#define RED_PWM_LVL TCA0.SINGLE.CMP2 // CMP2 is the output compare register for PB2 + +// translate cfg names to FSM names +#define LOW_PWM_LEVELS RED_PWM_LEVELS +#define LOW_PWM_LVL RED_PWM_LVL +#define LOW_PWM_PIN RED_PWM_PIN + +// only using 8-bit on this light +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define BLEND_PWM_DATATYPE uint8_t + // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR @@ -64,14 +108,20 @@ uint8_t PWM1_LVL; // lighted button -#ifndef AUXLED_PIN #define AUXLED_PIN PIN5_bp #define AUXLED_PORT PORTB -#endif + +// the button lights up +#define USE_INDICATOR_LED +// the button is visible while main LEDs are on +#define USE_INDICATOR_LED_WHILE_RAMPING + + +// custom channel modes +void set_level_auto_3ch_blend(uint8_t level); +void set_level_red_white_blend(uint8_t level); -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead inline void hwdef_setup() { // set up the system clock to run at 10 MHz instead of the default 3.33 MHz @@ -111,4 +161,5 @@ inline void hwdef_setup() { } -#endif +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 47cd00f..07560bc 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -54,10 +54,10 @@ /********* specific settings for known driver types *********/ // Anduril config file name (set it here or define it at the gcc command line) -//#define CONFIGFILE cfg-blf-q8.h +//#define CFG_H cfg-blf-q8.h #include "tk.h" -#include incfile(CONFIGFILE) +#include incfile(CFG_H) /********* Include headers which need to be before FSM *********/ @@ -92,8 +92,11 @@ #include "spaghetti-monster.h" /********* does this build target have special code to include? *********/ -#ifdef OVERRIDES_FILE -#include incfile(OVERRIDES_FILE) +#ifdef HWDEF_C_FILE +#include incfile(HWDEF_C_FILE) +#endif +#ifdef CFG_C_FILE +#include incfile(CFG_C_FILE) #endif @@ -138,8 +141,10 @@ #include "tactical-mode.h" #endif -#ifdef USE_TINT_RAMPING -#include "tint-ramping.h" +// allow the channel mode handler even when only 1 mode +// (so a tint ramp light could still use 3H even if there's no other mode) +#if defined(USE_CHANNEL_MODES) +#include "channel-modes.h" #endif #ifdef USE_FACTORY_RESET @@ -197,8 +202,8 @@ #include "tactical-mode.c" #endif -#ifdef USE_TINT_RAMPING -#include "tint-ramping.c" +#if defined(USE_CHANNEL_MODES) +#include "channel-modes.c" #endif #ifdef USE_FACTORY_RESET @@ -234,13 +239,13 @@ void setup() { #if defined(USE_MANUAL_MEMORY) && defined(USE_MANUAL_MEMORY_TIMER) // without this, initial boot-up brightness is wrong // when manual mem is enabled with a non-zero timer - if (manual_memory) memorized_level = manual_memory; + if (manual_memory) manual_memory_restore(); #endif - #ifdef USE_TINT_RAMPING - // add tint ramping underneath every other state - push_state(tint_ramping_state, 0); - #endif // ifdef USE_TINT_RAMPING + #if defined(USE_CHANNEL_MODES) + // add channel mode functions underneath every other state + push_state(channel_mode_state, 0); + #endif push_state(off_state, 1); @@ -250,10 +255,10 @@ void setup() { // power clicky acts as a momentary mode load_config(); - #ifdef USE_TINT_RAMPING - // add tint ramping underneath every other state - push_state(tint_ramping_state, 0); - #endif // ifdef USE_TINT_RAMPING + #if defined(USE_CHANNEL_MODES) + // add channel mode functions underneath every other state + push_state(channel_mode_state, 0); + #endif if (button_is_pressed()) // hold button to go to moon diff --git a/spaghetti-monster/anduril/build-all.sh b/spaghetti-monster/anduril/build-all.sh index b9f6d15..768559c 100755 --- a/spaghetti-monster/anduril/build-all.sh +++ b/spaghetti-monster/anduril/build-all.sh @@ -33,8 +33,8 @@ for TARGET in cfg-*.h ; do if [ -z "$ATTINY" ]; then ATTINY=85 ; fi # try to compile - echo ../../../bin/build.sh $ATTINY "$UI" "-DCONFIGFILE=${TARGET}" - ../../../bin/build.sh $ATTINY "$UI" "-DCONFIGFILE=${TARGET}" + echo ../../../bin/build.sh $ATTINY "$UI" "-DCFG_H=${TARGET}" + ../../../bin/build.sh $ATTINY "$UI" "-DCFG_H=${TARGET}" # track result, and rename compiled files if [ 0 = $? ] ; then diff --git a/spaghetti-monster/anduril/candle-mode.c b/spaghetti-monster/anduril/candle-mode.c index d15195e..12ffa84 100644 --- a/spaghetti-monster/anduril/candle-mode.c +++ b/spaghetti-monster/anduril/candle-mode.c @@ -28,7 +28,7 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { static int8_t ramp_direction = 1; - #define MAX_CANDLE_LEVEL (RAMP_LENGTH-CANDLE_AMPLITUDE-15) + #define MAX_CANDLE_LEVEL (MAX_LEVEL-CANDLE_AMPLITUDE-15) static uint8_t candle_wave1 = 0; static uint8_t candle_wave2 = 0; static uint8_t candle_wave3 = 0; diff --git a/spaghetti-monster/anduril/cfg-emisar-d4v2-219.h b/spaghetti-monster/anduril/cfg-emisar-d4v2-219.h index 414971a..dad84f0 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4v2-219.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4v2-219.h @@ -4,9 +4,10 @@ #define MODEL_NUMBER "0114" // ATTINY: 1634 -// don't turn off first channel at turbo level -#undef PWM1_LEVELS -#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 -// 65% FET power -#undef PWM2_LEVELS -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,15,16,17,18,19,21,22,23,25,26,27,28,30,32,33,34,36,38,39,41,42,44,46,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,78,80,82,84,87,90,92,94,97,99,102,104,108,110,113,116,119,121,125,127,130,134,136,140,143,146,149,153,156,159,163,166 +// don't turn off the low channel at turbo level +#undef LOW_PWM_LEVELS +#define LOW_PWM_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +// 65% DDFET power +#undef HIGH_PWM_LEVELS +#define HIGH_PWM_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,13,15,16,17,18,19,21,22,23,25,26,27,28,30,32,33,34,36,38,39,41,42,44,46,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,78,80,82,84,87,90,92,94,97,99,102,104,108,110,113,116,119,121,125,127,130,134,136,140,143,146,149,153,156,159,163,166 + diff --git a/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h b/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h index 717afcf..5e33a05 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h @@ -4,11 +4,23 @@ #define MODEL_NUMBER "0115" // ATTINY: 1634 +// switch to 1-channel support functions +#undef USE_SET_LEVEL_2CH_STACKED +#undef USE_GRADUAL_TICK_2CH_STACKED +#define USE_SET_LEVEL_1CH +#define USE_GRADUAL_TICK_1CH +#undef SET_LEVEL_MODES +#undef GRADUAL_TICK_MODES +#define SET_LEVEL_MODES set_level_1ch +#define GRADUAL_TICK_MODES gradual_tick_1ch + #undef PWM_CHANNELS #define PWM_CHANNELS 1 -#undef PWM1_LEVELS -#undef PWM2_LEVELS -#define PWM1_LEVELS 1,1,1,2,2,2,2,3,3,3,3,4,4,5,5,6,6,6,7,8,8,9,9,10,10,11,12,13,13,14,15,16,16,17,18,19,20,21,22,23,23,24,26,27,28,29,30,31,32,33,34,36,37,38,39,41,42,43,45,46,47,49,50,52,53,55,56,58,59,61,62,64,66,67,69,71,72,74,76,78,80,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,116,118,120,122,125,127,129,132,134,136,139,141,144,146,148,151,154,156,159,161,164,166,169,172,174,177,180,183,185,188,191,194,197,200,203,205,208,211,214,217,220,223,226,230,233,236,239,242,245,249,252,255 + +#undef LOW_PWM_LEVELS +#undef HIGH_PWM_LEVELS +#define LOW_PWM_LEVELS 1,1,1,2,2,2,2,3,3,3,3,4,4,5,5,6,6,6,7,8,8,9,9,10,10,11,12,13,13,14,15,16,16,17,18,19,20,21,22,23,23,24,26,27,28,29,30,31,32,33,34,36,37,38,39,41,42,43,45,46,47,49,50,52,53,55,56,58,59,61,62,64,66,67,69,71,72,74,76,78,80,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,116,118,120,122,125,127,129,132,134,136,139,141,144,146,148,151,154,156,159,161,164,166,169,172,174,177,180,183,185,188,191,194,197,200,203,205,208,211,214,217,220,223,226,230,233,236,239,242,245,249,252,255 + #undef MAX_1x7135 #define MAX_1x7135 150 #undef QUARTERSPEED_LEVEL @@ -39,4 +51,7 @@ #undef THERM_FASTER_LEVEL #define THERM_FASTER_LEVEL 150 -#undef USE_THERMAL_REGULATION +// maybe keep this, in case someone uses a higher power channel? +//#undef USE_THERMAL_REGULATION +//#undef USE_SET_LEVEL_GRADUALLY + diff --git a/spaghetti-monster/anduril/cfg-emisar-d4v2.h b/spaghetti-monster/anduril/cfg-emisar-d4v2.h index 4121465..54de297 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4v2.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4v2.h @@ -1,28 +1,19 @@ // Emisar D4 config options for Anduril +// Copyright (C) 2019 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + #define MODEL_NUMBER "0113" #include "hwdef-Emisar_D4v2.h" #include "hank-cfg.h" // ATTINY: 1634 -// this light has three aux LED channels: R, G, B -#define USE_AUX_RGB_LEDS -// it also has an independent LED in the button -#define USE_BUTTON_LED -// the aux LEDs are front-facing, so turn them off while main LEDs are on -// TODO: the whole "indicator LED" thing needs to be refactored into -// "aux LED(s)" and "button LED(s)" since they work a bit differently -#ifdef USE_INDICATOR_LED_WHILE_RAMPING -#undef USE_INDICATOR_LED_WHILE_RAMPING -#endif - - // copied from original D4, since it's also a FET+1 and has the same host // ../../bin/level_calc.py 1 65 7135 1 0.8 150 // ... mixed with this: // ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 -#define RAMP_LENGTH 150 -#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 +#define RAMP_SIZE 150 +#define LOW_PWM_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define HIGH_PWM_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 #define MAX_1x7135 65 #define HALFSPEED_LEVEL 14 #define QUARTERSPEED_LEVEL 6 diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index 4e5993b..e009e02 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -1,19 +1,9 @@ // Sofirn LT1S Pro + #define MODEL_NUMBER "0623" #include "hwdef-Sofirn_LT1S-Pro.h" // ATTINY: 1616 -// this model requires some special code -#define OVERRIDES_FILE cfg-sofirn-lt1s-pro.c -#define OVERRIDE_SET_LEVEL -inline void set_level_override(uint8_t level); - -// uses 4C action while On to switch between white and red channels (overrides lockout action) -#define USE_OUTPUT_MUX -// the button lights up -#define USE_INDICATOR_LED -// the button is visible while main LEDs are on -#define USE_INDICATOR_LED_WHILE_RAMPING // off mode: high (1) // lockout: blinking (3) #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) @@ -21,19 +11,23 @@ inline void set_level_override(uint8_t level); // the lantern has two PWM channels, but they drive different sets of emitters // (one channel for warm emitters, one channel for cold) // so enable a special ramping mode which changes tint instead of brightness -#define USE_TINT_RAMPING +//#define USE_TINT_RAMPING // how much to increase total brightness at middle tint // (0 = 100% brightness, 64 = 200% brightness) #define TINT_RAMPING_CORRECTION 10 // 115% -#ifdef RAMP_LENGTH -#undef RAMP_LENGTH -#endif - // level_calc.py 1 150 7135 1 30 800 -#define RAMP_LENGTH 150 -#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,11,11,12,13,13,14,15,15,16,17,18,18,19,20,21,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,43,44,45,46,48,49,50,51,53,54,56,57,58,60,61,63,64,66,67,69,70,72,74,75,77,79,80,82,84,85,87,89,91,93,95,97,98,100,102,104,106,108,111,113,115,117,119,121,124,126,128,130,133,135,137,140,142,145,147,150,152,155,157,160,163,165,168,171,173,176,179,182,185,188,190,193,196,199,202,205,209,212,215,218,221,224,228,231,234,238,241,245,248,251,255 +#define RAMP_SIZE 150 +// TODO: use dynamic PWM instead of plain 8-bit +// (so we can get lower lows and a smoother ramp) +// TODO: 200% power at top of ramp on white blend mode +#define PWM_LEVELS 1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,11,11,12,13,13,14,15,15,16,17,18,18,19,20,21,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,43,44,45,46,48,49,50,51,53,54,56,57,58,60,61,63,64,66,67,69,70,72,74,75,77,79,80,82,84,85,87,89,91,93,95,97,98,100,102,104,106,108,111,113,115,117,119,121,124,126,128,130,133,135,137,140,142,145,147,150,152,155,157,160,163,165,168,171,173,176,179,182,185,188,190,193,196,199,202,205,209,212,215,218,221,224,228,231,234,238,241,245,248,251,255 +#define BLEND_PWM_LEVELS PWM_LEVELS +#define RED_PWM_LEVELS PWM_LEVELS #define MAX_1x7135 65 +// FIXME: clock at 5 MHz w/ full+half+quarter speeds, +// instead of 10 MHz with w/ only half+quarter +// (10 MHz is just wasting power) #define HALFSPEED_LEVEL 256 // red LEDs use a QX7138 chip which has max PWM speed of 10 kHz, so never run faster than halfspeed #define QUARTERSPEED_LEVEL 5 @@ -68,8 +62,11 @@ inline void set_level_override(uint8_t level); #define USE_SOS_MODE #define USE_SOS_MODE_IN_BLINKY_GROUP -// the sensor (attiny) is nowhere near the emitters -// so thermal regulation can't work +#define USE_POLICE_COLOR_STROBE_MODE +#undef TACTICAL_LEVELS +#define TACTICAL_LEVELS 120,30,(RAMP_SIZE+3) // high, low, police strobe + +// FIXME: thermal regulation should actually work fine on this light #ifdef USE_THERMAL_REGULATION #undef USE_THERMAL_REGULATION #endif @@ -84,7 +81,7 @@ inline void set_level_override(uint8_t level); #ifdef BLINK_AT_RAMP_CEIL #undef BLINK_AT_RAMP_CEIL #endif +// without this, it's really hard to tell when ramping up stops +#define BLINK_AT_RAMP_CEIL -#ifndef USE_SOFT_FACTORY_RESET #define USE_SOFT_FACTORY_RESET -#endif \ No newline at end of file diff --git a/spaghetti-monster/anduril/channel-modes.c b/spaghetti-monster/anduril/channel-modes.c new file mode 100644 index 0000000..958b375 --- /dev/null +++ b/spaghetti-monster/anduril/channel-modes.c @@ -0,0 +1,146 @@ +/* + * channel-modes.c: Multi-channel functions for Anduril. + * Copyright (C) 2017-2023 Selene ToyKeeper + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "channel-modes.h" + + +uint8_t channel_mode_state(Event event, uint16_t arg) { + #ifdef USE_CHANNEL_MODE_ARGS + static int8_t tint_ramp_direction = 1; + static uint8_t prev_tint = 0; + // don't activate auto-tint modes unless the user hits the edge + // and keeps pressing for a while + static uint8_t past_edge_counter = 0; + // bugfix: click-click-hold from off to strobes would invoke tint ramping + // in addition to changing state... so ignore any tint-ramp events which + // don't look like they were meant to be here + static uint8_t active = 0; + uint8_t tint = channel_mode_args[channel_mode]; + #endif + + // it's possible that a light may need 3H but not 3C, + // so try to detect if 3C is needed + #if NUM_CHANNEL_MODES > 1 + // 3 clicks: next channel mode + if (event == EV_3clicks) { + uint8_t next = channel_mode; + // go to next channel mode until we find one which is enabled + // (and don't do any infinite loops if the user disabled them all) + uint8_t count = 0; + do { + count ++; + next = (next + 1) % NUM_CHANNEL_MODES; + } while ((! channel_mode_enabled(next)) && count < NUM_CHANNEL_MODES); + //} while ((! channel_modes_enabled[next]) && count < NUM_CHANNEL_MODES); + + // undo change if infinite loop detected (redundant?) + //if (NUM_CHANNEL_MODES == count) next = channel_mode; + + // if mode hasn't changed, abort + if (channel_mode == next) + return EVENT_NOT_HANDLED; + + set_channel_mode(next); + + // remember after battery changes + save_config(); + return EVENT_HANDLED; + } else + #endif // if NUM_CHANNEL_MODES > 1 + + #ifdef USE_CUSTOM_CHANNEL_3H_MODES + // defer to mode-specific function if defined + if (tint_ramp_modes[channel_mode]) { + StatePtr tint_func = channel_3H_modes[channel_mode]; + return tint_func(channel_mode); + } else + #endif + #ifdef USE_CHANNEL_MODE_ARGS + #ifndef DONT_USE_DEFAULT_CHANNEL_ARG_MODE + // click, click, hold: change the current channel's arg (like tint) + if (event == EV_click3_hold) { + ///// adjust value from 0 to 255 + // reset at beginning of movement + if (! arg) { + active = 1; // first frame means this is for us + past_edge_counter = 0; // doesn't start until user hits the edge + } + // ignore event if we weren't the ones who handled the first frame + if (! active) return EVENT_NOT_HANDLED; + + // change normal tints + if ((tint_ramp_direction > 0) && (tint < 255)) { + tint += 1; + } + else if ((tint_ramp_direction < 0) && (tint > 0)) { + tint -= 1; + } + // if tint change stalled, let user know we hit the edge + else if (prev_tint == tint) { + if (past_edge_counter == 0) blip(); + past_edge_counter = 1; + } + prev_tint = tint; + channel_mode_args[channel_mode] = tint; + set_level(actual_level); + return EVENT_HANDLED; + } + + // click, click, hold, release: reverse direction for next ramp + else if (event == EV_click3_hold_release) { + active = 0; // ignore next hold if it wasn't meant for us + // reverse + tint_ramp_direction = -tint_ramp_direction; + if (0 == tint) tint_ramp_direction = 1; + else if (255 == tint) tint_ramp_direction = -1; + // remember tint after battery change + channel_mode_args[channel_mode] = tint; + save_config(); + // bug?: for some reason, brightness can seemingly change + // from 1/150 to 2/150 without this next line... not sure why + set_level(actual_level); + return EVENT_HANDLED; + } + #endif // ifndef DONT_USE_DEFAULT_CHANNEL_ARG_MODE + #endif // ifdef USE_CHANNEL_MODE_ARGS + + #if defined(USE_SIMPLE_UI) + // remaining mappings aren't "simple", so stop here + if (simple_ui_active) { + return EVENT_NOT_HANDLED; + } + #endif + + #if NUM_CHANNEL_MODES > 1 + // channel toggle menu on ... 9H? + else if (event == EV_click9_hold) { + push_state(channel_mode_config_state, 0); + return MISCHIEF_MANAGED; + } + #endif + + return EVENT_NOT_HANDLED; +} + +#if NUM_CHANNEL_MODES > 1 +void channel_mode_config_save(uint8_t step, uint8_t value) { + // 1 menu item per channel mode, to enable or disable that mode + step --; // step is 1-based, channel modes are 0-based + if (value) channel_mode_enable(step); + else channel_mode_disable(step); +} + +uint8_t channel_mode_config_state(Event event, uint16_t arg) { + // 1 menu item per channel mode, to enable or disable that mode + return config_state_base( + event, arg, + NUM_CHANNEL_MODES, + channel_mode_config_save + ); +} +#endif diff --git a/spaghetti-monster/anduril/channel-modes.h b/spaghetti-monster/anduril/channel-modes.h new file mode 100644 index 0000000..f536d58 --- /dev/null +++ b/spaghetti-monster/anduril/channel-modes.h @@ -0,0 +1,20 @@ +/* + * channel-modes.h: Multi-channel functions for Anduril. + * Copyright (C) 2017-2023 Selene ToyKeeper + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#if defined(USE_MANUAL_MEMORY) && defined(USE_CHANNEL_MODE_ARGS) +// TODO: save to eeprom +// remember and reset 1 extra parameter per channel mode (like tint) +uint8_t manual_memory_channel_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; +#endif + +// not actually a mode, more of a fallback under other modes +uint8_t channel_mode_state(Event event, uint16_t arg); + +#if NUM_CHANNEL_MODES > 1 +uint8_t channel_mode_config_state(Event event, uint16_t arg); +#endif diff --git a/spaghetti-monster/anduril/factory-reset.c b/spaghetti-monster/anduril/factory-reset.c index ecb4cc2..a14b5b9 100644 --- a/spaghetti-monster/anduril/factory-reset.c +++ b/spaghetti-monster/anduril/factory-reset.c @@ -1,27 +1,15 @@ -/* - * factory-reset.c: Factory reset functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// factory-reset.c: Factory reset functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FACTORY_RESET_C -#define FACTORY_RESET_C +#pragma once #include "factory-reset.h" +// allows setting channel mode per animation stage, +// so it can ramp up in red then explode in white (as one example) +// TODO: maybe also do the same in menus? + void factory_reset() { // display a warning for a few seconds before doing the actual reset, // so the user has time to abort if they want @@ -31,6 +19,9 @@ void factory_reset() { uint8_t bright; uint8_t reset = 1; // wind up to an explosion + #ifdef FACTORY_RESET_WARN_CHANNEL + set_channel_mode(FACTORY_RESET_WARN_CHANNEL); + #endif for (bright=0; bright 0; bright--) { set_level(bright); @@ -69,6 +72,3 @@ void factory_reset() { } } - -#endif - diff --git a/spaghetti-monster/anduril/factory-reset.h b/spaghetti-monster/anduril/factory-reset.h index 9f0af38..63c25cd 100644 --- a/spaghetti-monster/anduril/factory-reset.h +++ b/spaghetti-monster/anduril/factory-reset.h @@ -1,26 +1,8 @@ -/* - * factory-reset.h: Factory reset functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// factory-reset.h: Factory reset functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FACTORY_RESET_H -#define FACTORY_RESET_H +#pragma once void factory_reset(); - -#endif diff --git a/spaghetti-monster/anduril/hank-cfg.h b/spaghetti-monster/anduril/hank-cfg.h index 11eb0a1..f24ea67 100644 --- a/spaghetti-monster/anduril/hank-cfg.h +++ b/spaghetti-monster/anduril/hank-cfg.h @@ -1,5 +1,7 @@ -#ifndef HANK_CFG -#define HANK_CFG +// Intl-Outdoor (Hank)'s config options for Anduril +// Copyright (C) 2021 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once // config preferences for Hank Wang of Intl-Outdoor (Emisar, Noctigon) @@ -18,4 +20,3 @@ // double click while on goes to full-power turbo, not ramp ceiling #define DEFAULT_2C_STYLE 1 -#endif // ifndef HANK_CFG diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h index f0de161..9004f1f 100644 --- a/spaghetti-monster/anduril/load-save-config-fsm.h +++ b/spaghetti-monster/anduril/load-save-config-fsm.h @@ -54,13 +54,6 @@ typedef enum { #ifdef USE_MANUAL_MEMORY_TIMER manual_memory_timer_e, #endif - #ifdef USE_TINT_RAMPING - manual_memory_tint_e, - #endif - #endif - #ifdef USE_TINT_RAMPING - tint_e, - tint_style_e, #endif #ifdef USE_JUMP_START jump_start_level_e, @@ -100,7 +93,28 @@ typedef enum { tactical_lvl_2_e, tactical_lvl_3_e, #endif - eeprom_indexes_e_END + #if NUM_CHANNEL_MODES > 1 + channel_mode_e, + channel_modes_enabled_e, + #if defined(USE_MANUAL_MEMORY) + manual_memory_channel_mode_e, + #endif + #endif + #ifdef USE_CHANNEL_MODE_ARGS + // this is an array, needs a few bytes + channel_mode_args_e, + #if defined(USE_MANUAL_MEMORY) + // this is an array, needs a few bytes + manual_memory_channel_args_e = channel_mode_args_e + NUM_CHANNEL_MODES, + // and this is an ugly ugly kludge + // FIXME: use a struct for eeprom, not an array + eeprom_indexes_e_END = manual_memory_channel_args_e + NUM_CHANNEL_MODES + #else + eeprom_indexes_e_END = channel_mode_args_e + NUM_CHANNEL_MODES + #endif + #else + eeprom_indexes_e_END + #endif } eeprom_indexes_e; #define EEPROM_BYTES eeprom_indexes_e_END diff --git a/spaghetti-monster/anduril/load-save-config.c b/spaghetti-monster/anduril/load-save-config.c index 4101e7a..ad84450 100644 --- a/spaghetti-monster/anduril/load-save-config.c +++ b/spaghetti-monster/anduril/load-save-config.c @@ -56,13 +56,6 @@ void load_config() { #ifdef USE_MANUAL_MEMORY_TIMER manual_memory_timer = eeprom[manual_memory_timer_e]; #endif - #ifdef USE_TINT_RAMPING - manual_memory_tint = eeprom[manual_memory_tint_e]; - #endif - #endif - #ifdef USE_TINT_RAMPING - tint = eeprom[tint_e]; - tint_style = eeprom[tint_style_e]; #endif #ifdef USE_JUMP_START jump_start_level = eeprom[jump_start_level_e], @@ -100,6 +93,21 @@ void load_config() { tactical_levels[1] = eeprom[tactical_lvl_2_e]; tactical_levels[2] = eeprom[tactical_lvl_3_e]; #endif + #if NUM_CHANNEL_MODES > 1 + channel_mode = eeprom[channel_mode_e]; + channel_modes_enabled = eeprom[channel_modes_enabled_e]; + #if defined(USE_MANUAL_MEMORY) + manual_memory_channel_mode = eeprom[manual_memory_channel_mode_e]; + #endif + #endif + #ifdef USE_CHANNEL_MODE_ARGS + for (uint8_t i=0; i 1 + eeprom[channel_mode_e] = channel_mode; + eeprom[channel_modes_enabled_e] = channel_modes_enabled; + #if defined(USE_MANUAL_MEMORY) + eeprom[manual_memory_channel_mode_e] = manual_memory_channel_mode; + #endif + #endif + #ifdef USE_CHANNEL_MODE_ARGS + for (uint8_t i=0; i= (manual_memory_timer * SLEEP_TICKS_PER_MINUTE))) { - memorized_level = manual_memory; - #ifdef USE_TINT_RAMPING - tint = manual_memory_tint; - #endif + manual_memory_restore(); } #endif #ifdef USE_INDICATOR_LED @@ -131,10 +128,7 @@ uint8_t off_state(Event event, uint16_t arg) { // this clause probably isn't used by any configs any more // but is included just in case someone configures it this way if (manual_memory) { - memorized_level = manual_memory; - #ifdef USE_TINT_RAMPING - tint = manual_memory_tint; - #endif + manual_memory_restore(); } #endif set_level(nearest_level(memorized_level)); diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index 6e8ba88..e57b68f 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -26,6 +26,7 @@ #include "sunset-timer.h" #endif + uint8_t steady_state(Event event, uint16_t arg) { static int8_t ramp_direction = 1; #if (B_TIMING_OFF == B_RELEASE_T) @@ -378,7 +379,26 @@ uint8_t steady_state(Event event, uint16_t arg) { #endif // 3 clicks: toggle smooth vs discrete ramping - else if (event == EV_3clicks) { + // (and/or 6 clicks when there are multiple channel modes) + // (handle 3C here anyway, when all but 1 mode is disabled) + else if ((event == EV_3clicks) + #if NUM_CHANNEL_MODES > 1 + || (event == EV_6clicks) + ) { + // detect if > 1 channel mode is enabled, + // and if so, fall through so channel mode code can handle it + // otherwise, change the ramp style + if (event == EV_3clicks) { + uint8_t enabled = 0; + for (uint8_t m=0; m 1) + return EVENT_NOT_HANDLED; + } + #else + ) { + #endif + ramp_style = !ramp_style; save_config(); #ifdef START_AT_MEMORIZED_LEVEL @@ -400,9 +420,9 @@ uint8_t steady_state(Event event, uint16_t arg) { } #endif - #ifndef USE_TINT_RAMPING // 3H: momentary turbo (on lights with no tint ramping) - else if (event == EV_click3_hold) { + // (or 4H on lights with tint ramping) + else if (event == EV_MOMENTARY_TURBO) { if (! arg) { // first frame only, to allow thermal regulation to work #ifdef USE_2C_STYLE_CONFIG uint8_t tl = style_2c ? MAX_LEVEL : turbo_level; @@ -413,11 +433,10 @@ uint8_t steady_state(Event event, uint16_t arg) { } return MISCHIEF_MANAGED; } - else if (event == EV_click3_hold_release) { + else if (event == EV_MOMENTARY_TURBO_RELEASE) { set_level_and_therm_target(memorized_level); return MISCHIEF_MANAGED; } - #endif // ifndef USE_TINT_RAMPING #ifdef USE_MOMENTARY_MODE // 5 clicks: shortcut to momentary mode @@ -439,10 +458,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_MANUAL_MEMORY else if (event == EV_10clicks) { // turn on manual memory and save current brightness - manual_memory = actual_level; - #ifdef USE_TINT_RAMPING - manual_memory_tint = tint; // remember tint too - #endif + manual_memory_save(); save_config(); blink_once(); return MISCHIEF_MANAGED; @@ -643,6 +659,27 @@ void set_level_and_therm_target(uint8_t level) { #define set_level_and_therm_target(level) set_level(level) #endif +void manual_memory_restore() { + memorized_level = manual_memory; + #if NUM_CHANNEL_MODES > 1 + channel_mode = manual_memory_channel_mode; + #endif + #ifdef USE_CHANNEL_MODE_ARGS + for (uint8_t i=0; i 1 + manual_memory_channel_mode = channel_mode; + #endif + #ifdef USE_CHANNEL_MODE_ARGS + for (uint8_t i=0; i= 3 #ifndef BLINK_AT_RAMP_MIDDLE_1 #define BLINK_AT_RAMP_MIDDLE_1 MAX_Nx7135 @@ -166,6 +178,9 @@ uint8_t manual_memory = DEFAULT_MANUAL_MEMORY; uint8_t manual_memory_timer = DEFAULT_MANUAL_MEMORY_TIMER; #endif #endif +void manual_memory_restore(); +void manual_memory_save(); + #ifdef USE_SIMPLE_UI // whether to enable the simplified interface or not uint8_t simple_ui_active = SIMPLE_UI_ACTIVE; diff --git a/spaghetti-monster/anduril/strobe-modes.c b/spaghetti-monster/anduril/strobe-modes.c index 78fe240..5ee2386 100644 --- a/spaghetti-monster/anduril/strobe-modes.c +++ b/spaghetti-monster/anduril/strobe-modes.c @@ -184,6 +184,12 @@ inline void strobe_state_iter() { break; #endif + #ifdef USE_POLICE_COLOR_STROBE_MODE + case police_color_strobe_e: + police_color_strobe_iter(); + break; + #endif + #ifdef USE_LIGHTNING_MODE case lightning_storm_e: lightning_storm_iter(); @@ -205,7 +211,7 @@ inline void party_tactical_strobe_mode_iter(uint8_t st) { uint8_t del = strobe_delays[st]; // TODO: make tac strobe brightness configurable? set_level(STROBE_BRIGHTNESS); - if (0) {} // placeholde0 + if (0) {} // placeholder #ifdef USE_PARTY_STROBE_MODE else if (st == party_strobe_e) { // party strobe #ifdef PARTY_STROBE_ONTIME @@ -226,6 +232,28 @@ inline void party_tactical_strobe_mode_iter(uint8_t st) { } #endif +#ifdef USE_POLICE_COLOR_STROBE_MODE +inline void police_color_strobe_iter() { + // one iteration of main loop() + uint8_t del = 66; + // TODO: make police strobe brightness configurable + uint8_t bright = memorized_level; + uint8_t channel = channel_mode; + + for (uint8_t i=0; i<10; i++) { + if (0 == i) set_channel_mode(POLICE_COLOR_STROBE_CH1); + else if (5 == i) set_channel_mode(POLICE_COLOR_STROBE_CH2); + set_level(bright); + nice_delay_ms(del >> 1); + set_level(STROBE_OFF_LEVEL); + nice_delay_ms(del); + } + + // restore this when done + set_channel_mode(channel); +} +#endif + #ifdef USE_LIGHTNING_MODE inline void lightning_storm_iter() { // one iteration of main loop() diff --git a/spaghetti-monster/anduril/strobe-modes.h b/spaghetti-monster/anduril/strobe-modes.h index c6cfb53..685c249 100644 --- a/spaghetti-monster/anduril/strobe-modes.h +++ b/spaghetti-monster/anduril/strobe-modes.h @@ -29,6 +29,9 @@ typedef enum { #ifdef USE_TACTICAL_STROBE_MODE tactical_strobe_e, #endif + #ifdef USE_POLICE_COLOR_STROBE_MODE + police_color_strobe_e, + #endif #ifdef USE_LIGHTNING_MODE lightning_storm_e, #endif @@ -81,6 +84,10 @@ uint8_t strobe_delays[] = { 41, 67 }; // party strobe 24 Hz, tactical strobe 10 inline void party_tactical_strobe_mode_iter(uint8_t st); #endif +#ifdef USE_POLICE_COLOR_STROBE_MODE +inline void police_color_strobe_iter(); +#endif + #ifdef USE_LIGHTNING_MODE inline void lightning_storm_iter(); #endif diff --git a/spaghetti-monster/anduril/tint-ramping.c b/spaghetti-monster/anduril/tint-ramping.c index d270d9d..13f5d29 100644 --- a/spaghetti-monster/anduril/tint-ramping.c +++ b/spaghetti-monster/anduril/tint-ramping.c @@ -1,24 +1,10 @@ /* * tint-ramping.c: Tint ramping functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . + * Copyright (C) 2017-2023 Selene ToyKeeper + * SPDX-License-Identifier: GPL-3.0-or-later */ -#ifndef TINT_RAMPING_C -#define TINT_RAMPING_C +#pragma once #include "tint-ramping.h" @@ -100,6 +86,3 @@ uint8_t tint_ramping_state(Event event, uint16_t arg) { return EVENT_NOT_HANDLED; } - -#endif - diff --git a/spaghetti-monster/anduril/tint-ramping.h b/spaghetti-monster/anduril/tint-ramping.h index 1c5e22a..9b7f9a8 100644 --- a/spaghetti-monster/anduril/tint-ramping.h +++ b/spaghetti-monster/anduril/tint-ramping.h @@ -1,24 +1,10 @@ /* * tint-ramping.h: Tint ramping functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . + * Copyright (C) 2017-2023 Selene ToyKeeper + * SPDX-License-Identifier: GPL-3.0-or-later */ -#ifndef TINT_RAMPING_H -#define TINT_RAMPING_H +#pragma once // 0: smooth tint ramp // 1: toggle tint only between two extremes @@ -35,5 +21,3 @@ uint8_t manual_memory_tint; // not actually a mode, more of a fallback under other modes uint8_t tint_ramping_state(Event event, uint16_t arg); - -#endif diff --git a/spaghetti-monster/fsm-main.c b/spaghetti-monster/fsm-main.c index 30b8a67..fca1e83 100644 --- a/spaghetti-monster/fsm-main.c +++ b/spaghetti-monster/fsm-main.c @@ -39,6 +39,7 @@ ISR(TIMER1_COMPA_vect) { } #endif +// FIXME: hw_setup() shouldn't be here ... move it entirely to hwdef files #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) static inline void hw_setup() { // configure PWM channels diff --git a/spaghetti-monster/fsm-misc.h b/spaghetti-monster/fsm-misc.h index 66d31ba..17ed66f 100644 --- a/spaghetti-monster/fsm-misc.h +++ b/spaghetti-monster/fsm-misc.h @@ -53,6 +53,11 @@ void indicator_led(uint8_t lvl); void button_led_set(uint8_t lvl); #endif +// if any type of aux LEDs exist, define a shorthand flag for it +#if defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS) || defined(USE_BUTTON_LED) +#define HAS_AUX_LEDS +#endif + #ifdef USE_AUX_RGB_LEDS // value: 0b00BBGGRR // each pair of bits: 0=off, 1=low, 2=high diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c index 63692c8..5096dfd 100644 --- a/spaghetti-monster/fsm-ramping.c +++ b/spaghetti-monster/fsm-ramping.c @@ -2,46 +2,28 @@ * fsm-ramping.c: Ramping functions for SpaghettiMonster. * Handles 1- to 4-channel smooth ramping on a single LED. * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . + * Copyright (C) 2017-2023 Selene ToyKeeper + * SPDX-License-Identifier: GPL-3.0-or-later */ -#ifndef FSM_RAMPING_C -#define FSM_RAMPING_C +#pragma once #ifdef USE_RAMPING -void set_level(uint8_t level) { - #ifdef USE_JUMP_START - // maybe "jump start" the engine, if it's prone to slow starts - // (pulse the output high for a moment to wake up the power regulator) - // (only do this when starting from off and going to a low level) - if ((! actual_level) - && level - && (level < jump_start_level)) { - set_level(jump_start_level); - delay_4ms(JUMP_START_TIME/4); - } - #endif // ifdef USE_JUMP_START +void set_channel_mode(uint8_t mode) { + uint8_t cur_level = actual_level; + // turn off old LEDs before changing channel + set_level(0); - actual_level = level; + // change the channel + channel_mode = mode; - #ifdef USE_SET_LEVEL_GRADUALLY - gradual_target = level; - #endif + // update the LEDs + set_level(cur_level); +} +#ifdef HAS_AUX_LEDS +inline void set_level_aux_leds(uint8_t level) { #ifdef USE_INDICATOR_LED_WHILE_RAMPING // use side-facing aux LEDs while main LEDs are on if (! go_to_standby) { @@ -52,9 +34,6 @@ void set_level(uint8_t level) { button_led_set((level > 0) + (level > DEFAULT_LEVEL)); #endif } - //if (level > MAX_1x7135) indicator_led(2); - //else if (level > 0) indicator_led(1); - //else if (! go_to_standby) indicator_led(0); #else // turn off front-facing aux LEDs while main LEDs are on #if defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS) if (! go_to_standby) { @@ -70,33 +49,173 @@ void set_level(uint8_t level) { } #endif #endif +} +#endif // ifdef HAS_AUX_LEDS - #ifdef OVERRIDE_SET_LEVEL - set_level_override(level); - #else - #if defined(PWM1_CNT) && defined(PWM1_PHASE_RESET_ON) || defined(PWM1_PHASE_SYNC) - static uint8_t prev_level = 0; - uint8_t api_level = level; +void set_level(uint8_t level) { + #ifdef USE_JUMP_START + // maybe "jump start" the engine, if it's prone to slow starts + // (pulse the output high for a moment to wake up the power regulator) + // (only do this when starting from off and going to a low level) + // TODO: allow different jump start behavior per channel mode + if ((! actual_level) + && level + && (level < jump_start_level)) { + set_level(jump_start_level); + delay_4ms(JUMP_START_TIME/4); + } + #endif + + #ifdef HAS_AUX_LEDS + set_level_aux_leds(level); + #endif + + // call the relevant hardware-specific set_level_*() + SetLevelFuncPtr set_level_func = channel_modes[channel_mode]; + set_level_func(level); + + actual_level = level; + + #ifdef USE_SET_LEVEL_GRADUALLY + gradual_target = level; + #endif + + #ifdef USE_DYNAMIC_UNDERCLOCKING + auto_clock_speed(); + #endif +} + +///// Common set_level_*() functions shared by multiple lights ///// +// (unique lights should use their own, +// but these common versions cover most of the common hardware designs) + +#ifdef USE_SET_LEVEL_1CH +// single set of LEDs with 1 power channel +void set_level_1ch(uint8_t level) { + if (level == 0) { + LOW_PWM_LVL = 0; + } else { + level --; // PWM array index = level - 1 + LOW_PWM_LVL = PWM_GET(low_pwm_levels, level); + } +} +#endif + +#ifdef USE_SET_LEVEL_2CH_STACKED +// single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear +void set_level_2ch_stacked(uint8_t level) { + if (level == 0) { + LOW_PWM_LVL = 0; + HIGH_PWM_LVL = 0; + } else { + level --; // PWM array index = level - 1 + LOW_PWM_LVL = PWM_GET(low_pwm_levels, level); + HIGH_PWM_LVL = PWM_GET(high_pwm_levels, level); + } +} +#endif + +#ifdef USE_SET_LEVEL_3CH_STACKED +// single set of LEDs with 3 stacked power channels, like DDFET+N+1 +void set_level_3ch_stacked(uint8_t level) { + if (level == 0) { + LOW_PWM_LVL = 0; + MED_PWM_LVL = 0; + HIGH_PWM_LVL = 0; + } else { + level --; // PWM array index = level - 1 + LOW_PWM_LVL = PWM_GET(low_pwm_levels, level); + MED_PWM_LVL = PWM_GET(med_pwm_levels, level); + HIGH_PWM_LVL = PWM_GET(high_pwm_levels, level); + } +} +#endif + +// TODO: upgrade some older lights to dynamic PWM +// TODO: 1ch w/ dynamic PWM +// TODO: 1ch w/ dynamic PWM and opamp enable pins? +// TODO: 2ch stacked w/ dynamic PWM +// TODO: 2ch stacked w/ dynamic PWM and opamp enable pins? + +#ifdef USE_SET_LEVEL_2CH_BLEND +// warm + cool blend w/ middle sag correction +void set_level_2ch_blend(uint8_t level) { + #ifndef TINT_RAMPING_CORRECTION + #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint + #endif + + BLEND_PWM_DATATYPE vpwm; + + if (level == 0) { + vpwm = 0; + } else { + level --; // PWM array index = level - 1 + vpwm = PWM_GET(blend_pwm_levels, level); + } + + // calculate actual PWM levels based on a single-channel ramp + // and a global tint value + uint16_t brightness = vpwm; + uint16_t warm_PWM, cool_PWM; + const uint16_t top = PWM_TOP; + + // auto-tint modes + uint8_t mytint = channel_mode_args[channel_mode]; + + PWM_DATATYPE2 base_PWM = brightness; + #if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0) + // middle tints sag, so correct for that effect + // by adding extra power which peaks at the middle tint + // (correction is only necessary when PWM is fast) + if (level > HALFSPEED_LEVEL) { + base_PWM = brightness + + ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64) + * triangle_wave(mytint) / 255); + } + // fade the triangle wave out when above 100% power, + // so it won't go over 200% + if (brightness > top) { + base_PWM -= 2 * ( + ((brightness - top) * TINT_RAMPING_CORRECTION / 64) + * triangle_wave(mytint) / 255 + ); + } + // guarantee no more than 200% power + if (base_PWM > (top << 1)) { base_PWM = top << 1; } #endif - //TCCR0A = PHASE; + cool_PWM = (((PWM_DATATYPE2)mytint * (PWM_DATATYPE2)base_PWM) + 127) / 255; + warm_PWM = base_PWM - cool_PWM; + // when running at > 100% power, spill extra over to other channel + if (cool_PWM > top) { + warm_PWM += (cool_PWM - top); + cool_PWM = top; + } else if (warm_PWM > top) { + cool_PWM += (warm_PWM - top); + warm_PWM = top; + } + + WARM_PWM_LVL = warm_PWM; + COOL_PWM_LVL = cool_PWM; +} +#endif // ifdef USE_TINT_RAMPING + +#ifdef USE_LEGACY_SET_LEVEL +// (this is mostly just here for reference, temporarily) +// single set of LEDs with 1 to 3 stacked power channels, +// like linear, FET+1, and FET+N+1 +// (default set_level_*() function for most lights) +void set_level_legacy(uint8_t level) { if (level == 0) { #if PWM_CHANNELS >= 1 - PWM1_LVL = 0; + PWM1_LVL = 0; #endif #if PWM_CHANNELS >= 2 - PWM2_LVL = 0; + PWM2_LVL = 0; #endif #if PWM_CHANNELS >= 3 - PWM3_LVL = 0; - #endif - #if PWM_CHANNELS >= 4 - PWM4_LVL = 0; - #endif - #ifdef USE_TINT_RAMPING - TINT1_LVL = 0; - TINT2_LVL = 0; + PWM3_LVL = 0; #endif #if defined(PWM1_CNT) && defined(PWM1_PHASE_RESET_OFF) PWM1_CNT = 0; @@ -121,7 +240,6 @@ void set_level(uint8_t level) { #endif } else { // enable the power channel, if relevant - #ifndef USE_TINT_RAMPING // update_tint handles this better #ifdef LED_ENABLE_PIN #ifdef LED_ON_DELAY uint8_t led_enable_port_save = LED_ENABLE_PORT; @@ -161,7 +279,6 @@ void set_level(uint8_t level) { delay_4ms(LED2_ON_DELAY/4); #endif #endif - #endif // ifndef USE_TINT_RAMPING // PWM array index = level - 1 level --; @@ -175,9 +292,6 @@ void set_level(uint8_t level) { #if PWM_CHANNELS >= 3 PWM3_LVL = PWM_GET(pwm3_levels, level); #endif - #if PWM_CHANNELS >= 4 - PWM4_LVL = PWM_GET(pwm4_levels, level); - #endif #ifdef USE_DYN_PWM uint16_t top = PWM_GET(pwm_tops, level); @@ -190,29 +304,15 @@ void set_level(uint8_t level) { // (but don't wait when turning on from zero, because // it'll reset the phase below anyway) // to be safe, allow at least 32 cycles to update TOP - while(prev_level && (PWM1_CNT > (top - 32))) {} + while(actual_level && (PWM1_CNT > (top - 32))) {} #endif // pulse frequency modulation, a.k.a. dynamic PWM PWM1_TOP = top; - - // repeat for other channels if necessary - #ifdef PMW2_TOP - #if defined(PWM2_CNT) && defined(PWM2_PHASE_SYNC) - while(prev_level && (PWM2_CNT > (top - 32))) {} - #endif - PWM2_TOP = top; - #endif - #ifdef PMW3_TOP - #if defined(PWM3_CNT) && defined(PWM3_PHASE_SYNC) - while(prev_level && (PWM3_CNT > (top - 32))) {} - #endif - PWM3_TOP = top; - #endif #endif // ifdef USE_DYN_PWM #if defined(PWM1_CNT) && defined(PWM1_PHASE_RESET_ON) // force reset phase when turning on from zero // (because otherwise the initial response is inconsistent) - if (! prev_level) { + if (! actual_level) { PWM1_CNT = 0; #if defined(PWM2_CNT) && defined(PWM2_PHASE_RESET_ON) PWM2_CNT = 0; @@ -223,114 +323,117 @@ void set_level(uint8_t level) { } #endif } - #ifdef USE_TINT_RAMPING - update_tint(); - #endif - - #if defined(PWM1_CNT) && defined(PWM1_PHASE_RESET_ON) || defined(PWM1_PHASE_SYNC) - prev_level = api_level; - #endif - #endif // ifdef OVERRIDE_SET_LEVEL #ifdef USE_DYNAMIC_UNDERCLOCKING auto_clock_speed(); #endif } +#endif + #ifdef USE_SET_LEVEL_GRADUALLY inline void set_level_gradually(uint8_t lvl) { gradual_target = lvl; } -#ifndef OVERRIDE_GRADUAL_TICK + // call this every frame or every few frames to change brightness very smoothly void gradual_tick() { - // go by only one ramp level at a time instead of directly to the target - uint8_t gt = gradual_target; - if (gt < actual_level) gt = actual_level - 1; - else if (gt > actual_level) gt = actual_level + 1; - - /* - #ifdef LED_ENABLE_PIN_LEVEL_MIN - // only enable during part of the ramp - if ((gt >= LED_ENABLE_PIN_LEVEL_MIN) - && (gt <= LED_ENABLE_PIN_LEVEL_MAX)) - LED_ENABLE_PORT |= (1 << LED_ENABLE_PIN); - else // disable during other parts of the ramp - LED_ENABLE_PORT &= ~(1 << LED_ENABLE_PIN); - #endif - */ + // call the relevant hardware-specific function + GradualTickFuncPtr gradual_tick_func = gradual_tick_modes[channel_mode]; + gradual_tick_func(); +} - gt --; // convert 1-based number to 0-based +// reduce repetition with macros +// common code at the beginning of every gradual tick handler +#define GRADUAL_TICK_SETUP() \ + uint8_t gt = gradual_target; \ + if (gt < actual_level) gt = actual_level - 1; \ + else if (gt > actual_level) gt = actual_level + 1; \ + gt --; \ PWM_DATATYPE target; - #if PWM_CHANNELS >= 1 - target = PWM_GET(pwm1_levels, gt); - #if PWM_CHANNELS > 1 - if ((gt < actual_level) // special case for FET-only turbo - && (PWM1_LVL == 0) // (bypass adjustment period for first step) - && (target == PWM_TOP)) PWM1_LVL = PWM_TOP; - else - #endif - if (PWM1_LVL < target) PWM1_LVL ++; - else if (PWM1_LVL > target) PWM1_LVL --; - #endif - #if PWM_CHANNELS >= 2 - target = PWM_GET(pwm2_levels, gt); - #if PWM_CHANNELS > 2 - if ((gt < actual_level) // special case for FET-only turbo - && (PWM2_LVL == 0) // (bypass adjustment period for first step) - && (target == PWM_TOP)) PWM2_LVL = PWM_TOP; - else - #endif - if (PWM2_LVL < target) PWM2_LVL ++; - else if (PWM2_LVL > target) PWM2_LVL --; - #endif - #if PWM_CHANNELS >= 3 - target = PWM_GET(pwm3_levels, gt); - if (PWM3_LVL < target) PWM3_LVL ++; - else if (PWM3_LVL > target) PWM3_LVL --; - #endif - #if PWM_CHANNELS >= 4 - target = PWM_GET(pwm4_levels, gt); - if (PWM4_LVL < target) PWM4_LVL ++; - else if (PWM4_LVL > target) PWM4_LVL --; - #endif +// tick the top layer of the stack +#define GRADUAL_ADJUST_1CH(TABLE,PWM) \ + target = PWM_GET(TABLE, gt); \ + if (PWM < target) PWM ++; \ + else if (PWM > target) PWM --; + +// tick a base level of the stack +// (with support for special DD FET behavior +// like "low=0, high=255" --> "low=255, high=254") +#define GRADUAL_ADJUST(TABLE,PWM,TOP) \ + target = PWM_GET(TABLE, gt); \ + if ((gt < actual_level) \ + && (PWM == 0) \ + && (target == TOP)) PWM = TOP; \ + else \ + if (PWM < target) PWM ++; \ + else if (PWM > target) PWM --; + +// do this when output exactly matches a ramp level +#define GRADUAL_IS_ACTUAL() \ + uint8_t orig = gradual_target; \ + set_level(gt + 1); \ + gradual_target = orig; + +#ifdef USE_GRADUAL_TICK_1CH +void gradual_tick_1ch() { + GRADUAL_TICK_SETUP(); + + GRADUAL_ADJUST_1CH(low_pwm_levels, LOW_PWM_LVL); // did we go far enough to hit the next defined ramp level? // if so, update the main ramp level tracking var - if ((PWM1_LVL == PWM_GET(pwm1_levels, gt)) - #if PWM_CHANNELS >= 2 - && (PWM2_LVL == PWM_GET(pwm2_levels, gt)) - #endif - #if PWM_CHANNELS >= 3 - && (PWM3_LVL == PWM_GET(pwm3_levels, gt)) - #endif - #if PWM_CHANNELS >= 4 - && (PWM4_LVL == PWM_GET(pwm4_levels, gt)) - #endif + if ((LOW_PWM_LVL == PWM_GET(low_pwm_levels, gt))) + { + GRADUAL_IS_ACTUAL(); + } +} +#endif + +#ifdef USE_GRADUAL_TICK_2CH_STACKED +void gradual_tick_2ch_stacked() { + GRADUAL_TICK_SETUP(); + + GRADUAL_ADJUST(low_pwm_levels, LOW_PWM_LVL, PWM_TOP); + GRADUAL_ADJUST_1CH(high_pwm_levels, HIGH_PWM_LVL); + + // did we go far enough to hit the next defined ramp level? + // if so, update the main ramp level tracking var + if ( (LOW_PWM_LVL == PWM_GET(low_pwm_levels, gt)) + && (HIGH_PWM_LVL == PWM_GET(high_pwm_levels, gt)) + ) + { + GRADUAL_IS_ACTUAL(); + } +} +#endif + +#ifdef USE_GRADUAL_TICK_3CH_STACKED +void gradual_tick_3ch_stacked() { + GRADUAL_TICK_SETUP(); + + GRADUAL_ADJUST(low_pwm_levels, LOW_PWM_LVL, PWM_TOP); + GRADUAL_ADJUST(med_pwm_levels, MED_PWM_LVL, PWM_TOP); + GRADUAL_ADJUST_1CH(high_pwm_levels, HIGH_PWM_LVL); + + // did we go far enough to hit the next defined ramp level? + // if so, update the main ramp level tracking var + if ( (LOW_PWM_LVL == PWM_GET(low_pwm_levels, gt)) + && (MED_PWM_LVL == PWM_GET(med_pwm_levels, gt)) + && (HIGH_PWM_LVL == PWM_GET(high_pwm_levels, gt)) ) { - //actual_level = gt + 1; - uint8_t orig = gradual_target; - set_level(gt + 1); - gradual_target = orig; + GRADUAL_IS_ACTUAL(); } - // is handled in set_level() - //#ifdef USE_TINT_RAMPING - //update_tint(); - //#endif - // is handled in set_level() - //#ifdef USE_DYNAMIC_UNDERCLOCKING - //auto_clock_speed(); - //#endif } -#endif // ifdef OVERRIDE_GRADUAL_TICK +#endif #endif // ifdef USE_SET_LEVEL_GRADUALLY #if defined(USE_TINT_RAMPING) && (!defined(TINT_RAMP_TOGGLE_ONLY)) -void update_tint() { +void set_level_2ch_blend() { #ifndef TINT_RAMPING_CORRECTION #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint #endif @@ -340,7 +443,7 @@ void update_tint() { //PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); uint16_t brightness = PWM1_LVL; uint16_t warm_PWM, cool_PWM; - #ifdef USE_DYN_PWM + #ifdef USE_STACKED_DYN_PWM uint16_t top = PWM1_TOP; //uint16_t top = PWM_GET(pwm_tops, actual_level-1); #else @@ -414,5 +517,12 @@ void update_tint() { #endif // ifdef USE_TINT_RAMPING -#endif // ifdef USE_RAMPING +// define the channel mode lists +// TODO: move to progmem +SetLevelFuncPtr channel_modes[NUM_CHANNEL_MODES] = { SET_LEVEL_MODES }; +#ifdef USE_SET_LEVEL_GRADUALLY +GradualTickFuncPtr gradual_tick_modes[NUM_CHANNEL_MODES] = { GRADUAL_TICK_MODES }; #endif + + +#endif // ifdef USE_RAMPING diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index de090c2..3021ff2 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -18,23 +18,80 @@ * along with this program. If not, see . */ -#ifndef FSM_RAMPING_H -#define FSM_RAMPING_H +#pragma once #ifdef USE_RAMPING // actual_level: last ramp level set by set_level() uint8_t actual_level = 0; -#ifdef USE_TINT_RAMPING -#ifdef TINT_RAMP_TOGGLE_ONLY -uint8_t tint = 0; -#else -uint8_t tint = 128; +// TODO: size-optimize the case with only 1 channel mode +// (the arrays and stuff shouldn't be needed) + +// current multi-channel mode +uint8_t channel_mode = DEFAULT_CHANNEL_MODE; +#ifdef USE_MANUAL_MEMORY +// reset w/ manual memory +uint8_t manual_memory_channel_mode = DEFAULT_CHANNEL_MODE; #endif -#define USE_TRIANGLE_WAVE + +#if NUM_CHANNEL_MODES > 1 +#define USE_CHANNEL_MODES #endif +// one function per channel mode +typedef void SetLevelFunc(uint8_t level); +typedef SetLevelFunc * SetLevelFuncPtr; +// TODO: move to progmem +SetLevelFuncPtr channel_modes[NUM_CHANNEL_MODES]; + +#ifdef USE_SET_LEVEL_GRADUALLY +// the gradual tick mechanism may be different per channel +typedef void GradualTickFunc(); +typedef GradualTickFunc * GradualTickFuncPtr; +// TODO: move to progmem +GradualTickFuncPtr gradual_tick_modes[NUM_CHANNEL_MODES]; +#endif + +#ifdef USE_CUSTOM_CHANNEL_3H_MODES +// different 3H behavior per channel? +// TODO: move to progmem +StatePtr channel_3H_modes[NUM_CHANNEL_MODES]; +#endif + +//#ifdef USE_CHANNEL_MODE_TOGGLES +#if NUM_CHANNEL_MODES > 1 +// user can take unwanted modes out of the rotation +// TODO: save to eeprom +// array +//uint8_t channel_modes_enabled[NUM_CHANNEL_MODES] = { CHANNEL_MODES_ENABLED }; +// bitmask +uint8_t channel_modes_enabled = CHANNEL_MODES_ENABLED; +#define channel_mode_enabled(n) ((channel_modes_enabled >> n) & 1) +#define channel_mode_enable(n) channel_modes_enabled |= (1 << n) +#define channel_mode_disable(n) channel_modes_enabled &= ((1 << n) ^ 0xff) +#endif + +#ifdef USE_CHANNEL_MODE_ARGS +// one byte of extra data per channel mode, like for tint value +uint8_t channel_mode_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; +#endif + +// TODO: remove this after implementing channel modes +//#ifdef USE_TINT_RAMPING +//#ifdef TINT_RAMP_TOGGLE_ONLY +//uint8_t tint = 0; +//#else +//uint8_t tint = 128; +//#endif +//#define USE_TRIANGLE_WAVE +//#endif + +void set_channel_mode(uint8_t mode); + +void set_level(uint8_t level); +//void set_level_smooth(uint8_t level); + #ifdef USE_SET_LEVEL_GRADUALLY // adjust brightness very smoothly uint8_t gradual_target; @@ -42,21 +99,24 @@ inline void set_level_gradually(uint8_t lvl); void gradual_tick(); #endif -#if defined(USE_TINT_RAMPING) && (!defined(TINT_RAMP_TOGGLE_ONLY)) -void update_tint(); -#endif - // auto-detect the data type for PWM tables -#ifndef PWM_BITS - #define PWM_BITS 8 - #define PWM_TOP 255 +// FIXME: PWM bits and data type should be per PWM table +#ifndef PWM1_BITS + #define PWM1_BITS 8 + #define PWM1_TOP 255 + #define STACKED_PWM_TOP 255 #endif #if PWM_BITS <= 8 + #define STACKED_PWM_DATATYPE uint8_t #define PWM_DATATYPE uint8_t #define PWM_DATATYPE2 uint16_t #define PWM_TOP 255 + #define STACKED_PWM_TOP 255 + #ifndef PWM_GET #define PWM_GET(x,y) pgm_read_byte(x+y) + #endif #else + #define STACKED_PWM_DATATYPE uint16_t #define PWM_DATATYPE uint16_t #ifndef PWM_DATATYPE2 #define PWM_DATATYPE2 uint32_t @@ -64,32 +124,55 @@ void update_tint(); #ifndef PWM_TOP #define PWM_TOP 1023 // 10 bits by default #endif + #ifndef STACKED_PWM_TOP + #define STACKED_PWM_TOP 1023 + #endif // pointer plus 2*y bytes //#define PWM_GET(x,y) pgm_read_word(x+(2*y)) // nope, the compiler was already doing the math correctly + #ifndef PWM_GET #define PWM_GET(x,y) pgm_read_word(x+y) + #endif #endif +#define PWM_GET8(x,y) pgm_read_byte(x+y) +#define PWM_GET16(x,y) pgm_read_word(x+y) // use UI-defined ramp tables if they exist #ifdef PWM1_LEVELS -PROGMEM const PWM_DATATYPE pwm1_levels[] = { PWM1_LEVELS }; +PROGMEM const PWM1_DATATYPE pwm1_levels[] = { PWM1_LEVELS }; #endif #ifdef PWM2_LEVELS -PROGMEM const PWM_DATATYPE pwm2_levels[] = { PWM2_LEVELS }; +PROGMEM const PWM2_DATATYPE pwm2_levels[] = { PWM2_LEVELS }; #endif #ifdef PWM3_LEVELS -PROGMEM const PWM_DATATYPE pwm3_levels[] = { PWM3_LEVELS }; +PROGMEM const PWM3_DATATYPE pwm3_levels[] = { PWM3_LEVELS }; +#endif + +// convenience defs for 1 LED with stacked channels +#ifdef LOW_PWM_LEVELS +PROGMEM const PWM_DATATYPE low_pwm_levels[] = { LOW_PWM_LEVELS }; +#endif +#ifdef MED_PWM_LEVELS +PROGMEM const PWM_DATATYPE med_pwm_levels[] = { MED_PWM_LEVELS }; +#endif +#ifdef HIGH_PWM_LEVELS +PROGMEM const PWM_DATATYPE high_pwm_levels[] = { HIGH_PWM_LEVELS }; #endif -#ifdef PWM4_LEVELS -PROGMEM const PWM_DATATYPE pwm4_levels[] = { PWM4_LEVELS }; + +// 2 channel CCT blending ramp +#ifdef BLEND_PWM_LEVELS +PROGMEM const PWM_DATATYPE blend_pwm_levels[] = { BLEND_PWM_LEVELS }; #endif + // pulse frequency modulation, a.k.a. dynamic PWM // (different ceiling / frequency at each ramp level) +// FIXME: dynamic PWM should be a per-channel option, not global #ifdef USE_DYN_PWM PROGMEM const PWM_DATATYPE pwm_tops[] = { PWM_TOPS }; #endif +// FIXME: jump start should be per channel / channel mode #ifdef USE_JUMP_START #ifndef JUMP_START_TIME #define JUMP_START_TIME 8 // in ms, should be 4, 8, or 12 @@ -100,78 +183,11 @@ PROGMEM const PWM_DATATYPE pwm_tops[] = { PWM_TOPS }; uint8_t jump_start_level = DEFAULT_JUMP_START_LEVEL; #endif -// default / example ramps -#ifndef PWM1_LEVELS -#if PWM_CHANNELS == 1 - #if RAMP_LENGTH == 50 - // ../../bin/level_calc.py 1 50 7135 3 0.25 980 - PROGMEM const PWM_DATATYPE pwm1_levels[] = { 3,3,3,3,4,4,4,5,5,6,7,8,9,11,12,14,16,18,20,23,25,28,32,35,39,43,47,52,57,62,68,74,80,87,94,102,110,118,127,136,146,156,167,178,189,201,214,227,241,255 }; - #elif RAMP_LENGTH == 75 - // ../../bin/level_calc.py 1 75 7135 3 0.25 980 - PROGMEM const PWM_DATATYPE pwm1_levels[] = { 3,3,3,3,3,3,4,4,4,4,5,5,5,6,6,7,8,8,9,10,11,12,13,14,15,17,18,20,21,23,25,27,29,31,33,36,38,41,44,47,50,53,56,59,63,67,71,75,79,83,88,93,98,103,108,113,119,125,131,137,143,150,157,164,171,178,186,194,202,210,219,227,236,246,255 }; - #elif RAMP_LENGTH == 150 - // ../../bin/level_calc.py 1 150 7135 3 0.25 980 - PROGMEM const PWM_DATATYPE pwm1_levels[] = { 3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,6,6,6,6,7,7,7,8,8,8,9,9,9,10,10,11,11,12,12,13,13,14,15,15,16,17,17,18,19,19,20,21,22,23,24,24,25,26,27,28,29,31,32,33,34,35,36,38,39,40,42,43,44,46,47,49,50,52,53,55,57,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,89,91,93,96,98,101,103,106,109,111,114,117,120,123,125,128,131,134,138,141,144,147,151,154,157,161,164,168,171,175,179,183,186,190,194,198,202,206,210,215,219,223,228,232,236,241,246,250,255 }; - #endif -#elif PWM_CHANNELS == 2 - #if RAMP_LENGTH == 50 - // ../../bin/level_calc.py 2 50 7135 4 0.33 150 FET 1 10 1500 - PROGMEM const PWM_DATATYPE pwm1_levels[] = { 4,5,6,8,10,13,17,22,28,35,44,54,65,78,93,109,128,149,171,197,224,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 }; - PROGMEM const PWM_DATATYPE pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,7,11,15,20,26,31,37,44,51,58,65,73,82,91,100,110,121,132,143,155,168,181,194,209,224,239,255 }; - #define MAX_1x7135 22 - #elif RAMP_LENGTH == 75 - // ../../bin/level_calc.py 2 75 7135 4 0.33 150 FET 1 10 1500 - PROGMEM const PWM_DATATYPE pwm1_levels[] = { 4,4,5,6,7,8,10,12,14,17,20,24,28,32,37,43,49,56,64,72,82,91,102,114,126,139,153,168,184,202,220,239,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 }; - PROGMEM const PWM_DATATYPE pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,5,7,10,13,16,19,23,26,30,34,38,42,47,51,56,61,66,72,77,83,89,95,101,108,115,122,129,136,144,152,160,168,177,186,195,204,214,224,234,244,255 }; - #define MAX_1x7135 33 - #elif RAMP_LENGTH == 150 - // ../../bin/level_calc.py 1 65 7135 1 0.8 150 - // ... mixed with this: - // ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 - PROGMEM const PWM_DATATYPE pwm1_levels[] = { 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 }; - PROGMEM const PWM_DATATYPE pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 }; - #define MAX_1x7135 65 - #define HALFSPEED_LEVEL 14 - #define QUARTERSPEED_LEVEL 5 - #endif -#elif PWM_CHANNELS == 3 - #if RAMP_LENGTH == 50 - // ../../bin/level_calc.py 3 50 7135 4 0.33 150 7135 4 1 840 FET 1 10 2000 - PROGMEM const PWM_DATATYPE pwm1_levels[] = { 4,5,6,8,11,15,20,26,34,43,54,67,82,99,118,140,165,192,221,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 }; - PROGMEM const PWM_DATATYPE pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,17,25,33,42,52,62,73,85,97,111,125,140,157,174,192,210,230,251,255,255,255,255,255,255,255,255,255,255,0 }; - PROGMEM const PWM_DATATYPE pwm3_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,34,54,76,98,122,146,172,198,226,255 }; - #define MAX_1x7135 20 - #define MAX_Nx7135 39 - #elif RAMP_LENGTH == 75 - // ../../bin/level_calc.py 3 75 7135 4 0.33 150 7135 4 1 840 FET 1 10 2000 - PROGMEM const PWM_DATATYPE pwm1_levels[] = { 4,4,5,6,7,9,11,14,16,20,24,28,34,40,46,54,62,71,81,92,104,117,130,146,162,179,198,218,239,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 }; - PROGMEM const PWM_DATATYPE pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,9,14,18,23,29,34,40,47,53,60,67,75,83,91,99,108,117,127,137,148,158,170,181,193,206,219,232,246,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 }; - PROGMEM const PWM_DATATYPE pwm3_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,15,28,42,55,70,84,99,115,131,147,164,181,199,217,236,255 }; - #define MAX_1x7135 30 - #define MAX_Nx7135 59 - #elif RAMP_LENGTH == 150 - // ../../bin/level_calc.py 1 65 7135 1 0.8 150 - // ... mixed with this: - // ../../../bin/level_calc.py 3 150 7135 1 0.33 150 7135 1 1 850 FET 1 10 1500 - PROGMEM const PWM_DATATYPE pwm1_levels[] = { 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 }; - PROGMEM const PWM_DATATYPE pwm2_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,8,10,13,15,17,19,22,24,26,29,31,34,37,39,42,45,48,51,54,57,60,64,67,70,74,77,81,85,88,92,96,100,104,108,112,116,121,125,130,134,139,143,148,153,158,163,168,173,179,184,189,195,201,206,212,218,224,230,236,243,249,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 }; - PROGMEM const PWM_DATATYPE pwm3_levels[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,19,31,43,55,67,79,91,104,117,130,143,157,170,184,198,212,226,240,255 }; - #define MAX_1x7135 65 - #define MAX_Nx7135 130 - #define HALFSPEED_LEVEL 14 - #define QUARTERSPEED_LEVEL 5 - #endif -#elif PWM_CHANNELS == 4 - 4-channel PWM not really supported yet, sorry. -#endif -#endif - // RAMP_SIZE / MAX_LVL -#define RAMP_SIZE (sizeof(pwm1_levels)/sizeof(PWM_DATATYPE)) +// cfg-*.h should define RAMP_SIZE +//#define RAMP_SIZE (sizeof(stacked_pwm1_levels)/sizeof(STACKED_PWM_DATATYPE)) #define MAX_LEVEL RAMP_SIZE -void set_level(uint8_t level); -//void set_level_smooth(uint8_t level); #endif // ifdef USE_RAMPING -#endif + diff --git a/spaghetti-monster/fsm-states.h b/spaghetti-monster/fsm-states.h index 9964bc1..2c51d0a 100644 --- a/spaghetti-monster/fsm-states.h +++ b/spaghetti-monster/fsm-states.h @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef FSM_STATES_H #define FSM_STATES_H -- cgit v1.2.3 From f8e1150ba52fb3128d452e68ae2d8dda97a53ff1 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 14 Apr 2023 18:01:03 -0600 Subject: LT1S Pro: added dynamic PWM (much better low modes!) --- hwdef-Sofirn_LT1S-Pro.c | 114 +++++++++++++++++++++--- hwdef-Sofirn_LT1S-Pro.h | 75 ++++++++++------ spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 39 ++++---- spaghetti-monster/anduril/channel-modes.h | 1 - spaghetti-monster/fsm-ramping.h | 2 +- 5 files changed, 168 insertions(+), 63 deletions(-) diff --git a/hwdef-Sofirn_LT1S-Pro.c b/hwdef-Sofirn_LT1S-Pro.c index 3c31c96..61d2157 100644 --- a/hwdef-Sofirn_LT1S-Pro.c +++ b/hwdef-Sofirn_LT1S-Pro.c @@ -5,22 +5,105 @@ #pragma once -// "auto tint" channel mode -void set_level_auto_3ch_blend(uint8_t level) { - BLEND_PWM_DATATYPE vpwm; - +// single set of LEDs with 1 power channel and dynamic PWM +void set_level_1ch_dyn(uint8_t level) { if (level == 0) { - vpwm = 0; + RED_PWM_LVL = 0; + PWM_CNT = 0; // reset phase } else { level --; // PWM array index = level - 1 - vpwm = PWM_GET(blend_pwm_levels, level); + RED_PWM_LVL = PWM_GET(pwm1_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + PWM_TOP = PWM_GET(pwm_tops, level); + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; + } +} + + +// warm + cool blend w/ middle sag correction and dynamic PWM +void set_level_2ch_dyn_blend(uint8_t level) { + #ifndef TINT_RAMPING_CORRECTION + #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint + #endif + + if (level == 0) { + WARM_PWM_LVL = 0; + COOL_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + return; + } + + level --; // PWM array index = level - 1 + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + uint16_t top = PWM_GET(pwm_tops, level); + + // calculate actual PWM levels based on a single-channel ramp + // and a global tint value + uint16_t warm_PWM, cool_PWM; + uint8_t mytint = channel_mode_args[channel_mode]; + + PWM_DATATYPE2 base_PWM = brightness; + #if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0) + // middle tints sag, so correct for that effect + // by adding extra power which peaks at the middle tint + // (correction is only necessary when PWM is fast) + if (level > HALFSPEED_LEVEL) { + base_PWM = brightness + + ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64) + * triangle_wave(mytint) / 255); + } + // fade the triangle wave out when above 100% power, + // so it won't go over 200% + if (brightness > top) { + base_PWM -= 2 * ( + ((brightness - top) * TINT_RAMPING_CORRECTION / 64) + * triangle_wave(mytint) / 255 + ); + } + // guarantee no more than 200% power + if (base_PWM > (top << 1)) { base_PWM = top << 1; } + #endif + + cool_PWM = (((PWM_DATATYPE2)mytint * (PWM_DATATYPE2)base_PWM) + 127) / 255; + warm_PWM = base_PWM - cool_PWM; + // when running at > 100% power, spill extra over to other channel + if (cool_PWM > top) { + warm_PWM += (cool_PWM - top); + cool_PWM = top; + } else if (warm_PWM > top) { + cool_PWM += (warm_PWM - top); + warm_PWM = top; + } + + WARM_PWM_LVL = warm_PWM; + COOL_PWM_LVL = cool_PWM; + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; // reset phase +} + + +// "auto tint" channel mode with dynamic PWM +void set_level_auto_3ch_dyn_blend(uint8_t level) { + if (level == 0) { + WARM_PWM_LVL = 0; + COOL_PWM_LVL = 0; + RED_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + return; } + level --; // PWM array index = level - 1 + PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET(pwm_tops, level); + // tint goes from 0 (red) to 127 (warm white) to 255 (cool white) uint8_t mytint; mytint = 255 * (uint16_t)level / RAMP_SIZE; - BLEND_PWM_DATATYPE a, b, c; + PWM_DATATYPE a, b, c; // red is high at 0, low at 255 a = (((PWM_DATATYPE2)(255 - mytint) @@ -35,6 +118,8 @@ void set_level_auto_3ch_blend(uint8_t level) { RED_PWM_LVL = a; WARM_PWM_LVL = b; COOL_PWM_LVL = c; + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; } @@ -42,19 +127,19 @@ void set_level_auto_3ch_blend(uint8_t level) { void set_level_red_white_blend(uint8_t level) { // set the warm+cool white LEDs first channel_mode = CM_WHITE; - set_level_2ch_blend(level); + set_level_2ch_dyn_blend(level); channel_mode = CM_WHITE_RED; - BLEND_PWM_DATATYPE vpwm; - // set the red LED as a ratio of the white output level if (level == 0) { - vpwm = 0; - } else { - level --; // PWM array index = level - 1 - vpwm = PWM_GET(blend_pwm_levels, level); + RED_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + return; } + level --; // PWM array index = level - 1 + PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level); + // 0 = no red // 255 = red at 100% of white channel PWM uint8_t ratio = channel_mode_args[channel_mode]; @@ -63,5 +148,6 @@ void set_level_red_white_blend(uint8_t level) { red_pwm = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)vpwm) + 127) / 255; RED_PWM_LVL = red_pwm; + if (! actual_level) PWM_CNT = 0; // reset phase } diff --git a/hwdef-Sofirn_LT1S-Pro.h b/hwdef-Sofirn_LT1S-Pro.h index c52364f..c994d09 100644 --- a/hwdef-Sofirn_LT1S-Pro.h +++ b/hwdef-Sofirn_LT1S-Pro.h @@ -15,9 +15,6 @@ Driver pinout: #define HWDEF_C_FILE hwdef-Sofirn_LT1S-Pro.c -#ifdef ATTINY -#undef ATTINY -#endif #define ATTINY 1616 #include @@ -39,20 +36,21 @@ Driver pinout: // TODO: blend mode should enable this automatically? #define USE_CHANNEL_MODE_ARGS // TODO: or maybe if args are defined, the USE_ should be auto-set? +// 128=middle CCT, N/A, N/A, 255=100% red #define CHANNEL_MODE_ARGS 128,0,0,255 -#define SET_LEVEL_MODES set_level_2ch_blend, \ - set_level_auto_3ch_blend, \ - set_level_1ch, \ +#define SET_LEVEL_MODES set_level_2ch_dyn_blend, \ + set_level_auto_3ch_dyn_blend, \ + set_level_1ch_dyn, \ set_level_red_white_blend // TODO: gradual ticking for thermal regulation #define GRADUAL_TICK_MODES gradual_tick_2ch_blend, \ gradual_tick_auto_3ch_blend, \ gradual_tick_1ch, \ gradual_tick_red_white_blend -// can use some of the common handlers -#define USE_SET_LEVEL_2CH_BLEND +// can use some of the common handlers? +//#define USE_SET_LEVEL_2CH_BLEND //#define USE_SET_LEVEL_AUTO_3CH_BLEND -#define USE_SET_LEVEL_1CH +//#define USE_SET_LEVEL_1CH //#define USE_SET_LEVEL_RED_WHITE_BLEND // TODO: //#define USE_GRADUAL_TICK_2CH_BLEND @@ -78,27 +76,30 @@ Driver pinout: #define SWITCH_INTFLG VPORTA.INTFLAGS +// dynamic PWM +// PWM parameters of all channels are tied together because they share a counter +#define PWM_TOP_INIT 511 // highest value used in the top half of the ramp +#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM +#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment + // warm tint channel -#define WARM_PWM_PIN PB0 -#define WARM_PWM_LVL TCA0.SINGLE.CMP0 // CMP1 is the output compare register for PB0 +//#define WARM_PWM_PIN PB0 +#define WARM_PWM_LVL TCA0.SINGLE.CMP0BUF // CMP1 is the output compare register for PB0 // cold tint channel -#define COOL_PWM_PIN PB1 -#define COOL_PWM_LVL TCA0.SINGLE.CMP1 // CMP0 is the output compare register for PB1 +//#define COOL_PWM_PIN PB1 +#define COOL_PWM_LVL TCA0.SINGLE.CMP1BUF // CMP0 is the output compare register for PB1 // red channel -#define RED_PWM_PIN PB0 // -#define RED_PWM_LVL TCA0.SINGLE.CMP2 // CMP2 is the output compare register for PB2 - -// translate cfg names to FSM names -#define LOW_PWM_LEVELS RED_PWM_LEVELS -#define LOW_PWM_LVL RED_PWM_LVL -#define LOW_PWM_PIN RED_PWM_PIN +//#define RED_PWM_PIN PB2 +#define RED_PWM_LVL TCA0.SINGLE.CMP2BUF // CMP2 is the output compare register for PB2 -// only using 8-bit on this light -#define PWM_GET PWM_GET8 -#define PWM_DATATYPE uint8_t -#define BLEND_PWM_DATATYPE uint8_t +// only using 16-bit PWM on this light +#define PWM_BITS 16 +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM1_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // average drop across diode on this hardware @@ -118,7 +119,9 @@ Driver pinout: // custom channel modes -void set_level_auto_3ch_blend(uint8_t level); +void set_level_1ch_dyn(uint8_t level); +void set_level_2ch_dyn_blend(uint8_t level); +void set_level_auto_3ch_dyn_blend(uint8_t level); void set_level_red_white_blend(uint8_t level); @@ -128,7 +131,11 @@ inline void hwdef_setup() { _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); //VPORTA.DIR = ...; - VPORTB.DIR = PIN0_bm | PIN1_bm | PIN2_bm | PIN5_bm; // Outputs: Aux LED and PWMs + // Outputs: + VPORTB.DIR = PIN0_bm // warm white + | PIN1_bm // cool white + | PIN2_bm // red + | PIN5_bm; // aux LED //VPORTC.DIR = ...; // enable pullups on the unused pins to reduce power @@ -154,10 +161,20 @@ inline void hwdef_setup() { PORTC.PIN3CTRL = PORT_PULLUPEN_bm; // set up the PWM + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf + // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm + // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm + // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm + // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc + // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc // TODO: add references to MCU documentation - TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_CMP2EN_bm | TCA_SINGLE_WGMODE_DSBOTTOM_gc; - TCA0.SINGLE.PER = 255; - TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm + | TCA_SINGLE_CMP1EN_bm + | TCA_SINGLE_CMP2EN_bm + | TCA_SINGLE_WGMODE_DSBOTTOM_gc; + PWM_TOP = PWM_TOP_INIT; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc + | TCA_SINGLE_ENABLE_bm; } diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index e009e02..c9e786d 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -4,31 +4,32 @@ #include "hwdef-Sofirn_LT1S-Pro.h" // ATTINY: 1616 -// off mode: high (1) +// off mode: high (2) // lockout: blinking (3) -#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2) -// the lantern has two PWM channels, but they drive different sets of emitters -// (one channel for warm emitters, one channel for cold) -// so enable a special ramping mode which changes tint instead of brightness -//#define USE_TINT_RAMPING // how much to increase total brightness at middle tint // (0 = 100% brightness, 64 = 200% brightness) -#define TINT_RAMPING_CORRECTION 10 // 115% +// seems unnecessary on this light +#define TINT_RAMPING_CORRECTION 0 -// level_calc.py 1 150 7135 1 30 800 #define RAMP_SIZE 150 -// TODO: use dynamic PWM instead of plain 8-bit +// TODO? 200% power at top of ramp on white blend mode +// use dynamic PWM instead of plain 8-bit // (so we can get lower lows and a smoother ramp) -// TODO: 200% power at top of ramp on white blend mode -#define PWM_LEVELS 1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,11,11,12,13,13,14,15,15,16,17,18,18,19,20,21,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,43,44,45,46,48,49,50,51,53,54,56,57,58,60,61,63,64,66,67,69,70,72,74,75,77,79,80,82,84,85,87,89,91,93,95,97,98,100,102,104,106,108,111,113,115,117,119,121,124,126,128,130,133,135,137,140,142,145,147,150,152,155,157,160,163,165,168,171,173,176,179,182,185,188,190,193,196,199,202,205,209,212,215,218,221,224,228,231,234,238,241,245,248,251,255 -#define BLEND_PWM_LEVELS PWM_LEVELS -#define RED_PWM_LEVELS PWM_LEVELS -#define MAX_1x7135 65 +// level_calc.py 5.99 1 150 7135 1 0.2 600 --pwm dyn:74:16383:511 +// (with a few manual tweaks at the mid-point) +#define PWM_LEVELS 1,1,2,3,3,4,5,6,7,8,9,10,11,13,14,16,17,19,20,22,24,26,28,30,32,34,36,38,41,43,46,48,51,54,56,59,62,65,67,70,73,76,79,82,84,87,90,92,95,97,99,101,103,105,106,107,108,108,109,108,108,107,105,103,101,97,93,89,83,77,70,62,53,43,36,37,38,39,40,42,44,46,48,50,52,54,56,58,60,63,65,68,71,74,77,80,83,87,90,94,98,101,105,109,114,118,123,127,132,137,142,147,153,158,164,170,176,183,189,196,203,210,217,224,232,240,248,257,265,274,283,293,302,312,322,333,343,354,366,377,389,401,414,427,440,453,467,481,496,511 +#define PWM_TOPS 16383,11015,13411,15497,11274,12834,13512,13749,13735,13565,13292,12948,12555,13284,12747,13087,12495,12621,12010,12007,11928,11790,11609,11395,11155,10895,10622,10338,10307,9996,9905,9581,9452,9302,8973,8806,8627,8440,8124,7935,7743,7549,7354,7159,6883,6696,6511,6260,6084,5851,5628,5414,5210,5014,4782,4562,4355,4120,3937,3694,3501,3288,3060,2848,2651,2418,2202,2003,1775,1566,1353,1140,926,713,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511 +// shared table for white and red +#define PWM1_LEVELS PWM_LEVELS +#define MAX_1x7135 75 // FIXME: clock at 5 MHz w/ full+half+quarter speeds, // instead of 10 MHz with w/ only half+quarter // (10 MHz is just wasting power) -#define HALFSPEED_LEVEL 256 // red LEDs use a QX7138 chip which has max PWM speed of 10 kHz, so never run faster than halfspeed +// red LEDs use a QX7138 chip which has max PWM speed of 10 kHz, +// so PWM is 512 clock cycles long to avoid running faster than that +#define HALFSPEED_LEVEL 12 #define QUARTERSPEED_LEVEL 5 // the default of 26 looks a bit flat, so increase it @@ -41,16 +42,18 @@ // because this lantern isn't overpowered #define RAMP_SMOOTH_FLOOR 1 #define RAMP_SMOOTH_CEIL 150 -#define RAMP_DISCRETE_FLOOR 10 +//#define RAMP_DISCRETE_FLOOR 17 // 17 50 83 116 150 +#define RAMP_DISCRETE_FLOOR 1 // 1 25 50 75 100 125 150 #define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 5 +#define RAMP_DISCRETE_STEPS 7 // LT1S can handle heat well, so don't limit simple mode +//#define SIMPLE_UI_FLOOR 10 // 10 45 80 115 150 #define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR #define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL #define SIMPLE_UI_STEPS RAMP_DISCRETE_STEPS -// Allow 3C in Simple UI for switching between smooth and stepped ramping +// Allow 3C (or 6C) in Simple UI (toggle smooth or stepped ramping) #define USE_SIMPLE_UI_RAMPING_TOGGLE // allow Aux Config and Strobe Modes in Simple UI diff --git a/spaghetti-monster/anduril/channel-modes.h b/spaghetti-monster/anduril/channel-modes.h index f536d58..167c293 100644 --- a/spaghetti-monster/anduril/channel-modes.h +++ b/spaghetti-monster/anduril/channel-modes.h @@ -7,7 +7,6 @@ #pragma once #if defined(USE_MANUAL_MEMORY) && defined(USE_CHANNEL_MODE_ARGS) -// TODO: save to eeprom // remember and reset 1 extra parameter per channel mode (like tint) uint8_t manual_memory_channel_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; #endif diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 3021ff2..028157f 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -168,7 +168,7 @@ PROGMEM const PWM_DATATYPE blend_pwm_levels[] = { BLEND_PWM_LEVELS }; // pulse frequency modulation, a.k.a. dynamic PWM // (different ceiling / frequency at each ramp level) // FIXME: dynamic PWM should be a per-channel option, not global -#ifdef USE_DYN_PWM +#ifdef PWM_TOPS PROGMEM const PWM_DATATYPE pwm_tops[] = { PWM_TOPS }; #endif -- cgit v1.2.3 From 04ae99c89c7032db1c7cda524c27bf14d929d336 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 14 Apr 2023 18:43:09 -0600 Subject: LT1S Pro: after measuring, perhaps low aux mode is better after all --- spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index c9e786d..fb412a6 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -4,9 +4,17 @@ #include "hwdef-Sofirn_LT1S-Pro.h" // ATTINY: 1616 -// off mode: high (2) +// off mode: low (1) // lockout: blinking (3) -#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2) +// Standby power usage: +// - aux high: 6.9 mA (30 days) +// - aux low: 0.16 mA (3.5 years) +// - red moon: 2.17 mA (96 days) +// - white moon: 1.47 mA (141 days) +// Low mode isn't bright enough to be useful on this light, +// but at least it doesn't drain the battery 3X faster than moon mode. +// (it seriously would be more practical to just use moon instead) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) // how much to increase total brightness at middle tint // (0 = 100% brightness, 64 = 200% brightness) -- cgit v1.2.3 From 6142f73db27cef29246291fd09227cc7bc3d4b15 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 14 Apr 2023 20:51:40 -0600 Subject: LT1S: added thermal regulation ... and a bunch of gradual_tick functions ... and abstracted out some of the tint calculations ... and moved some UI settings into cfg.h --- hwdef-Sofirn_LT1S-Pro.c | 234 ++++++++++++++++++------ hwdef-Sofirn_LT1S-Pro.h | 44 ++--- spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 16 +- spaghetti-monster/fsm-ramping.c | 33 ---- spaghetti-monster/fsm-ramping.h | 41 ++++- 5 files changed, 243 insertions(+), 125 deletions(-) diff --git a/hwdef-Sofirn_LT1S-Pro.c b/hwdef-Sofirn_LT1S-Pro.c index 61d2157..a6d2b8f 100644 --- a/hwdef-Sofirn_LT1S-Pro.c +++ b/hwdef-Sofirn_LT1S-Pro.c @@ -5,68 +5,51 @@ #pragma once -// single set of LEDs with 1 power channel and dynamic PWM -void set_level_1ch_dyn(uint8_t level) { - if (level == 0) { - RED_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - } else { - level --; // PWM array index = level - 1 - RED_PWM_LVL = PWM_GET(pwm1_levels, level); - // pulse frequency modulation, a.k.a. dynamic PWM - PWM_TOP = PWM_GET(pwm_tops, level); - // force reset phase when turning on from zero - // (because otherwise the initial response is inconsistent) - if (! actual_level) PWM_CNT = 0; - } -} +// calculate a "tint ramp" blend between 2 channels +// results are placed in *warm and *cool vars +// brightness : total amount of light units to distribute +// top : maximum allowed brightness per channel +// blend : ratio between warm and cool (0 = warm, 128 = 50%, 255 = cool) +void calc_2ch_blend( + PWM_DATATYPE *warm, + PWM_DATATYPE *cool, + PWM_DATATYPE brightness, + PWM_DATATYPE top, + uint8_t blend) { - -// warm + cool blend w/ middle sag correction and dynamic PWM -void set_level_2ch_dyn_blend(uint8_t level) { #ifndef TINT_RAMPING_CORRECTION #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint #endif - if (level == 0) { - WARM_PWM_LVL = 0; - COOL_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); - uint16_t top = PWM_GET(pwm_tops, level); - // calculate actual PWM levels based on a single-channel ramp - // and a global tint value - uint16_t warm_PWM, cool_PWM; - uint8_t mytint = channel_mode_args[channel_mode]; - + // and a blend value + PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE2 base_PWM = brightness; + #if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0) + uint8_t level = actual_level - 1; + // middle tints sag, so correct for that effect // by adding extra power which peaks at the middle tint // (correction is only necessary when PWM is fast) if (level > HALFSPEED_LEVEL) { base_PWM = brightness + ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64) - * triangle_wave(mytint) / 255); + * triangle_wave(blend) / 255); } // fade the triangle wave out when above 100% power, // so it won't go over 200% if (brightness > top) { base_PWM -= 2 * ( ((brightness - top) * TINT_RAMPING_CORRECTION / 64) - * triangle_wave(mytint) / 255 + * triangle_wave(blend) / 255 ); } // guarantee no more than 200% power if (base_PWM > (top << 1)) { base_PWM = top << 1; } #endif - cool_PWM = (((PWM_DATATYPE2)mytint * (PWM_DATATYPE2)base_PWM) + 127) / 255; + cool_PWM = (((PWM_DATATYPE2)blend * (PWM_DATATYPE2)base_PWM) + 127) / 255; warm_PWM = base_PWM - cool_PWM; // when running at > 100% power, spill extra over to other channel if (cool_PWM > top) { @@ -77,6 +60,76 @@ void set_level_2ch_dyn_blend(uint8_t level) { warm_PWM = top; } + *warm = warm_PWM; + *cool = cool_PWM; +} + + +// calculate a 3-channel "auto tint" blend +// (like red -> warm white -> cool white) +// results are placed in *a, *b, and *c vars +// level : ramp level to convert into 3 channel levels +// (assumes ramp table is "pwm1_levels") +void calc_auto_3ch_blend( + PWM_DATATYPE *a, + PWM_DATATYPE *b, + PWM_DATATYPE *c, + uint8_t level) { + + PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level); + + // tint goes from 0 (red) to 127 (warm white) to 255 (cool white) + uint8_t mytint; + mytint = 255 * (uint16_t)level / RAMP_SIZE; + + // red is high at 0, low at 255 (linear) + *a = (((PWM_DATATYPE2)(255 - mytint) + * (PWM_DATATYPE2)vpwm) + 127) / 255; + // warm white is low at 0 and 255, high at 127 (linear triangle) + *b = (((PWM_DATATYPE2)triangle_wave(mytint) + * (PWM_DATATYPE2)vpwm) + 127) / 255; + // cool white is low at 0, high at 255 (linear) + *c = (((PWM_DATATYPE2)mytint + * (PWM_DATATYPE2)vpwm) + 127) / 255; + +} + + +// single set of LEDs with 1 power channel and dynamic PWM +void set_level_red(uint8_t level) { + if (level == 0) { + RED_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + } else { + level --; // PWM array index = level - 1 + RED_PWM_LVL = PWM_GET(pwm1_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + PWM_TOP = PWM_GET(pwm_tops, level); + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; + } +} + + +// warm + cool blend w/ dynamic PWM +void set_level_white_blend(uint8_t level) { + if (level == 0) { + WARM_PWM_LVL = 0; + COOL_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + return; + } + + level --; // PWM array index = level - 1 + + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + PWM_DATATYPE top = PWM_GET(pwm_tops, level); + uint8_t blend = channel_mode_args[channel_mode]; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + WARM_PWM_LVL = warm_PWM; COOL_PWM_LVL = cool_PWM; PWM_TOP = top; @@ -85,7 +138,7 @@ void set_level_2ch_dyn_blend(uint8_t level) { // "auto tint" channel mode with dynamic PWM -void set_level_auto_3ch_dyn_blend(uint8_t level) { +void set_level_auto_3ch_blend(uint8_t level) { if (level == 0) { WARM_PWM_LVL = 0; COOL_PWM_LVL = 0; @@ -95,25 +148,12 @@ void set_level_auto_3ch_dyn_blend(uint8_t level) { } level --; // PWM array index = level - 1 - PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level); - // pulse frequency modulation, a.k.a. dynamic PWM - uint16_t top = PWM_GET(pwm_tops, level); - - // tint goes from 0 (red) to 127 (warm white) to 255 (cool white) - uint8_t mytint; - mytint = 255 * (uint16_t)level / RAMP_SIZE; PWM_DATATYPE a, b, c; + calc_auto_3ch_blend(&a, &b, &c, level); - // red is high at 0, low at 255 - a = (((PWM_DATATYPE2)(255 - mytint) - * (PWM_DATATYPE2)vpwm) + 127) / 255; - // warm white is low at 0 and 255, high at 127 - b = (((PWM_DATATYPE2)triangle_wave(mytint) - * (PWM_DATATYPE2)vpwm) + 127) / 255; - // cool white is low at 0, high at 255 - c = (((PWM_DATATYPE2)mytint - * (PWM_DATATYPE2)vpwm) + 127) / 255; + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET(pwm_tops, level); RED_PWM_LVL = a; WARM_PWM_LVL = b; @@ -127,10 +167,9 @@ void set_level_auto_3ch_dyn_blend(uint8_t level) { void set_level_red_white_blend(uint8_t level) { // set the warm+cool white LEDs first channel_mode = CM_WHITE; - set_level_2ch_dyn_blend(level); + set_level_white_blend(level); channel_mode = CM_WHITE_RED; - // set the red LED as a ratio of the white output level if (level == 0) { RED_PWM_LVL = 0; PWM_CNT = 0; // reset phase @@ -140,14 +179,91 @@ void set_level_red_white_blend(uint8_t level) { level --; // PWM array index = level - 1 PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level); + // set the red LED as a ratio of the white output level // 0 = no red // 255 = red at 100% of white channel PWM uint8_t ratio = channel_mode_args[channel_mode]; - PWM_DATATYPE red_pwm; - red_pwm = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)vpwm) + 127) / 255; - - RED_PWM_LVL = red_pwm; + RED_PWM_LVL = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)vpwm) + 127) / 255; if (! actual_level) PWM_CNT = 0; // reset phase } + +///// "gradual tick" functions for smooth thermal regulation ///// + +void gradual_tick_red() { + GRADUAL_TICK_SETUP(); + + GRADUAL_ADJUST_1CH(pwm1_levels, RED_PWM_LVL); + + if ((RED_PWM_LVL == PWM_GET(pwm1_levels, gt))) + { + GRADUAL_IS_ACTUAL(); + } +} + + +void gradual_tick_white_blend() { + uint8_t gt = gradual_target; + if (gt < actual_level) gt = actual_level - 1; + else if (gt > actual_level) gt = actual_level + 1; + gt --; + + // figure out what exact PWM levels we're aiming for + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE top = PWM_GET(pwm_tops, gt); + uint8_t blend = channel_mode_args[channel_mode]; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + + // move up/down if necessary + GRADUAL_ADJUST_SIMPLE(warm_PWM, WARM_PWM_LVL); + GRADUAL_ADJUST_SIMPLE(cool_PWM, COOL_PWM_LVL); + + // check for completion + if ( (WARM_PWM_LVL == warm_PWM) + && (COOL_PWM_LVL == cool_PWM) + ) + { + GRADUAL_IS_ACTUAL(); + } +} + + +void gradual_tick_auto_3ch_blend() { + uint8_t gt = gradual_target; + if (gt < actual_level) gt = actual_level - 1; + else if (gt > actual_level) gt = actual_level + 1; + gt --; + + // figure out what exact PWM levels we're aiming for + PWM_DATATYPE red, warm, cool; + calc_auto_3ch_blend(&red, &warm, &cool, gt); + + // move up/down if necessary + GRADUAL_ADJUST_SIMPLE(red, RED_PWM_LVL); + GRADUAL_ADJUST_SIMPLE(warm, WARM_PWM_LVL); + GRADUAL_ADJUST_SIMPLE(cool, COOL_PWM_LVL); + + // check for completion + if ( (RED_PWM_LVL == red) + && (WARM_PWM_LVL == warm) + && (COOL_PWM_LVL == cool) + ) + { + GRADUAL_IS_ACTUAL(); + } +} + + +void gradual_tick_red_white_blend() { + // do the white blend thing... + channel_mode = CM_WHITE; + gradual_tick_white_blend(); + channel_mode = CM_WHITE_RED; + // ... and then update red to the closest ramp level + // (coarse red adjustments aren't visible here anyway) + set_level_red(actual_level); +} + diff --git a/hwdef-Sofirn_LT1S-Pro.h b/hwdef-Sofirn_LT1S-Pro.h index c994d09..84623fd 100644 --- a/hwdef-Sofirn_LT1S-Pro.h +++ b/hwdef-Sofirn_LT1S-Pro.h @@ -38,33 +38,18 @@ Driver pinout: // TODO: or maybe if args are defined, the USE_ should be auto-set? // 128=middle CCT, N/A, N/A, 255=100% red #define CHANNEL_MODE_ARGS 128,0,0,255 -#define SET_LEVEL_MODES set_level_2ch_dyn_blend, \ - set_level_auto_3ch_dyn_blend, \ - set_level_1ch_dyn, \ +#define SET_LEVEL_MODES set_level_white_blend, \ + set_level_auto_3ch_blend, \ + set_level_red, \ set_level_red_white_blend -// TODO: gradual ticking for thermal regulation -#define GRADUAL_TICK_MODES gradual_tick_2ch_blend, \ +// gradual ticking for thermal regulation +#define GRADUAL_TICK_MODES gradual_tick_white_blend, \ gradual_tick_auto_3ch_blend, \ - gradual_tick_1ch, \ + gradual_tick_red, \ gradual_tick_red_white_blend -// can use some of the common handlers? -//#define USE_SET_LEVEL_2CH_BLEND -//#define USE_SET_LEVEL_AUTO_3CH_BLEND -//#define USE_SET_LEVEL_1CH -//#define USE_SET_LEVEL_RED_WHITE_BLEND -// TODO: -//#define USE_GRADUAL_TICK_2CH_BLEND -//#define USE_GRADUAL_TICK_AUTO_3CH_BLEND -//#define USE_GRADUAL_TICK_1CH -//#define USE_GRADUAL_TICK_RED_WHITE_BLEND - -#define DEFAULT_CHANNEL_MODE CM_AUTO - -#define FACTORY_RESET_WARN_CHANNEL CM_RED -#define FACTORY_RESET_SUCCESS_CHANNEL CM_WHITE - -#define POLICE_COLOR_STROBE_CH1 CM_RED -#define POLICE_COLOR_STROBE_CH2 CM_WHITE +// can use some of the common handlers +//#define USE_CALC_2CH_BLEND +//#define USE_CALC_AUTO_3CH_BLEND // TODO: remove this as soon as it's not needed #define PWM_CHANNELS 1 @@ -119,11 +104,16 @@ Driver pinout: // custom channel modes -void set_level_1ch_dyn(uint8_t level); -void set_level_2ch_dyn_blend(uint8_t level); -void set_level_auto_3ch_dyn_blend(uint8_t level); +void set_level_red(uint8_t level); +void set_level_white_blend(uint8_t level); +void set_level_auto_3ch_blend(uint8_t level); void set_level_red_white_blend(uint8_t level); +void gradual_tick_red(); +void gradual_tick_white_blend(); +void gradual_tick_auto_3ch_blend(); +void gradual_tick_red_white_blend(); + inline void hwdef_setup() { diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index fb412a6..fbcbf59 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -16,6 +16,16 @@ // (it seriously would be more practical to just use moon instead) #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) +// channel modes... +// CM_WHITE, CM_AUTO, CM_RED, CM_WHITE_RED +#define DEFAULT_CHANNEL_MODE CM_AUTO + +#define FACTORY_RESET_WARN_CHANNEL CM_RED +#define FACTORY_RESET_SUCCESS_CHANNEL CM_WHITE + +#define POLICE_COLOR_STROBE_CH1 CM_RED +#define POLICE_COLOR_STROBE_CH2 CM_WHITE + // how much to increase total brightness at middle tint // (0 = 100% brightness, 64 = 200% brightness) // seems unnecessary on this light @@ -32,6 +42,7 @@ // shared table for white and red #define PWM1_LEVELS PWM_LEVELS #define MAX_1x7135 75 +#define MIN_THERM_STEPDOWN 75 // should be above highest dyn_pwm level // FIXME: clock at 5 MHz w/ full+half+quarter speeds, // instead of 10 MHz with w/ only half+quarter // (10 MHz is just wasting power) @@ -77,11 +88,6 @@ #undef TACTICAL_LEVELS #define TACTICAL_LEVELS 120,30,(RAMP_SIZE+3) // high, low, police strobe -// FIXME: thermal regulation should actually work fine on this light -#ifdef USE_THERMAL_REGULATION -#undef USE_THERMAL_REGULATION -#endif - // don't blink while ramping #ifdef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_MIDDLE diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c index 5096dfd..a55c74b 100644 --- a/spaghetti-monster/fsm-ramping.c +++ b/spaghetti-monster/fsm-ramping.c @@ -344,39 +344,6 @@ void gradual_tick() { } -// reduce repetition with macros -// common code at the beginning of every gradual tick handler -#define GRADUAL_TICK_SETUP() \ - uint8_t gt = gradual_target; \ - if (gt < actual_level) gt = actual_level - 1; \ - else if (gt > actual_level) gt = actual_level + 1; \ - gt --; \ - PWM_DATATYPE target; - -// tick the top layer of the stack -#define GRADUAL_ADJUST_1CH(TABLE,PWM) \ - target = PWM_GET(TABLE, gt); \ - if (PWM < target) PWM ++; \ - else if (PWM > target) PWM --; - -// tick a base level of the stack -// (with support for special DD FET behavior -// like "low=0, high=255" --> "low=255, high=254") -#define GRADUAL_ADJUST(TABLE,PWM,TOP) \ - target = PWM_GET(TABLE, gt); \ - if ((gt < actual_level) \ - && (PWM == 0) \ - && (target == TOP)) PWM = TOP; \ - else \ - if (PWM < target) PWM ++; \ - else if (PWM > target) PWM --; - -// do this when output exactly matches a ramp level -#define GRADUAL_IS_ACTUAL() \ - uint8_t orig = gradual_target; \ - set_level(gt + 1); \ - gradual_target = orig; - #ifdef USE_GRADUAL_TICK_1CH void gradual_tick_1ch() { GRADUAL_TICK_SETUP(); diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 028157f..8a12cc8 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -97,7 +97,46 @@ void set_level(uint8_t level); uint8_t gradual_target; inline void set_level_gradually(uint8_t lvl); void gradual_tick(); -#endif + +// reduce repetition with macros +// common code at the beginning of every gradual tick handler +#define GRADUAL_TICK_SETUP() \ + uint8_t gt = gradual_target; \ + if (gt < actual_level) gt = actual_level - 1; \ + else if (gt > actual_level) gt = actual_level + 1; \ + gt --; \ + PWM_DATATYPE target; + +// tick to a specific value +#define GRADUAL_ADJUST_SIMPLE(TARGET,PWM) \ + if (PWM < TARGET) PWM ++; \ + else if (PWM > TARGET) PWM --; + +// tick the top layer of the stack +#define GRADUAL_ADJUST_1CH(TABLE,PWM) \ + target = PWM_GET(TABLE, gt); \ + if (PWM < target) PWM ++; \ + else if (PWM > target) PWM --; + +// tick a base level of the stack +// (with support for special DD FET behavior +// like "low=0, high=255" --> "low=255, high=254") +#define GRADUAL_ADJUST(TABLE,PWM,TOP) \ + target = PWM_GET(TABLE, gt); \ + if ((gt < actual_level) \ + && (PWM == 0) \ + && (target == TOP)) PWM = TOP; \ + else \ + if (PWM < target) PWM ++; \ + else if (PWM > target) PWM --; + +// do this when output exactly matches a ramp level +#define GRADUAL_IS_ACTUAL() \ + uint8_t orig = gradual_target; \ + set_level(gt + 1); \ + gradual_target = orig; + +#endif // ifdef USE_SET_LEVEL_GRADUALLY // auto-detect the data type for PWM tables // FIXME: PWM bits and data type should be per PWM table -- cgit v1.2.3 From 951758c23dca945e856239d913df0fc54aa0de51 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 15 Apr 2023 15:55:47 -0600 Subject: LT1S Pro: reduced visibility of PWM by dropping the TOP values faster (and reduced mid-ramp "stall" behavior) The red channel seems to behave a little better too, when PWM is limited to 9 kHz or so instead of 10 kHz. It really starts spazzing out at even 10.1 kHz, 1% above its spec, and behaves nicer at 9 kHz or below. --- spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index fbcbf59..4b4d4b2 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -1,4 +1,5 @@ // Sofirn LT1S Pro +#pragma once #define MODEL_NUMBER "0623" #include "hwdef-Sofirn_LT1S-Pro.h" @@ -35,19 +36,16 @@ // TODO? 200% power at top of ramp on white blend mode // use dynamic PWM instead of plain 8-bit // (so we can get lower lows and a smoother ramp) -// level_calc.py 5.99 1 150 7135 1 0.2 600 --pwm dyn:74:16383:511 -// (with a few manual tweaks at the mid-point) -#define PWM_LEVELS 1,1,2,3,3,4,5,6,7,8,9,10,11,13,14,16,17,19,20,22,24,26,28,30,32,34,36,38,41,43,46,48,51,54,56,59,62,65,67,70,73,76,79,82,84,87,90,92,95,97,99,101,103,105,106,107,108,108,109,108,108,107,105,103,101,97,93,89,83,77,70,62,53,43,36,37,38,39,40,42,44,46,48,50,52,54,56,58,60,63,65,68,71,74,77,80,83,87,90,94,98,101,105,109,114,118,123,127,132,137,142,147,153,158,164,170,176,183,189,196,203,210,217,224,232,240,248,257,265,274,283,293,302,312,322,333,343,354,366,377,389,401,414,427,440,453,467,481,496,511 -#define PWM_TOPS 16383,11015,13411,15497,11274,12834,13512,13749,13735,13565,13292,12948,12555,13284,12747,13087,12495,12621,12010,12007,11928,11790,11609,11395,11155,10895,10622,10338,10307,9996,9905,9581,9452,9302,8973,8806,8627,8440,8124,7935,7743,7549,7354,7159,6883,6696,6511,6260,6084,5851,5628,5414,5210,5014,4782,4562,4355,4120,3937,3694,3501,3288,3060,2848,2651,2418,2202,2003,1775,1566,1353,1140,926,713,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511 +// (also, red LEDs use a QX7138 chip which has max PWM speed of 10 kHz, +// and it behaves erratically at full speed, +// so PWM here is 576 clock cycles long to keep the speed low enough) +// level_calc.py 5.99 1 150 7135 1 0.2 600 --pwm dyn:77:16383:575:3 +#define PWM_LEVELS 1,1,2,2,3,4,4,5,6,6,7,8,9,9,10,11,11,12,13,13,14,15,15,16,16,17,18,18,19,19,19,20,20,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,24,24,24,25,26,26,27,28,29,30,32,33,34,36,38,40,42,44,46,48,50,52,55,57,59,62,65,68,70,73,77,80,83,86,90,94,97,101,105,110,114,118,123,128,133,138,143,148,154,160,166,172,178,185,191,198,205,213,220,228,236,244,252,261,270,279,289,298,308,319,329,340,351,363,374,386,399,411,424,438,452,466,480,495,510,526,542,558,575 +#define PWM_TOPS 16383,10869,13246,8043,11458,12772,10093,11043,11450,9664,9991,10091,10048,8868,8838,8730,7814,7724,7589,6864,6748,6604,6024,5899,5398,5287,5159,4754,4638,4287,3963,3876,3594,3511,3265,3038,2829,2770,2586,2417,2260,2115,1981,1857,1742,1636,1537,1445,1360,1281,1207,1138,1073,1013,957,904,855,848,803,760,720,714,677,643,637,630,599,592,585,577,569,579,570,560,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575 // shared table for white and red #define PWM1_LEVELS PWM_LEVELS #define MAX_1x7135 75 #define MIN_THERM_STEPDOWN 75 // should be above highest dyn_pwm level -// FIXME: clock at 5 MHz w/ full+half+quarter speeds, -// instead of 10 MHz with w/ only half+quarter -// (10 MHz is just wasting power) -// red LEDs use a QX7138 chip which has max PWM speed of 10 kHz, -// so PWM is 512 clock cycles long to avoid running faster than that #define HALFSPEED_LEVEL 12 #define QUARTERSPEED_LEVEL 5 -- cgit v1.2.3 From 1b426266e4fb9dc7c526438f34e649f7ff5caba7 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 15 Apr 2023 18:33:17 -0600 Subject: added gchart's Extended Simple UI (strobes and aux config in simple mode) --- spaghetti-monster/anduril/lockout-mode.c | 35 +++++++++----- spaghetti-monster/anduril/off-mode.c | 82 ++++++++++++++++++++++---------- 2 files changed, 81 insertions(+), 36 deletions(-) diff --git a/spaghetti-monster/anduril/lockout-mode.c b/spaghetti-monster/anduril/lockout-mode.c index 13d3c0a..4997f29 100644 --- a/spaghetti-monster/anduril/lockout-mode.c +++ b/spaghetti-monster/anduril/lockout-mode.c @@ -65,6 +65,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { rgb_led_update(rgb_led_lockout_mode, 0); } else #endif + if (event == EV_tick) { if (arg > HOLD_TIMEOUT) { go_to_standby = 1; @@ -77,6 +78,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { } return MISCHIEF_MANAGED; } + #if defined(TICK_DURING_STANDBY) && (defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS)) else if (event == EV_sleep_tick) { #if defined(USE_INDICATOR_LED) @@ -94,6 +96,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { set_state(off_state, 0); return MISCHIEF_MANAGED; } + // 4 clicks: exit and turn on else if (event == EV_4clicks) { #ifdef USE_MANUAL_MEMORY @@ -105,6 +108,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { set_state(steady_state, memorized_level); return MISCHIEF_MANAGED; } + // 4 clicks, but hold last: exit and start at floor else if (event == EV_click4_hold) { //blink_once(); @@ -115,26 +119,20 @@ uint8_t lockout_state(Event event, uint16_t arg) { set_state(steady_state, 1); return MISCHIEF_MANAGED; } + // 5 clicks: exit and turn on at ceiling level else if (event == EV_5clicks) { set_state(steady_state, MAX_LEVEL); return MISCHIEF_MANAGED; } - ////////// Every action below here is blocked in the simple UI ////////// - #ifdef USE_SIMPLE_UI + ////////// Every action below here is blocked in the (non-Extended) Simple UI ////////// + + #if defined(USE_SIMPLE_UI) && !defined(USE_EXTENDED_SIMPLE_UI) if (simple_ui_active) { return EVENT_NOT_HANDLED; } - #endif - - #ifdef USE_AUTOLOCK - // 10H: configure the autolock option - else if (event == EV_click10_hold) { - push_state(autolock_config_state, 0); - return MISCHIEF_MANAGED; - } - #endif + #endif // if simple UI but not extended simple UI #if defined(USE_INDICATOR_LED) // 7 clicks: rotate through indicator LED modes (lockout mode) @@ -188,6 +186,21 @@ uint8_t lockout_state(Event event, uint16_t arg) { } #endif + #if defined(USE_EXTENDED_SIMPLE_UI) && defined(USE_SIMPLE_UI) + ////////// Every action below here is blocked in the Extended Simple UI ////////// + if (simple_ui_active) { + return EVENT_NOT_HANDLED; + } + #endif // if extended simple UI + + #ifdef USE_AUTOLOCK + // 10H: configure the autolock option + else if (event == EV_click10_hold) { + push_state(autolock_config_state, 0); + return MISCHIEF_MANAGED; + } + #endif + return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/anduril/off-mode.c b/spaghetti-monster/anduril/off-mode.c index 68ab234..c459979 100644 --- a/spaghetti-monster/anduril/off-mode.c +++ b/spaghetti-monster/anduril/off-mode.c @@ -45,6 +45,7 @@ uint8_t off_state(Event event, uint16_t arg) { if (! arg) { go_to_standby = 1; } return MISCHIEF_MANAGED; } + // go back to sleep eventually if we got bumped but didn't leave "off" state else if (event == EV_tick) { if (arg > HOLD_TIMEOUT) { @@ -58,6 +59,7 @@ uint8_t off_state(Event event, uint16_t arg) { } return MISCHIEF_MANAGED; } + #if defined(TICK_DURING_STANDBY) // blink the indicator LED, maybe else if (event == EV_sleep_tick) { @@ -84,6 +86,7 @@ uint8_t off_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif + #if (B_TIMING_ON == B_PRESS_T) // hold (initially): go to lowest level (floor), but allow abort for regular click else if (event == EV_click1_press) { @@ -91,6 +94,7 @@ uint8_t off_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif // B_TIMING_ON == B_PRESS_T + // hold: go to lowest level else if (event == EV_click1_hold) { #if (B_TIMING_ON == B_PRESS_T) @@ -116,11 +120,13 @@ uint8_t off_state(Event event, uint16_t arg) { } return MISCHIEF_MANAGED; } + // hold, release quickly: go to lowest level (floor) else if (event == EV_click1_hold_release) { set_state(steady_state, 1); return MISCHIEF_MANAGED; } + #if (B_TIMING_ON != B_TIMEOUT_T) // 1 click (before timeout): go to memorized level, but allow abort for double click else if (event == EV_click1_release) { @@ -135,6 +141,7 @@ uint8_t off_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif // if (B_TIMING_ON != B_TIMEOUT_T) + // 1 click: regular mode else if (event == EV_1click) { #if (B_TIMING_ON != B_TIMEOUT_T) @@ -147,6 +154,7 @@ uint8_t off_state(Event event, uint16_t arg) { #endif return MISCHIEF_MANAGED; } + // click, hold: momentary at ceiling or turbo else if (event == EV_click2_hold) { uint8_t turbo_level; // how bright is "turbo"? @@ -178,16 +186,19 @@ uint8_t off_state(Event event, uint16_t arg) { set_level(0); return MISCHIEF_MANAGED; } + // 2 clicks: highest mode (ceiling) else if (event == EV_2clicks) { set_state(steady_state, MAX_LEVEL); return MISCHIEF_MANAGED; } + // 3 clicks (initial press): off, to prep for later events else if (event == EV_click3_press) { set_level(0); return MISCHIEF_MANAGED; } + #ifdef USE_BATTCHECK // 3 clicks: battcheck mode / blinky mode group 1 else if (event == EV_3clicks) { @@ -195,6 +206,7 @@ uint8_t off_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif + #ifdef USE_LOCKOUT_MODE // 4 clicks: soft lockout else if (event == EV_4clicks) { @@ -203,6 +215,7 @@ uint8_t off_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif + #if defined(USE_FACTORY_RESET) && defined(USE_SOFT_FACTORY_RESET) // 13 clicks and hold the last click: invoke factory reset (reboot) else if (event == EV_click13_hold) { @@ -210,6 +223,7 @@ uint8_t off_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif + #ifdef USE_VERSION_CHECK // 15+ clicks: show the version number else if (event == EV_15clicks) { @@ -232,18 +246,14 @@ uint8_t off_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } - ////////// Every action below here is blocked in the simple UI ////////// + ////////// Every action below here is blocked in the (non-Extended) Simple UI ////////// + + #ifndef USE_EXTENDED_SIMPLE_UI if (simple_ui_active) { return EVENT_NOT_HANDLED; } - // 10 clicks: enable simple UI - else if (event == EV_10clicks) { - blink_once(); - simple_ui_active = 1; - save_config(); - return MISCHIEF_MANAGED; - } - #endif + #endif // ifndef USE_EXTENDED_SIMPLE_UI + #endif // ifdef USE_SIMPLE_UI // click, click, long-click: strobe mode #ifdef USE_STROBE_STATE @@ -257,22 +267,7 @@ uint8_t off_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif - #ifdef USE_MOMENTARY_MODE - // 5 clicks: momentary mode - else if (event == EV_5clicks) { - blink_once(); - set_state(momentary_state, 0); - return MISCHIEF_MANAGED; - } - #endif - #ifdef USE_TACTICAL_MODE - // 6 clicks: tactical mode - else if (event == EV_6clicks) { - blink_once(); - set_state(tactical_state, 0); - return MISCHIEF_MANAGED; - } - #endif + #ifdef USE_INDICATOR_LED // 7 clicks: change indicator LED mode else if (event == EV_7clicks) { @@ -321,6 +316,42 @@ uint8_t off_state(Event event, uint16_t arg) { } #endif // end 7 clicks + ////////// Every action below here is blocked in the Extended Simple UI ////////// + + #ifdef USE_SIMPLE_UI + #ifdef USE_EXTENDED_SIMPLE_UI + if (simple_ui_active) { + return EVENT_NOT_HANDLED; + } + #endif // ifdef USE_EXTENDED_SIMPLE_UI + + // 10 clicks: enable simple UI + else if (event == EV_10clicks) { + blink_once(); + simple_ui_active = 1; + save_config(); + return MISCHIEF_MANAGED; + } + #endif // ifdef USE_SIMPLE_UI + + #ifdef USE_MOMENTARY_MODE + // 5 clicks: momentary mode + else if (event == EV_5clicks) { + blink_once(); + set_state(momentary_state, 0); + return MISCHIEF_MANAGED; + } + #endif + + #ifdef USE_TACTICAL_MODE + // 6 clicks: tactical mode + else if (event == EV_6clicks) { + blink_once(); + set_state(tactical_state, 0); + return MISCHIEF_MANAGED; + } + #endif + #ifdef USE_GLOBALS_CONFIG // 9 clicks, but hold last click: configure misc global settings else if ((event == EV_click9_hold) && (!arg)) { @@ -328,6 +359,7 @@ uint8_t off_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } #endif + return EVENT_NOT_HANDLED; } -- cgit v1.2.3 From 4d7cd5f4dc593f96ba447ddf9970c53cdc7bc991 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 15 Apr 2023 18:34:16 -0600 Subject: merged gcharts config updates for BLF Q8 t1616 --- spaghetti-monster/anduril/cfg-blf-q8-t1616.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-blf-q8-t1616.h b/spaghetti-monster/anduril/cfg-blf-q8-t1616.h index 30a3368..204066d 100644 --- a/spaghetti-monster/anduril/cfg-blf-q8-t1616.h +++ b/spaghetti-monster/anduril/cfg-blf-q8-t1616.h @@ -7,9 +7,9 @@ #define USE_INDICATOR_LED // the button is visible while main LEDs are on #define USE_INDICATOR_LED_WHILE_RAMPING -// off mode: high (2) +// off mode: low (1) // lockout: blinking (3) -#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) // copied from Emisar D4 ramp // ../../bin/level_calc.py 1 65 7135 1 0.8 150 @@ -44,6 +44,15 @@ // Allow 3C in Simple UI for switching between smooth and stepped ramping #define USE_SIMPLE_UI_RAMPING_TOGGLE +// allow Aux Config and Strobe Modes in Simple UI +#define USE_EXTENDED_SIMPLE_UI + // stop panicking at ~75% power or ~3000 lm, this light has high thermal mass #define THERM_FASTER_LEVEL (RAMP_SIZE*9/10) // throttle back faster when high +// don't blink during the ramp; the button LED brightness is sufficient +// to indicate which power channel(s) are being used +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + -- cgit v1.2.3 From ef84fef658f3d2ef5fb13d198faa64bb59443afb Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 15 Apr 2023 18:35:24 -0600 Subject: LT1S Pro: added manual memory with a timer by default, like on SP10 Pro --- spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index 4b4d4b2..b98eebd 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -76,6 +76,12 @@ // allow Aux Config and Strobe Modes in Simple UI #define USE_EXTENDED_SIMPLE_UI +// turn on at med-low brightness by default (level 50/150, or ramp step 3/7) +// (also sets lockout mode 2H to a useful level) +#define DEFAULT_MANUAL_MEMORY 50 +// reset to default after being off for 10 minutes +#define DEFAULT_MANUAL_MEMORY_TIMER 10 + // enable 2 click turbo (Anduril 1 style) #define DEFAULT_2C_STYLE 1 -- cgit v1.2.3 From 3ae85eabf6fc665fb0be9276013f8c603d6a6dc9 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 15 Apr 2023 19:11:58 -0600 Subject: adapted smooth-sunset patch from SammysHP https://github.com/SammysHP/flashlight-firmware/tree/smooth-sunset https://github.com/SammysHP/flashlight-firmware/compare/anduril2...smooth-sunset (also shortened file headers, as long as I was touching those files) --- spaghetti-monster/anduril/ramp-mode.c | 49 ++++++++++++++------------------ spaghetti-monster/anduril/ramp-mode.h | 31 ++++++-------------- spaghetti-monster/anduril/sunset-timer.c | 30 ++++--------------- spaghetti-monster/anduril/sunset-timer.h | 26 +++-------------- 4 files changed, 41 insertions(+), 95 deletions(-) diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index e57b68f..a87e9b0 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -1,24 +1,8 @@ -/* - * ramp-mode.c: Ramping functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef RAMP_MODE_C -#define RAMP_MODE_C +// ramp-mode.c: Ramping functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once #include "ramp-mode.h" @@ -85,13 +69,12 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_SUNSET_TIMER // handle the shutoff timer first - static uint8_t timer_orig_level = 0; uint8_t sunset_active = sunset_timer; // save for comparison // clock tick sunset_timer_state(event, arg); // if the timer was just turned on if (sunset_timer && (! sunset_active)) { - timer_orig_level = actual_level; + sunset_timer_orig_level = actual_level; } // if the timer just expired, shut off else if (sunset_active && (! sunset_timer)) { @@ -145,7 +128,7 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level_and_therm_target(memorized_level); } #ifdef USE_SUNSET_TIMER - timer_orig_level = actual_level; + reset_sunset_timer(); #endif return MISCHIEF_MANAGED; } @@ -243,7 +226,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #endif set_level_and_therm_target(memorized_level); #ifdef USE_SUNSET_TIMER - timer_orig_level = actual_level; + reset_sunset_timer(); #endif return MISCHIEF_MANAGED; } @@ -264,8 +247,12 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_SUNSET_TIMER // reduce output if shutoff timer is active if (sunset_timer) { - uint8_t dimmed_level = timer_orig_level * (sunset_timer-1) / sunset_timer_peak; + uint8_t dimmed_level = sunset_timer_orig_level * sunset_timer / sunset_timer_peak; + uint8_t dimmed_level_next = sunset_timer_orig_level * (sunset_timer-1) / sunset_timer_peak; + uint8_t dimmed_level_delta = dimmed_level - dimmed_level_next; + dimmed_level -= dimmed_level_delta * (sunset_ticks/TICKS_PER_SECOND) / 60; if (dimmed_level < 1) dimmed_level = 1; + #ifdef USE_SET_LEVEL_GRADUALLY set_level_gradually(dimmed_level); target_level = dimmed_level; @@ -408,7 +395,7 @@ uint8_t steady_state(Event event, uint16_t arg) { memorized_level = nearest_level(actual_level); set_level_and_therm_target(memorized_level); #ifdef USE_SUNSET_TIMER - timer_orig_level = actual_level; + reset_sunset_timer(); #endif return MISCHIEF_MANAGED; } @@ -681,5 +668,13 @@ void manual_memory_save() { #endif } +#ifdef USE_SUNSET_TIMER +void reset_sunset_timer() { + if (sunset_timer) { + sunset_timer_orig_level = actual_level; + sunset_timer_peak = sunset_timer; + sunset_ticks = 0; + } +} #endif diff --git a/spaghetti-monster/anduril/ramp-mode.h b/spaghetti-monster/anduril/ramp-mode.h index 969cb6b..6bc3846 100644 --- a/spaghetti-monster/anduril/ramp-mode.h +++ b/spaghetti-monster/anduril/ramp-mode.h @@ -1,24 +1,8 @@ -/* - * ramp-mode.h: Ramping functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// ramp-mode.h: Ramping functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef RAMP_MODE_H -#define RAMP_MODE_H +#pragma once #ifndef RAMP_LENGTH #define RAMP_LENGTH 150 // default, if not overridden in a driver cfg file @@ -239,6 +223,11 @@ uint8_t ramp_stepss[] = { }; uint8_t ramp_discrete_step_size; // don't set this +#ifdef USE_SUNSET_TIMER +uint8_t sunset_timer_orig_level = 0; +void reset_sunset_timer(); +#endif + #ifdef USE_GLOBALS_CONFIG typedef enum { #ifdef USE_TINT_RAMPING @@ -254,5 +243,3 @@ void globals_config_save(uint8_t step, uint8_t value); uint8_t globals_config_state(Event event, uint16_t arg); #endif - -#endif diff --git a/spaghetti-monster/anduril/sunset-timer.c b/spaghetti-monster/anduril/sunset-timer.c index d942eba..eae1831 100644 --- a/spaghetti-monster/anduril/sunset-timer.c +++ b/spaghetti-monster/anduril/sunset-timer.c @@ -1,24 +1,8 @@ -/* - * sunset-timer.c: Sunset / candle auto-shutoff functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// sunset-timer.c: Sunset / candle auto-shutoff functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef SUNSET_TIMER_C -#define SUNSET_TIMER_C +#pragma once #include "sunset-timer.h" @@ -39,8 +23,9 @@ uint8_t sunset_timer_state(Event event, uint16_t arg) { else if (event == EV_hold) { // ramping up should "bump" the timer to extend the deadline a bit if ((sunset_timer > 0) && (sunset_timer < 4)) { - sunset_timer = 3; + sunset_timer = 3; // 3 minutes sunset_timer_peak = 3; + sunset_ticks = 0; // re-start current "minute" } } // 5H: add 5m to timer, per second, until released @@ -73,6 +58,3 @@ uint8_t sunset_timer_state(Event event, uint16_t arg) { return EVENT_NOT_HANDLED; } - -#endif - diff --git a/spaghetti-monster/anduril/sunset-timer.h b/spaghetti-monster/anduril/sunset-timer.h index 8f7840c..963804e 100644 --- a/spaghetti-monster/anduril/sunset-timer.h +++ b/spaghetti-monster/anduril/sunset-timer.h @@ -1,24 +1,8 @@ -/* - * sunset-timer.h: Sunset / candle auto-shutoff functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// sunset-timer.h: Sunset / candle auto-shutoff functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef SUNSET_TIMER_H -#define SUNSET_TIMER_H +#pragma once // how many minutes to add each time the user "bumps" the timer? #define SUNSET_TIMER_UNIT 5 @@ -31,5 +15,3 @@ uint8_t sunset_timer_peak = 0; // total minutes in countdown uint16_t sunset_ticks = 0; // counts from 0 to TICKS_PER_MINUTE, then repeats uint8_t sunset_timer_state(Event event, uint16_t arg); - -#endif -- cgit v1.2.3 From c3abe88fe78d3cc1520065de0cdf2e7bdecff0dc Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 15 Apr 2023 19:28:43 -0600 Subject: enable sunset timer in Extended Simple UI --- spaghetti-monster/anduril/sunset-timer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/sunset-timer.c b/spaghetti-monster/anduril/sunset-timer.c index eae1831..bad317c 100644 --- a/spaghetti-monster/anduril/sunset-timer.c +++ b/spaghetti-monster/anduril/sunset-timer.c @@ -8,7 +8,7 @@ uint8_t sunset_timer_state(Event event, uint16_t arg) { - #ifdef USE_SIMPLE_UI + #if defined(USE_SIMPLE_UI) && !defined(USE_EXTENDED_SIMPLE_UI) // No timer functions in Simple UI if (simple_ui_active) return EVENT_NOT_HANDLED; #endif -- cgit v1.2.3 From 359892f0af6ce29bafd53b114bda685dc3d9d0dc Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 15 Apr 2023 21:57:57 -0600 Subject: added ability to use 2 colors in config mode --- spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 3 ++ spaghetti-monster/anduril/config-mode.c | 61 ++++++++++++++----------- spaghetti-monster/anduril/config-mode.h | 31 ++++--------- 3 files changed, 46 insertions(+), 49 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index b98eebd..282dca2 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -24,6 +24,9 @@ #define FACTORY_RESET_WARN_CHANNEL CM_RED #define FACTORY_RESET_SUCCESS_CHANNEL CM_WHITE +#define CONFIG_WAITING_CHANNEL CM_RED +#define CONFIG_BLINK_CHANNEL CM_WHITE + #define POLICE_COLOR_STROBE_CH1 CM_RED #define POLICE_COLOR_STROBE_CH2 CM_WHITE diff --git a/spaghetti-monster/anduril/config-mode.c b/spaghetti-monster/anduril/config-mode.c index 3af2a1c..a74bdbe 100644 --- a/spaghetti-monster/anduril/config-mode.c +++ b/spaghetti-monster/anduril/config-mode.c @@ -1,24 +1,8 @@ -/* - * config-mode.c: Config mode base functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef CONFIG_MODE_C -#define CONFIG_MODE_C +// config-mode.c: Config mode base functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once #include "config-mode.h" @@ -45,7 +29,13 @@ uint8_t config_state_base( void (*savefunc)(uint8_t step, uint8_t value)) { static uint8_t config_step; + #ifdef USE_CONFIG_COLORS + static uint8_t orig_channel; + #endif if (event == EV_enter_state) { + #ifdef USE_CONFIG_COLORS + orig_channel = channel_mode; + #endif config_step = 0; set_level(0); // if button isn't held, configure first menu item @@ -62,14 +52,21 @@ uint8_t config_state_base( #define B_ANY_HOLD_RELEASE (B_CLICK|B_HOLD|B_RELEASE|B_TIMEOUT) else if ((event & B_CLICK_FLAGS) == B_ANY_HOLD) { if (config_step <= num_config_steps) { - if (2 == (arg % (TICKS_PER_SECOND*3/2))) { + if ((TICKS_PER_SECOND/10) == (arg % (TICKS_PER_SECOND*3/2))) { config_step ++; // blink when config step advances - if (config_step <= num_config_steps) + if (config_step <= num_config_steps) { + #ifdef CONFIG_BLINK_CHANNEL + set_channel_mode(CONFIG_BLINK_CHANNEL); + #endif set_level(RAMP_SIZE * 3 / 8); + } } else { // stay on at a low level to indicate menu is active + #ifdef CONFIG_WAITING_CHANNEL + set_channel_mode(CONFIG_WAITING_CHANNEL); + #endif set_level(RAMP_SIZE * 1 / 8); } } else { @@ -99,6 +96,13 @@ uint8_t config_state_base( pop_state(); } + #ifdef USE_CONFIG_COLORS + else if (event == EV_leave_state) { + // put the colors back how they were + set_channel_mode(orig_channel); + } + #endif + // eat all other events; don't pass any through to parent return EVENT_HANDLED; } @@ -135,8 +139,11 @@ uint8_t number_entry_state(Event event, uint16_t arg) { // (flicker every other frame, // except first frame (so we can see flashes after each click)) else if (arg) { + #ifdef CONFIG_WAITING_CHANNEL + set_channel_mode(CONFIG_WAITING_CHANNEL); + #endif set_level( (RAMP_SIZE/8) - + ((arg&2)<<1) ); + + ((arg&2)<<2) ); } } // all done, save result and return to parent state @@ -159,6 +166,9 @@ uint8_t number_entry_state(Event event, uint16_t arg) { #endif number_entry_value ++; // update the result empty_event_sequence(); // reset FSM's click count + #ifdef CONFIG_BLINK_CHANNEL + set_channel_mode(CONFIG_BLINK_CHANNEL); + #endif set_level(RAMP_SIZE/2); // flash briefly return MISCHIEF_MANAGED; } @@ -167,6 +177,3 @@ uint8_t number_entry_state(Event event, uint16_t arg) { return EVENT_HANDLED; } - -#endif - diff --git a/spaghetti-monster/anduril/config-mode.h b/spaghetti-monster/anduril/config-mode.h index 7cbc534..388c0a2 100644 --- a/spaghetti-monster/anduril/config-mode.h +++ b/spaghetti-monster/anduril/config-mode.h @@ -1,24 +1,13 @@ -/* - * config-mode.h: Config mode base functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// config-mode.h: Config mode base functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef CONFIG_MODE_H -#define CONFIG_MODE_H +#pragma once + +// menus can use 2 colors +#if defined (CONFIG_WAITING_CHANNEL) || defined(CONFIG_BLINK_CHANNEL) +#define USE_CONFIG_COLORS +#endif // config menu uint8_t config_state_base( @@ -28,5 +17,3 @@ uint8_t config_state_base( void (*savefunc)(uint8_t step, uint8_t value) ); - -#endif -- cgit v1.2.3 From fbcac59563c32f14de4861449c1b267c247b5b78 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 16 Apr 2023 18:21:29 -0600 Subject: reduced ROM by ~600 bytes by moving all eeprom config values to a "cfg" struct (this also made some parts of the code cleaner) --- hwdef-Sofirn_LT1S-Pro.c | 74 +-------- hwdef-Sofirn_LT1S-Pro.h | 2 +- spaghetti-monster/anduril/anduril.c | 8 +- spaghetti-monster/anduril/aux-leds.h | 11 +- spaghetti-monster/anduril/battcheck-mode.c | 4 +- spaghetti-monster/anduril/beacon-mode.c | 4 +- spaghetti-monster/anduril/beacon-mode.h | 3 - spaghetti-monster/anduril/channel-modes.c | 20 +-- spaghetti-monster/anduril/channel-modes.h | 5 - spaghetti-monster/anduril/config-mode.c | 2 +- spaghetti-monster/anduril/factory-reset.c | 3 +- spaghetti-monster/anduril/load-save-config-fsm.h | 173 ++++++++++--------- spaghetti-monster/anduril/load-save-config.c | 201 +---------------------- spaghetti-monster/anduril/load-save-config.h | 162 +++++++++++++++--- spaghetti-monster/anduril/lockout-mode.c | 48 +++--- spaghetti-monster/anduril/lockout-mode.h | 1 - spaghetti-monster/anduril/off-mode.c | 60 +++---- spaghetti-monster/anduril/ramp-mode.c | 77 ++++----- spaghetti-monster/anduril/ramp-mode.h | 64 ++------ spaghetti-monster/anduril/strobe-modes.c | 36 ++-- spaghetti-monster/anduril/strobe-modes.h | 7 +- spaghetti-monster/anduril/sunset-timer.c | 2 +- spaghetti-monster/anduril/tactical-mode.c | 10 +- spaghetti-monster/anduril/tactical-mode.h | 7 +- spaghetti-monster/anduril/tempcheck-mode.c | 8 +- spaghetti-monster/fsm-adc.c | 14 +- spaghetti-monster/fsm-adc.h | 22 ++- spaghetti-monster/fsm-eeprom.h | 7 +- spaghetti-monster/fsm-ramping.c | 126 ++++++++++---- spaghetti-monster/fsm-ramping.h | 83 ++++++---- 30 files changed, 580 insertions(+), 664 deletions(-) diff --git a/hwdef-Sofirn_LT1S-Pro.c b/hwdef-Sofirn_LT1S-Pro.c index a6d2b8f..f617933 100644 --- a/hwdef-Sofirn_LT1S-Pro.c +++ b/hwdef-Sofirn_LT1S-Pro.c @@ -5,66 +5,6 @@ #pragma once -// calculate a "tint ramp" blend between 2 channels -// results are placed in *warm and *cool vars -// brightness : total amount of light units to distribute -// top : maximum allowed brightness per channel -// blend : ratio between warm and cool (0 = warm, 128 = 50%, 255 = cool) -void calc_2ch_blend( - PWM_DATATYPE *warm, - PWM_DATATYPE *cool, - PWM_DATATYPE brightness, - PWM_DATATYPE top, - uint8_t blend) { - - #ifndef TINT_RAMPING_CORRECTION - #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint - #endif - - // calculate actual PWM levels based on a single-channel ramp - // and a blend value - PWM_DATATYPE warm_PWM, cool_PWM; - PWM_DATATYPE2 base_PWM = brightness; - - #if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0) - uint8_t level = actual_level - 1; - - // middle tints sag, so correct for that effect - // by adding extra power which peaks at the middle tint - // (correction is only necessary when PWM is fast) - if (level > HALFSPEED_LEVEL) { - base_PWM = brightness - + ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64) - * triangle_wave(blend) / 255); - } - // fade the triangle wave out when above 100% power, - // so it won't go over 200% - if (brightness > top) { - base_PWM -= 2 * ( - ((brightness - top) * TINT_RAMPING_CORRECTION / 64) - * triangle_wave(blend) / 255 - ); - } - // guarantee no more than 200% power - if (base_PWM > (top << 1)) { base_PWM = top << 1; } - #endif - - cool_PWM = (((PWM_DATATYPE2)blend * (PWM_DATATYPE2)base_PWM) + 127) / 255; - warm_PWM = base_PWM - cool_PWM; - // when running at > 100% power, spill extra over to other channel - if (cool_PWM > top) { - warm_PWM += (cool_PWM - top); - cool_PWM = top; - } else if (warm_PWM > top) { - cool_PWM += (warm_PWM - top); - warm_PWM = top; - } - - *warm = warm_PWM; - *cool = cool_PWM; -} - - // calculate a 3-channel "auto tint" blend // (like red -> warm white -> cool white) // results are placed in *a, *b, and *c vars @@ -126,7 +66,7 @@ void set_level_white_blend(uint8_t level) { PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); PWM_DATATYPE top = PWM_GET(pwm_tops, level); - uint8_t blend = channel_mode_args[channel_mode]; + uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); @@ -166,9 +106,9 @@ void set_level_auto_3ch_blend(uint8_t level) { // "white + red" channel mode void set_level_red_white_blend(uint8_t level) { // set the warm+cool white LEDs first - channel_mode = CM_WHITE; + cfg.channel_mode = CM_WHITE; set_level_white_blend(level); - channel_mode = CM_WHITE_RED; + cfg.channel_mode = CM_WHITE_RED; if (level == 0) { RED_PWM_LVL = 0; @@ -182,7 +122,7 @@ void set_level_red_white_blend(uint8_t level) { // set the red LED as a ratio of the white output level // 0 = no red // 255 = red at 100% of white channel PWM - uint8_t ratio = channel_mode_args[channel_mode]; + uint8_t ratio = cfg.channel_mode_args[cfg.channel_mode]; RED_PWM_LVL = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)vpwm) + 127) / 255; if (! actual_level) PWM_CNT = 0; // reset phase @@ -213,7 +153,7 @@ void gradual_tick_white_blend() { PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); PWM_DATATYPE top = PWM_GET(pwm_tops, gt); - uint8_t blend = channel_mode_args[channel_mode]; + uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); @@ -259,9 +199,9 @@ void gradual_tick_auto_3ch_blend() { void gradual_tick_red_white_blend() { // do the white blend thing... - channel_mode = CM_WHITE; + cfg.channel_mode = CM_WHITE; gradual_tick_white_blend(); - channel_mode = CM_WHITE_RED; + cfg.channel_mode = CM_WHITE_RED; // ... and then update red to the closest ramp level // (coarse red adjustments aren't visible here anyway) set_level_red(actual_level); diff --git a/hwdef-Sofirn_LT1S-Pro.h b/hwdef-Sofirn_LT1S-Pro.h index 84623fd..b50ccc7 100644 --- a/hwdef-Sofirn_LT1S-Pro.h +++ b/hwdef-Sofirn_LT1S-Pro.h @@ -48,7 +48,7 @@ Driver pinout: gradual_tick_red, \ gradual_tick_red_white_blend // can use some of the common handlers -//#define USE_CALC_2CH_BLEND +#define USE_CALC_2CH_BLEND //#define USE_CALC_AUTO_3CH_BLEND // TODO: remove this as soon as it's not needed diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 07560bc..e180cc4 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -104,7 +104,6 @@ #include "off-mode.h" #include "ramp-mode.h" -#include "load-save-config.h" #include "config-mode.h" #include "aux-leds.h" #include "misc.h" @@ -158,6 +157,9 @@ #include "sos-mode.h" #endif +// this should be last, so other headers have a chance to declare values +#include "load-save-config.h" + /********* Include all the app logic source files *********/ // (is a bit weird to do things this way, @@ -239,7 +241,7 @@ void setup() { #if defined(USE_MANUAL_MEMORY) && defined(USE_MANUAL_MEMORY_TIMER) // without this, initial boot-up brightness is wrong // when manual mem is enabled with a non-zero timer - if (manual_memory) manual_memory_restore(); + if (cfg.manual_memory) manual_memory_restore(); #endif #if defined(USE_CHANNEL_MODES) @@ -321,7 +323,7 @@ void loop() { // in simple mode, turn off after one readout // FIXME: can eat the next button press // (state changes in loop() act weird) - if (simple_ui_active) set_state_deferred(off_state, 0); + if (cfg.simple_ui_active) set_state_deferred(off_state, 0); else nice_delay_ms(1000); #endif } diff --git a/spaghetti-monster/anduril/aux-leds.h b/spaghetti-monster/anduril/aux-leds.h index 71a14e3..f496ddc 100644 --- a/spaghetti-monster/anduril/aux-leds.h +++ b/spaghetti-monster/anduril/aux-leds.h @@ -61,8 +61,6 @@ const PROGMEM uint8_t rgb_led_colors[] = { #ifndef RGB_RAINBOW_SPEED #define RGB_RAINBOW_SPEED 0x0f // change color every 16 frames #endif -uint8_t rgb_led_off_mode = RGB_LED_OFF_DEFAULT; -uint8_t rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT; #endif //#define USE_OLD_BLINKING_INDICATOR @@ -71,14 +69,11 @@ uint8_t rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT; // bits 2-3 control lockout mode // bits 0-1 control "off" mode // modes are: 0=off, 1=low, 2=high, 3=blinking (if TICK_DURING_STANDBY enabled) - #ifdef INDICATOR_LED_DEFAULT_MODE - uint8_t indicator_led_mode = INDICATOR_LED_DEFAULT_MODE; - #else + #ifndef INDICATOR_LED_DEFAULT_MODE #ifdef USE_INDICATOR_LED_WHILE_RAMPING - //uint8_t indicator_led_mode = (1<<2) + 2; - uint8_t indicator_led_mode = (2<<2) + 1; + #define INDICATOR_LED_DEFAULT_MODE ((2<<2) + 1) #else - uint8_t indicator_led_mode = (3<<2) + 1; + #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) #endif #endif #endif diff --git a/spaghetti-monster/anduril/battcheck-mode.c b/spaghetti-monster/anduril/battcheck-mode.c index d34559b..5edc6f4 100644 --- a/spaghetti-monster/anduril/battcheck-mode.c +++ b/spaghetti-monster/anduril/battcheck-mode.c @@ -25,7 +25,7 @@ uint8_t battcheck_state(Event event, uint16_t arg) { ////////// Every action below here is blocked in the simple UI ////////// #ifdef USE_SIMPLE_UI - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif @@ -69,7 +69,7 @@ uint8_t battcheck_state(Event event, uint16_t arg) { // ... // 13 = add 0.30V void voltage_config_save(uint8_t step, uint8_t value) { - if (value) voltage_correction = value; + if (value) cfg.voltage_correction = value; } uint8_t voltage_config_state(Event event, uint16_t arg) { diff --git a/spaghetti-monster/anduril/beacon-mode.c b/spaghetti-monster/anduril/beacon-mode.c index e8e5004..76ada0f 100644 --- a/spaghetti-monster/anduril/beacon-mode.c +++ b/spaghetti-monster/anduril/beacon-mode.c @@ -28,7 +28,7 @@ inline void beacon_mode_iter() { set_level(memorized_level); nice_delay_ms(100); set_level(0); - nice_delay_ms(((beacon_seconds) * 1000) - 100); + nice_delay_ms(((cfg.beacon_seconds) * 1000) - 100); } } @@ -61,7 +61,7 @@ uint8_t beacon_state(Event event, uint16_t arg) { } // release hold: save new timing else if (event == EV_click1_hold_release) { - beacon_seconds = 1 + (arg / TICKS_PER_SECOND); + cfg.beacon_seconds = 1 + (arg / TICKS_PER_SECOND); save_config(); return MISCHIEF_MANAGED; } diff --git a/spaghetti-monster/anduril/beacon-mode.h b/spaghetti-monster/anduril/beacon-mode.h index 752918e..c0f0b18 100644 --- a/spaghetti-monster/anduril/beacon-mode.h +++ b/spaghetti-monster/anduril/beacon-mode.h @@ -20,9 +20,6 @@ #ifndef BEACON_MODE_H #define BEACON_MODE_H -// beacon timing -uint8_t beacon_seconds = 2; - // beacon mode uint8_t beacon_state(Event event, uint16_t arg); inline void beacon_mode_iter(); diff --git a/spaghetti-monster/anduril/channel-modes.c b/spaghetti-monster/anduril/channel-modes.c index 958b375..f3a21cf 100644 --- a/spaghetti-monster/anduril/channel-modes.c +++ b/spaghetti-monster/anduril/channel-modes.c @@ -20,7 +20,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { // in addition to changing state... so ignore any tint-ramp events which // don't look like they were meant to be here static uint8_t active = 0; - uint8_t tint = channel_mode_args[channel_mode]; + uint8_t tint = cfg.channel_mode_args[cfg.channel_mode]; #endif // it's possible that a light may need 3H but not 3C, @@ -28,7 +28,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { #if NUM_CHANNEL_MODES > 1 // 3 clicks: next channel mode if (event == EV_3clicks) { - uint8_t next = channel_mode; + uint8_t next = cfg.channel_mode; // go to next channel mode until we find one which is enabled // (and don't do any infinite loops if the user disabled them all) uint8_t count = 0; @@ -39,10 +39,10 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { //} while ((! channel_modes_enabled[next]) && count < NUM_CHANNEL_MODES); // undo change if infinite loop detected (redundant?) - //if (NUM_CHANNEL_MODES == count) next = channel_mode; + //if (NUM_CHANNEL_MODES == count) next = cfg.channel_mode; // if mode hasn't changed, abort - if (channel_mode == next) + if (cfg.channel_mode == next) return EVENT_NOT_HANDLED; set_channel_mode(next); @@ -55,9 +55,9 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { #ifdef USE_CUSTOM_CHANNEL_3H_MODES // defer to mode-specific function if defined - if (tint_ramp_modes[channel_mode]) { - StatePtr tint_func = channel_3H_modes[channel_mode]; - return tint_func(channel_mode); + if (tint_ramp_modes[cfg.channel_mode]) { + StatePtr tint_func = channel_3H_modes[cfg.channel_mode]; + return tint_func(cfg.channel_mode); } else #endif #ifdef USE_CHANNEL_MODE_ARGS @@ -86,7 +86,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { past_edge_counter = 1; } prev_tint = tint; - channel_mode_args[channel_mode] = tint; + cfg.channel_mode_args[cfg.channel_mode] = tint; set_level(actual_level); return EVENT_HANDLED; } @@ -99,7 +99,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { if (0 == tint) tint_ramp_direction = 1; else if (255 == tint) tint_ramp_direction = -1; // remember tint after battery change - channel_mode_args[channel_mode] = tint; + cfg.channel_mode_args[cfg.channel_mode] = tint; save_config(); // bug?: for some reason, brightness can seemingly change // from 1/150 to 2/150 without this next line... not sure why @@ -111,7 +111,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { #if defined(USE_SIMPLE_UI) // remaining mappings aren't "simple", so stop here - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif diff --git a/spaghetti-monster/anduril/channel-modes.h b/spaghetti-monster/anduril/channel-modes.h index 167c293..c10af5b 100644 --- a/spaghetti-monster/anduril/channel-modes.h +++ b/spaghetti-monster/anduril/channel-modes.h @@ -6,11 +6,6 @@ #pragma once -#if defined(USE_MANUAL_MEMORY) && defined(USE_CHANNEL_MODE_ARGS) -// remember and reset 1 extra parameter per channel mode (like tint) -uint8_t manual_memory_channel_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; -#endif - // not actually a mode, more of a fallback under other modes uint8_t channel_mode_state(Event event, uint16_t arg); diff --git a/spaghetti-monster/anduril/config-mode.c b/spaghetti-monster/anduril/config-mode.c index a74bdbe..394998a 100644 --- a/spaghetti-monster/anduril/config-mode.c +++ b/spaghetti-monster/anduril/config-mode.c @@ -34,7 +34,7 @@ uint8_t config_state_base( #endif if (event == EV_enter_state) { #ifdef USE_CONFIG_COLORS - orig_channel = channel_mode; + orig_channel = cfg.channel_mode; #endif config_step = 0; set_level(0); diff --git a/spaghetti-monster/anduril/factory-reset.c b/spaghetti-monster/anduril/factory-reset.c index a14b5b9..1e9714a 100644 --- a/spaghetti-monster/anduril/factory-reset.c +++ b/spaghetti-monster/anduril/factory-reset.c @@ -8,7 +8,6 @@ // allows setting channel mode per animation stage, // so it can ramp up in red then explode in white (as one example) -// TODO: maybe also do the same in menus? void factory_reset() { // display a warning for a few seconds before doing the actual reset, @@ -38,7 +37,7 @@ void factory_reset() { // AVR 1-Series has factory calibrated thermal sensor, always remove the offset on reset #if defined(USE_THERMAL_REGULATION) && defined(AVRXMEGA3) // this will cancel out the offset - thermal_config_save(1, temperature - therm_cal_offset); + thermal_config_save(1, temperature - cfg.therm_cal_offset); #elif defined(USE_THERMAL_REGULATION) && defined(USE_THERM_AUTOCALIBRATE) // assume current temperature is 21 C thermal_config_save(1, 21); diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h index 9004f1f..ef079db 100644 --- a/spaghetti-monster/anduril/load-save-config-fsm.h +++ b/spaghetti-monster/anduril/load-save-config-fsm.h @@ -1,127 +1,122 @@ -/* - * load-save-config-fsm.h: FSM config for eeprom configuration in Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef LOAD_SAVE_CONFIG_FSM_H -#define LOAD_SAVE_CONFIG_FSM_H +// load-save-config-fsm.h: FSM config for eeprom configuration in Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once -// auto-detect how many eeprom bytes #define USE_EEPROM -typedef enum { - ramp_style_e, - #ifdef USE_RAMP_CONFIG - ramp_smooth_floor_e, - ramp_smooth_ceil_e, - #ifdef USE_RAMP_SPEED_CONFIG - ramp_speed_e, +// load into a custom RAM location instead of FSM's default byte array +#define EEPROM_OVERRIDE + +#ifdef USE_SIMPLE_UI +#define NUM_RAMPS 3 +#else +#define NUM_RAMPS 2 +#endif + +// let FSM know this config struct exists +#define USE_CFG + +typedef struct Config { + + ///// ramp vars + uint8_t ramp_style; + #ifdef USE_2C_STYLE_CONFIG + uint8_t ramp_2c_style; #endif - ramp_discrete_floor_e, - ramp_discrete_ceil_e, - ramp_discrete_steps_e, + #ifdef USE_RAMP_CONFIG + uint8_t ramp_floors[NUM_RAMPS]; + uint8_t ramp_ceils [NUM_RAMPS]; + uint8_t ramp_stepss[NUM_RAMPS]; #endif #ifdef USE_SIMPLE_UI - simple_ui_floor_e, - simple_ui_ceil_e, - simple_ui_steps_e, - simple_ui_active_e, - #ifdef USE_2C_STYLE_CONFIG - ramp_2c_style_simple_e, - #endif + uint8_t simple_ui_active; + #ifdef USE_2C_STYLE_CONFIG + uint8_t ramp_2c_style_simple; + #endif #endif #ifdef USE_RAMP_AFTER_MOON_CONFIG - dont_ramp_after_moon_e, - #endif - #ifdef USE_2C_STYLE_CONFIG - ramp_2c_style_e, + uint8_t dont_ramp_after_moon; #endif #ifdef USE_MANUAL_MEMORY - manual_memory_e, + uint8_t manual_memory; #ifdef USE_MANUAL_MEMORY_TIMER - manual_memory_timer_e, + uint8_t manual_memory_timer; #endif #endif - #ifdef USE_JUMP_START - jump_start_level_e, + + ///// channel modes / color modes + #if NUM_CHANNEL_MODES > 1 + uint8_t channel_mode; + uint8_t channel_modes_enabled; + #ifdef USE_MANUAL_MEMORY + uint8_t manual_memory_channel_mode; + #endif + #endif + #ifdef USE_CHANNEL_MODE_ARGS + // this is an array, needs a few bytes + uint8_t channel_mode_args[NUM_CHANNEL_MODES]; + #ifdef USE_MANUAL_MEMORY + uint8_t manual_memory_channel_args[NUM_CHANNEL_MODES]; + #endif #endif + + ///// strobe / blinky mode settings #ifdef USE_STROBE_STATE - strobe_type_e, + uint8_t strobe_type; #endif #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) - strobe_delays_0_e, - strobe_delays_1_e, + uint8_t strobe_delays[2]; #endif #ifdef USE_BIKE_FLASHER_MODE - bike_flasher_brightness_e, + uint8_t bike_flasher_brightness; #endif #ifdef USE_BEACON_MODE - beacon_seconds_e, - #endif - #ifdef USE_THERMAL_REGULATION - therm_ceil_e, - therm_cal_offset_e, + uint8_t beacon_seconds; #endif + + ///// voltage and temperature #ifdef USE_VOLTAGE_CORRECTION - voltage_correction_e, + uint8_t voltage_correction; + #endif + #ifdef USE_THERMAL_REGULATION + uint8_t therm_ceil; + uint8_t therm_cal_offset; #endif + + ///// aux LEDs #ifdef USE_INDICATOR_LED - indicator_led_mode_e, + uint8_t indicator_led_mode; #endif #ifdef USE_AUX_RGB_LEDS - rgb_led_off_mode_e, - rgb_led_lockout_mode_e, + uint8_t rgb_led_off_mode; + uint8_t rgb_led_lockout_mode; #endif + + ///// misc other mode settings #ifdef USE_AUTOLOCK - autolock_time_e, + uint8_t autolock_time; #endif #ifdef USE_TACTICAL_MODE - tactical_lvl_1_e, - tactical_lvl_2_e, - tactical_lvl_3_e, - #endif - #if NUM_CHANNEL_MODES > 1 - channel_mode_e, - channel_modes_enabled_e, - #if defined(USE_MANUAL_MEMORY) - manual_memory_channel_mode_e, - #endif + uint8_t tactical_levels[3]; #endif - #ifdef USE_CHANNEL_MODE_ARGS - // this is an array, needs a few bytes - channel_mode_args_e, - #if defined(USE_MANUAL_MEMORY) - // this is an array, needs a few bytes - manual_memory_channel_args_e = channel_mode_args_e + NUM_CHANNEL_MODES, - // and this is an ugly ugly kludge - // FIXME: use a struct for eeprom, not an array - eeprom_indexes_e_END = manual_memory_channel_args_e + NUM_CHANNEL_MODES - #else - eeprom_indexes_e_END = channel_mode_args_e + NUM_CHANNEL_MODES - #endif - #else - eeprom_indexes_e_END + + ///// hardware config / globals menu + #ifdef USE_JUMP_START + uint8_t jump_start_level; #endif -} eeprom_indexes_e; -#define EEPROM_BYTES eeprom_indexes_e_END + +} Config; + +// auto-detect how many eeprom bytes +#define EEPROM_BYTES sizeof(Config) + +// declare this so FSM can see it, +// but define its values in a file which loads later +Config cfg; #ifdef START_AT_MEMORIZED_LEVEL #define USE_EEPROM_WL #define EEPROM_WL_BYTES 1 #endif - -#endif diff --git a/spaghetti-monster/anduril/load-save-config.c b/spaghetti-monster/anduril/load-save-config.c index ad84450..aa772e1 100644 --- a/spaghetti-monster/anduril/load-save-config.c +++ b/spaghetti-monster/anduril/load-save-config.c @@ -1,114 +1,17 @@ -/* - * load-save-config.c: Load/save/eeprom functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// load-save-config.c: Load/save/eeprom functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef LOAD_SAVE_CONFIG_C -#define LOAD_SAVE_CONFIG_C +#pragma once #include "load-save-config-fsm.h" #include "load-save-config.h" void load_config() { - if (load_eeprom()) { - ramp_style = eeprom[ramp_style_e]; - #ifdef USE_RAMP_CONFIG - ramp_floors[0] = eeprom[ramp_smooth_floor_e]; - ramp_ceils[0] = eeprom[ramp_smooth_ceil_e]; - #ifdef USE_RAMP_SPEED_CONFIG - ramp_speed = eeprom[ramp_speed_e]; - #endif - ramp_floors[1] = eeprom[ramp_discrete_floor_e]; - ramp_ceils[1] = eeprom[ramp_discrete_ceil_e]; - ramp_stepss[1] = eeprom[ramp_discrete_steps_e]; - #endif - #ifdef USE_SIMPLE_UI - ramp_floors[2] = eeprom[simple_ui_floor_e]; - ramp_ceils[2] = eeprom[simple_ui_ceil_e]; - ramp_stepss[2] = eeprom[simple_ui_steps_e]; - simple_ui_active = eeprom[simple_ui_active_e]; - #ifdef USE_2C_STYLE_CONFIG - ramp_2c_style_simple = eeprom[ramp_2c_style_simple_e]; - #endif - #endif - #ifdef USE_RAMP_AFTER_MOON_CONFIG - dont_ramp_after_moon = eeprom[dont_ramp_after_moon_e]; - #endif - #ifdef USE_2C_STYLE_CONFIG - ramp_2c_style = eeprom[ramp_2c_style_e]; - #endif - #ifdef USE_MANUAL_MEMORY - manual_memory = eeprom[manual_memory_e]; - #ifdef USE_MANUAL_MEMORY_TIMER - manual_memory_timer = eeprom[manual_memory_timer_e]; - #endif - #endif - #ifdef USE_JUMP_START - jump_start_level = eeprom[jump_start_level_e], - #endif - #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) - strobe_type = eeprom[strobe_type_e]; // TODO: move this to eeprom_wl? - strobe_delays[0] = eeprom[strobe_delays_0_e]; - strobe_delays[1] = eeprom[strobe_delays_1_e]; - #endif - #ifdef USE_BIKE_FLASHER_MODE - bike_flasher_brightness = eeprom[bike_flasher_brightness_e]; - #endif - #ifdef USE_BEACON_MODE - beacon_seconds = eeprom[beacon_seconds_e]; - #endif - #ifdef USE_THERMAL_REGULATION - therm_ceil = eeprom[therm_ceil_e]; - therm_cal_offset = eeprom[therm_cal_offset_e]; - #endif - #ifdef USE_VOLTAGE_CORRECTION - voltage_correction = eeprom[voltage_correction_e]; - #endif - #ifdef USE_INDICATOR_LED - indicator_led_mode = eeprom[indicator_led_mode_e]; - #endif - #ifdef USE_AUX_RGB_LEDS - rgb_led_off_mode = eeprom[rgb_led_off_mode_e]; - rgb_led_lockout_mode = eeprom[rgb_led_lockout_mode_e]; - #endif - #ifdef USE_AUTOLOCK - autolock_time = eeprom[autolock_time_e]; - #endif - #ifdef USE_TACTICAL_MODE - tactical_levels[0] = eeprom[tactical_lvl_1_e]; - tactical_levels[1] = eeprom[tactical_lvl_2_e]; - tactical_levels[2] = eeprom[tactical_lvl_3_e]; - #endif - #if NUM_CHANNEL_MODES > 1 - channel_mode = eeprom[channel_mode_e]; - channel_modes_enabled = eeprom[channel_modes_enabled_e]; - #if defined(USE_MANUAL_MEMORY) - manual_memory_channel_mode = eeprom[manual_memory_channel_mode_e]; - #endif - #endif - #ifdef USE_CHANNEL_MODE_ARGS - for (uint8_t i=0; i 1 - eeprom[channel_mode_e] = channel_mode; - eeprom[channel_modes_enabled_e] = channel_modes_enabled; - #if defined(USE_MANUAL_MEMORY) - eeprom[manual_memory_channel_mode_e] = manual_memory_channel_mode; - #endif - #endif - #ifdef USE_CHANNEL_MODE_ARGS - for (uint8_t i=0; i. - */ - -#ifndef LOAD_SAVE_CONFIG_H -#define LOAD_SAVE_CONFIG_H +// load-save-config.h: Load/save/eeprom functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once // remember stuff even after battery was changed void load_config(); @@ -27,5 +11,139 @@ void save_config(); void save_config_wl(); #endif +// a struct to hold config values +Config cfg = { + + ///// ramp vars + + // smooth vs discrete ramping + .ramp_style = RAMP_STYLE, // 0 = smooth, 1 = discrete + #ifdef USE_2C_STYLE_CONFIG + // 1 = A1 style, 2 = A2 style + .ramp_2c_style = DEFAULT_2C_STYLE, + #endif + + // settings for each ramp (smooth, stepped, simple UI) + #ifdef USE_RAMP_CONFIG + .ramp_floors = { + RAMP_SMOOTH_FLOOR, + RAMP_DISCRETE_FLOOR, + #ifdef USE_SIMPLE_UI + SIMPLE_UI_FLOOR, + #endif + }, + .ramp_ceils = { + RAMP_SMOOTH_CEIL, + RAMP_DISCRETE_CEIL, + #ifdef USE_SIMPLE_UI + SIMPLE_UI_CEIL, + #endif + }, + .ramp_stepss = { + DEFAULT_RAMP_SPEED, + RAMP_DISCRETE_STEPS, + #ifdef USE_SIMPLE_UI + SIMPLE_UI_STEPS, + #endif + }, + #endif + + #ifdef USE_SIMPLE_UI + // whether to enable the simplified interface or not + .simple_ui_active = SIMPLE_UI_ACTIVE, + #ifdef USE_2C_STYLE_CONFIG + // 0 = no turbo, 1 = A1 style, 2 = A2 style + .ramp_2c_style_simple = DEFAULT_2C_STYLE_SIMPLE, + #endif + #endif + + .dont_ramp_after_moon = DEFAULT_DONT_RAMP_AFTER_MOON, + + #ifdef USE_MANUAL_MEMORY + .manual_memory = DEFAULT_MANUAL_MEMORY, + #ifdef USE_MANUAL_MEMORY_TIMER + .manual_memory_timer = DEFAULT_MANUAL_MEMORY_TIMER, + #endif + #endif + + ///// channel modes / color modes + + #if NUM_CHANNEL_MODES > 1 + // current multi-channel mode + .channel_mode = DEFAULT_CHANNEL_MODE, + // user can take unwanted modes out of the rotation (bitmask) + .channel_modes_enabled = CHANNEL_MODES_ENABLED, + #ifdef USE_MANUAL_MEMORY + // reset w/ manual memory + .manual_memory_channel_mode = DEFAULT_CHANNEL_MODE, + #endif + #endif + #ifdef USE_CHANNEL_MODE_ARGS + // one byte of extra data per channel mode, like for tint value + .channel_mode_args = { CHANNEL_MODE_ARGS }, + #ifdef USE_MANUAL_MEMORY + // remember and reset 1 extra parameter per channel mode (like tint) + .manual_memory_channel_args = { CHANNEL_MODE_ARGS }, + #endif + #endif + + ///// strobe / blinky mode settings + + #ifdef USE_STROBE_STATE + .strobe_type = DEFAULT_STROBE, + #endif + #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) + // party / tactical strobe timing + // party strobe 24 Hz, tactical strobe 10 Hz + .strobe_delays = { 41, 67 }, + #endif + #ifdef USE_BIKE_FLASHER_MODE + .bike_flasher_brightness = MAX_1x7135, + #endif + #ifdef USE_BEACON_MODE + // beacon timing + .beacon_seconds = 2, + #endif + + ///// voltage and temperature + + #ifdef USE_VOLTAGE_CORRECTION + // same 0.05V units as fudge factor, + // but 7 is neutral, and the expected range is from 1 to 13 + .voltage_correction = 7, + #endif + #ifdef USE_THERMAL_REGULATION + .therm_ceil = DEFAULT_THERM_CEIL, + .therm_cal_offset = 0, + #endif + + ///// aux LEDs + + #ifdef USE_INDICATOR_LED + // bits 2-3 control lockout mode + // bits 0-1 control "off" mode + // modes are: 0=off, 1=low, 2=high, 3=blinking (if TICK_DURING_STANDBY enabled) + .indicator_led_mode = INDICATOR_LED_DEFAULT_MODE, + #endif + #ifdef USE_AUX_RGB_LEDS + .rgb_led_off_mode = RGB_LED_OFF_DEFAULT, + .rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT, + #endif + + ///// misc other mode settings + + #ifdef USE_AUTOLOCK + .autolock_time = DEFAULT_AUTOLOCK_TIME, + #endif + #ifdef USE_TACTICAL_MODE + .tactical_levels = { TACTICAL_LEVELS }, + #endif + + ///// hardware config / globals menu + + #ifdef USE_JUMP_START + .jump_start_level = DEFAULT_JUMP_START_LEVEL, + #endif + +}; -#endif diff --git a/spaghetti-monster/anduril/lockout-mode.c b/spaghetti-monster/anduril/lockout-mode.c index 4997f29..3bf7ce0 100644 --- a/spaghetti-monster/anduril/lockout-mode.c +++ b/spaghetti-monster/anduril/lockout-mode.c @@ -33,14 +33,14 @@ uint8_t lockout_state(Event event, uint16_t arg) { if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) { // hold: lowest floor // click, hold: highest floor (or manual mem level) - uint8_t lvl = ramp_floors[0]; + uint8_t lvl = cfg.ramp_floors[0]; if ((event & 0x0f) == 2) { // second click - if (ramp_floors[1] > lvl) lvl = ramp_floors[1]; + if (cfg.ramp_floors[1] > lvl) lvl = cfg.ramp_floors[1]; #ifdef USE_MANUAL_MEMORY - if (manual_memory) lvl = manual_memory; + if (cfg.manual_memory) lvl = cfg.manual_memory; #endif } else { // anything except second click - if (ramp_floors[1] < lvl) lvl = ramp_floors[1]; + if (cfg.ramp_floors[1] < lvl) lvl = cfg.ramp_floors[1]; } set_level(lvl); } @@ -58,11 +58,11 @@ uint8_t lockout_state(Event event, uint16_t arg) { #ifdef USE_INDICATOR_LED // redundant, sleep tick does the same thing //if (event == EV_enter_state) { - // indicator_led_update(indicator_led_mode >> 2, 0); + // indicator_led_update(cfg.indicator_led_mode >> 2, 0); //} else #elif defined(USE_AUX_RGB_LEDS) if (event == EV_enter_state) { - rgb_led_update(rgb_led_lockout_mode, 0); + rgb_led_update(cfg.rgb_led_lockout_mode, 0); } else #endif @@ -71,9 +71,9 @@ uint8_t lockout_state(Event event, uint16_t arg) { go_to_standby = 1; #ifdef USE_INDICATOR_LED // redundant, sleep tick does the same thing - //indicator_led_update(indicator_led_mode >> 2, arg); + //indicator_led_update(cfg.indicator_led_mode >> 2, arg); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(rgb_led_lockout_mode, arg); + rgb_led_update(cfg.rgb_led_lockout_mode, arg); #endif } return MISCHIEF_MANAGED; @@ -82,9 +82,9 @@ uint8_t lockout_state(Event event, uint16_t arg) { #if defined(TICK_DURING_STANDBY) && (defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS)) else if (event == EV_sleep_tick) { #if defined(USE_INDICATOR_LED) - indicator_led_update(indicator_led_mode >> 2, arg); + indicator_led_update(cfg.indicator_led_mode >> 2, arg); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(rgb_led_lockout_mode, arg); + rgb_led_update(cfg.rgb_led_lockout_mode, arg); #endif return MISCHIEF_MANAGED; } @@ -101,8 +101,8 @@ uint8_t lockout_state(Event event, uint16_t arg) { else if (event == EV_4clicks) { #ifdef USE_MANUAL_MEMORY // FIXME: memory timer is totally ignored - if (manual_memory) - set_state(steady_state, manual_memory); + if (cfg.manual_memory) + set_state(steady_state, cfg.manual_memory); else #endif set_state(steady_state, memorized_level); @@ -129,7 +129,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { ////////// Every action below here is blocked in the (non-Extended) Simple UI ////////// #if defined(USE_SIMPLE_UI) && !defined(USE_EXTENDED_SIMPLE_UI) - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif // if simple UI but not extended simple UI @@ -138,7 +138,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { // 7 clicks: rotate through indicator LED modes (lockout mode) else if (event == EV_7clicks) { #if defined(USE_INDICATOR_LED) - uint8_t mode = indicator_led_mode >> 2; + uint8_t mode = cfg.indicator_led_mode >> 2; #ifdef TICK_DURING_STANDBY mode = (mode + 1) & 3; #else @@ -147,9 +147,9 @@ uint8_t lockout_state(Event event, uint16_t arg) { #ifdef INDICATOR_LED_SKIP_LOW if (mode == 1) { mode ++; } #endif - indicator_led_mode = (mode << 2) + (indicator_led_mode & 0x03); + cfg.indicator_led_mode = (mode << 2) + (cfg.indicator_led_mode & 0x03); // redundant, sleep tick does the same thing - //indicator_led_update(indicator_led_mode >> 2, arg); + //indicator_led_update(cfg.indicator_led_mode >> 2, arg); #elif defined(USE_AUX_RGB_LEDS) #endif save_config(); @@ -158,10 +158,10 @@ uint8_t lockout_state(Event event, uint16_t arg) { #elif defined(USE_AUX_RGB_LEDS) // 7 clicks: change RGB aux LED pattern else if (event == EV_7clicks) { - uint8_t mode = (rgb_led_lockout_mode >> 4) + 1; + uint8_t mode = (cfg.rgb_led_lockout_mode >> 4) + 1; mode = mode % RGB_LED_NUM_PATTERNS; - rgb_led_lockout_mode = (mode << 4) | (rgb_led_lockout_mode & 0x0f); - rgb_led_update(rgb_led_lockout_mode, 0); + cfg.rgb_led_lockout_mode = (mode << 4) | (cfg.rgb_led_lockout_mode & 0x0f); + rgb_led_update(cfg.rgb_led_lockout_mode, 0); save_config(); blink_once(); return MISCHIEF_MANAGED; @@ -170,12 +170,12 @@ uint8_t lockout_state(Event event, uint16_t arg) { else if (event == EV_click7_hold) { setting_rgb_mode_now = 1; if (0 == (arg & 0x3f)) { - uint8_t mode = (rgb_led_lockout_mode & 0x0f) + 1; + uint8_t mode = (cfg.rgb_led_lockout_mode & 0x0f) + 1; mode = mode % RGB_LED_NUM_COLORS; - rgb_led_lockout_mode = mode | (rgb_led_lockout_mode & 0xf0); + cfg.rgb_led_lockout_mode = mode | (cfg.rgb_led_lockout_mode & 0xf0); //save_config(); } - rgb_led_update(rgb_led_lockout_mode, arg); + rgb_led_update(cfg.rgb_led_lockout_mode, arg); return MISCHIEF_MANAGED; } // 7H, release: save new color @@ -188,7 +188,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { #if defined(USE_EXTENDED_SIMPLE_UI) && defined(USE_SIMPLE_UI) ////////// Every action below here is blocked in the Extended Simple UI ////////// - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif // if extended simple UI @@ -207,7 +207,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { #ifdef USE_AUTOLOCK // set the auto-lock timer to N minutes, where N is the number of clicks void autolock_config_save(uint8_t step, uint8_t value) { - autolock_time = value; + cfg.autolock_time = value; } uint8_t autolock_config_state(Event event, uint16_t arg) { diff --git a/spaghetti-monster/anduril/lockout-mode.h b/spaghetti-monster/anduril/lockout-mode.h index 1c9c081..37b02ab 100644 --- a/spaghetti-monster/anduril/lockout-mode.h +++ b/spaghetti-monster/anduril/lockout-mode.h @@ -27,7 +27,6 @@ uint8_t lockout_state(Event event, uint16_t arg); #ifndef DEFAULT_AUTOLOCK_TIME #define DEFAULT_AUTOLOCK_TIME 0 // autolock time in minutes, 0 = disabled #endif -uint8_t autolock_time = DEFAULT_AUTOLOCK_TIME; uint8_t autolock_config_state(Event event, uint16_t arg); #endif diff --git a/spaghetti-monster/anduril/off-mode.c b/spaghetti-monster/anduril/off-mode.c index c459979..d9ab5cb 100644 --- a/spaghetti-monster/anduril/off-mode.c +++ b/spaghetti-monster/anduril/off-mode.c @@ -33,9 +33,9 @@ uint8_t off_state(Event event, uint16_t arg) { set_level(0); #ifdef USE_INDICATOR_LED // redundant, sleep tick does the same thing - //indicator_led_update(indicator_led_mode & 0x03, 0); + //indicator_led_update(cfg.indicator_led_mode & 0x03, 0); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(rgb_led_off_mode, 0); + rgb_led_update(cfg.rgb_led_off_mode, 0); #endif #ifdef USE_SUNSET_TIMER sunset_timer = 0; // needs a reset in case previous timer was aborted @@ -52,9 +52,9 @@ uint8_t off_state(Event event, uint16_t arg) { go_to_standby = 1; #ifdef USE_INDICATOR_LED // redundant, sleep tick does the same thing - //indicator_led_update(indicator_led_mode & 0x03, arg); + //indicator_led_update(cfg.indicator_led_mode & 0x03, arg); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(rgb_led_off_mode, arg); + rgb_led_update(cfg.rgb_led_off_mode, arg); #endif } return MISCHIEF_MANAGED; @@ -65,21 +65,21 @@ uint8_t off_state(Event event, uint16_t arg) { else if (event == EV_sleep_tick) { #ifdef USE_MANUAL_MEMORY_TIMER // reset to manual memory level when timer expires - if (manual_memory && - (arg >= (manual_memory_timer * SLEEP_TICKS_PER_MINUTE))) { + if (cfg.manual_memory && + (arg >= (cfg.manual_memory_timer * SLEEP_TICKS_PER_MINUTE))) { manual_memory_restore(); } #endif #ifdef USE_INDICATOR_LED - indicator_led_update(indicator_led_mode & 0x03, arg); + indicator_led_update(cfg.indicator_led_mode & 0x03, arg); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(rgb_led_off_mode, arg); + rgb_led_update(cfg.rgb_led_off_mode, arg); #endif #ifdef USE_AUTOLOCK // lock the light after being off for N minutes - uint16_t ticks = autolock_time * SLEEP_TICKS_PER_MINUTE; - if ((autolock_time > 0) && (arg > ticks)) { + uint16_t ticks = cfg.autolock_time * SLEEP_TICKS_PER_MINUTE; + if ((cfg.autolock_time > 0) && (arg > ticks)) { set_state(lockout_state, 0); } #endif // ifdef USE_AUTOLOCK @@ -108,14 +108,14 @@ uint8_t off_state(Event event, uint16_t arg) { set_level(nearest_level(1)); #endif #ifdef USE_RAMP_AFTER_MOON_CONFIG - if (dont_ramp_after_moon) { + if (cfg.dont_ramp_after_moon) { return MISCHIEF_MANAGED; } #endif // don't start ramping immediately; // give the user time to release at moon level //if (arg >= HOLD_TIMEOUT) { // smaller - if (arg >= (!ramp_style) * HOLD_TIMEOUT) { // more consistent + if (arg >= (!cfg.ramp_style) * HOLD_TIMEOUT) { // more consistent set_state(steady_state, 1); } return MISCHIEF_MANAGED; @@ -133,7 +133,7 @@ uint8_t off_state(Event event, uint16_t arg) { #if defined(USE_MANUAL_MEMORY) && !defined(USE_MANUAL_MEMORY_TIMER) // this clause probably isn't used by any configs any more // but is included just in case someone configures it this way - if (manual_memory) { + if (cfg.manual_memory) { manual_memory_restore(); } #endif @@ -160,10 +160,10 @@ uint8_t off_state(Event event, uint16_t arg) { uint8_t turbo_level; // how bright is "turbo"? #if defined(USE_2C_STYLE_CONFIG) // user can choose 2C behavior - uint8_t style_2c = ramp_2c_style; + uint8_t style_2c = cfg.ramp_2c_style; #ifdef USE_SIMPLE_UI // simple UI has its own turbo config - if (simple_ui_active) style_2c = ramp_2c_style_simple; + if (cfg.simple_ui_active) style_2c = cfg.ramp_2c_style_simple; #endif // 0 = ceiling // 1+ = full power @@ -173,7 +173,7 @@ uint8_t off_state(Event event, uint16_t arg) { // simple UI: ceiling // full UI: full power #ifdef USE_SIMPLE_UI - if (simple_ui_active) turbo_level = nearest_level(MAX_LEVEL); + if (cfg.simple_ui_active) turbo_level = nearest_level(MAX_LEVEL); else #endif turbo_level = MAX_LEVEL; @@ -235,9 +235,9 @@ uint8_t off_state(Event event, uint16_t arg) { #ifdef USE_SIMPLE_UI // 10 clicks, but hold last click: turn simple UI off (or configure it) else if ((event == EV_click10_hold) && (!arg)) { - if (simple_ui_active) { // turn off simple UI + if (cfg.simple_ui_active) { // turn off simple UI blink_once(); - simple_ui_active = 0; + cfg.simple_ui_active = 0; save_config(); } else { // configure simple UI ramp @@ -249,7 +249,7 @@ uint8_t off_state(Event event, uint16_t arg) { ////////// Every action below here is blocked in the (non-Extended) Simple UI ////////// #ifndef USE_EXTENDED_SIMPLE_UI - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif // ifndef USE_EXTENDED_SIMPLE_UI @@ -271,7 +271,7 @@ uint8_t off_state(Event event, uint16_t arg) { #ifdef USE_INDICATOR_LED // 7 clicks: change indicator LED mode else if (event == EV_7clicks) { - uint8_t mode = (indicator_led_mode & 3) + 1; + uint8_t mode = (cfg.indicator_led_mode & 3) + 1; #ifdef TICK_DURING_STANDBY mode = mode & 3; #else @@ -280,19 +280,19 @@ uint8_t off_state(Event event, uint16_t arg) { #ifdef INDICATOR_LED_SKIP_LOW if (mode == 1) { mode ++; } #endif - indicator_led_mode = (indicator_led_mode & 0b11111100) | mode; + cfg.indicator_led_mode = (cfg.indicator_led_mode & 0b11111100) | mode; // redundant, sleep tick does the same thing - //indicator_led_update(indicator_led_mode & 0x03, arg); + //indicator_led_update(cfg.indicator_led_mode & 0x03, arg); save_config(); return MISCHIEF_MANAGED; } #elif defined(USE_AUX_RGB_LEDS) // 7 clicks: change RGB aux LED pattern else if (event == EV_7clicks) { - uint8_t mode = (rgb_led_off_mode >> 4) + 1; + uint8_t mode = (cfg.rgb_led_off_mode >> 4) + 1; mode = mode % RGB_LED_NUM_PATTERNS; - rgb_led_off_mode = (mode << 4) | (rgb_led_off_mode & 0x0f); - rgb_led_update(rgb_led_off_mode, 0); + cfg.rgb_led_off_mode = (mode << 4) | (cfg.rgb_led_off_mode & 0x0f); + rgb_led_update(cfg.rgb_led_off_mode, 0); save_config(); blink_once(); return MISCHIEF_MANAGED; @@ -301,12 +301,12 @@ uint8_t off_state(Event event, uint16_t arg) { else if (event == EV_click7_hold) { setting_rgb_mode_now = 1; if (0 == (arg & 0x3f)) { - uint8_t mode = (rgb_led_off_mode & 0x0f) + 1; + uint8_t mode = (cfg.rgb_led_off_mode & 0x0f) + 1; mode = mode % RGB_LED_NUM_COLORS; - rgb_led_off_mode = mode | (rgb_led_off_mode & 0xf0); + cfg.rgb_led_off_mode = mode | (cfg.rgb_led_off_mode & 0xf0); //save_config(); } - rgb_led_update(rgb_led_off_mode, arg); + rgb_led_update(cfg.rgb_led_off_mode, arg); return MISCHIEF_MANAGED; } else if (event == EV_click7_hold_release) { @@ -320,7 +320,7 @@ uint8_t off_state(Event event, uint16_t arg) { #ifdef USE_SIMPLE_UI #ifdef USE_EXTENDED_SIMPLE_UI - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif // ifdef USE_EXTENDED_SIMPLE_UI @@ -328,7 +328,7 @@ uint8_t off_state(Event event, uint16_t arg) { // 10 clicks: enable simple UI else if (event == EV_10clicks) { blink_once(); - simple_ui_active = 1; + cfg.simple_ui_active = 1; save_config(); return MISCHIEF_MANAGED; } diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index a87e9b0..88b141e 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -27,16 +27,16 @@ uint8_t steady_state(Event event, uint16_t arg) { uint8_t mode_min = ramp_floor; uint8_t mode_max = ramp_ceil; uint8_t step_size; - if (ramp_style) { step_size = ramp_discrete_step_size; } + if (cfg.ramp_style) { step_size = ramp_discrete_step_size; } else { step_size = 1; } // how bright is "turbo"? uint8_t turbo_level; #if defined(USE_2C_STYLE_CONFIG) // user can choose 2C behavior - uint8_t style_2c = ramp_2c_style; + uint8_t style_2c = cfg.ramp_2c_style; #ifdef USE_SIMPLE_UI // simple UI has its own turbo config - if (simple_ui_active) style_2c = ramp_2c_style_simple; + if (cfg.simple_ui_active) style_2c = cfg.ramp_2c_style_simple; #endif // 0 = no turbo // 1 = Anduril 1 direct to turbo @@ -51,7 +51,7 @@ uint8_t steady_state(Event event, uint16_t arg) { // simple UI: to/from ceiling // full UI: to/from turbo (Anduril1 behavior) #ifdef USE_SIMPLE_UI - if (simple_ui_active) turbo_level = mode_max; + if (cfg.simple_ui_active) turbo_level = mode_max; else #endif turbo_level = MAX_LEVEL; @@ -61,7 +61,7 @@ uint8_t steady_state(Event event, uint16_t arg) { // or to/from turbo if mem >= ceiling if ((memorized_level < mode_max) #ifdef USE_SIMPLE_UI - || simple_ui_active + || cfg.simple_ui_active #endif ) { turbo_level = mode_max; } else { turbo_level = MAX_LEVEL; } @@ -146,12 +146,12 @@ uint8_t steady_state(Event event, uint16_t arg) { // click, hold: change brightness (dimmer) else if ((event == EV_click1_hold) || (event == EV_click2_hold)) { // ramp slower in discrete mode - if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { + if (cfg.ramp_style && (arg % HOLD_TIMEOUT != 0)) { return MISCHIEF_MANAGED; } #ifdef USE_RAMP_SPEED_CONFIG // ramp slower if user configured things that way - if ((! ramp_style) && (arg % ramp_speed)) { + if ((! cfg.ramp_style) && (arg % ramp_speed)) { return MISCHIEF_MANAGED; } #endif @@ -211,13 +211,13 @@ uint8_t steady_state(Event event, uint16_t arg) { } #endif #if defined(BLINK_AT_STEPS) - uint8_t foo = ramp_style; - ramp_style = 1; + uint8_t foo = cfg.ramp_style; + cfg.ramp_style = 1; uint8_t nearest = nearest_level((int16_t)actual_level); - ramp_style = foo; + cfg.ramp_style = foo; // only blink once for each threshold if ((memorized_level != actual_level) && - (ramp_style == 0) && + (cfg.ramp_style == 0) && (memorized_level == nearest) ) { @@ -360,7 +360,7 @@ uint8_t steady_state(Event event, uint16_t arg) { ////////// Every action below here is blocked in the simple UI ////////// // That is, unless we specifically want to enable 3C for smooth/stepped selection in Simple UI #if defined(USE_SIMPLE_UI) && !defined(USE_SIMPLE_UI_RAMPING_TOGGLE) - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif @@ -386,7 +386,7 @@ uint8_t steady_state(Event event, uint16_t arg) { ) { #endif - ramp_style = !ramp_style; + cfg.ramp_style = !cfg.ramp_style; save_config(); #ifdef START_AT_MEMORIZED_LEVEL save_config_wl(); @@ -402,13 +402,14 @@ uint8_t steady_state(Event event, uint16_t arg) { // If we allowed 3C in Simple UI, now block further actions #if defined(USE_SIMPLE_UI) && defined(USE_SIMPLE_UI_RAMPING_TOGGLE) - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif // 3H: momentary turbo (on lights with no tint ramping) // (or 4H on lights with tint ramping) + // FIXME: handle 3H if channel mode has no args else if (event == EV_MOMENTARY_TURBO) { if (! arg) { // first frame only, to allow thermal regulation to work #ifdef USE_2C_STYLE_CONFIG @@ -457,7 +458,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #else // manual mem, but no timer // turn off manual memory; go back to automatic if (0 == arg) { - manual_memory = 0; + cfg.manual_memory = 0; save_config(); blink_once(); } @@ -474,7 +475,7 @@ uint8_t steady_state(Event event, uint16_t arg) { void ramp_config_save(uint8_t step, uint8_t value) { // 0 = smooth ramp, 1 = stepped ramp, 2 = simple UI's ramp - uint8_t style = ramp_style; + uint8_t style = cfg.ramp_style; #ifdef USE_SIMPLE_UI if (current_state == simple_ui_config_state) style = 2; #endif @@ -483,7 +484,7 @@ void ramp_config_save(uint8_t step, uint8_t value) { // simple UI config is weird... // has some ramp extras after floor/ceil/steps if (4 == step) { - ramp_2c_style_simple = value; + cfg.ramp_2c_style_simple = value; } else #endif @@ -496,7 +497,7 @@ void ramp_config_save(uint8_t step, uint8_t value) { // which option are we configuring? // TODO? maybe rearrange definitions to avoid the need for this table // (move all ramp values into a single array?) - uint8_t *steps[] = { ramp_floors, ramp_ceils, ramp_stepss }; + uint8_t *steps[] = { cfg.ramp_floors, cfg.ramp_ceils, cfg.ramp_stepss }; uint8_t *option; option = steps[step-1]; option[style] = value; @@ -507,7 +508,7 @@ uint8_t ramp_config_state(Event event, uint16_t arg) { #ifdef USE_RAMP_SPEED_CONFIG const uint8_t num_config_steps = 3; #else - uint8_t num_config_steps = ramp_style + 2; + uint8_t num_config_steps = cfg.ramp_style + 2; #endif return config_state_base(event, arg, num_config_steps, ramp_config_save); @@ -530,14 +531,14 @@ uint8_t simple_ui_config_state(Event event, uint16_t arg) { #ifdef USE_RAMP_EXTRAS_CONFIG void ramp_extras_config_save(uint8_t step, uint8_t value) { // item 1: disable manual memory, go back to automatic - if (1 == step) { manual_memory = 0; } + if (1 == step) { cfg.manual_memory = 0; } #ifdef USE_MANUAL_MEMORY_TIMER // item 2: set manual memory timer duration // FIXME: should be limited to (65535 / SLEEP_TICKS_PER_MINUTE) // to avoid overflows or impossibly long timeouts // (by default, the effective limit is 145, but it allows up to 255) - else if (2 == step) { manual_memory_timer = value; } + else if (2 == step) { cfg.manual_memory_timer = value; } #endif #ifdef USE_RAMP_AFTER_MOON_CONFIG @@ -545,7 +546,7 @@ void ramp_extras_config_save(uint8_t step, uint8_t value) { // 0 = yes, ramp after moon // 1+ = no, stay at moon else if (3 == step) { - dont_ramp_after_moon = value; + cfg.dont_ramp_after_moon = value; } #endif @@ -554,7 +555,7 @@ void ramp_extras_config_save(uint8_t step, uint8_t value) { // 1 = Anduril 1, 2C turbo // 2+ = Anduril 2, 2C ceiling else if (4 == step) { - ramp_2c_style = value; + cfg.ramp_2c_style = value; } #endif } @@ -575,7 +576,7 @@ void globals_config_save(uint8_t step, uint8_t value) { } #endif #ifdef USE_JUMP_START - else if (step == 1+jump_start_config_step) { jump_start_level = value; } + else if (step == 1+jump_start_config_step) { cfg.jump_start_level = value; } #endif } @@ -597,20 +598,20 @@ uint8_t nearest_level(int16_t target) { // bounds check uint8_t mode_min = ramp_floor; uint8_t mode_max = ramp_ceil; - uint8_t num_steps = ramp_stepss[1 + uint8_t num_steps = cfg.ramp_stepss[1 #ifdef USE_SIMPLE_UI - + simple_ui_active + + cfg.simple_ui_active #endif ]; // special case for 1-step ramp... use halfway point between floor and ceiling - if (ramp_style && (1 == num_steps)) { + if (cfg.ramp_style && (1 == num_steps)) { uint8_t mid = (mode_max + mode_min) >> 1; return mid; } if (target < mode_min) return mode_min; if (target > mode_max) return mode_max; // the rest isn't relevant for smooth ramping - if (! ramp_style) return target; + if (! cfg.ramp_style) return target; uint8_t ramp_range = mode_max - mode_min; ramp_discrete_step_size = ramp_range / (num_steps-1); @@ -628,13 +629,13 @@ uint8_t nearest_level(int16_t target) { // ensure ramp globals are correct void ramp_update_config() { - uint8_t which = ramp_style; + uint8_t which = cfg.ramp_style; #ifdef USE_SIMPLE_UI - if (simple_ui_active) { which = 2; } + if (cfg.simple_ui_active) { which = 2; } #endif - ramp_floor = ramp_floors[which]; - ramp_ceil = ramp_ceils[which]; + ramp_floor = cfg.ramp_floors[which]; + ramp_ceil = cfg.ramp_ceils[which]; } #ifdef USE_THERMAL_REGULATION @@ -647,24 +648,24 @@ void set_level_and_therm_target(uint8_t level) { #endif void manual_memory_restore() { - memorized_level = manual_memory; + memorized_level = cfg.manual_memory; #if NUM_CHANNEL_MODES > 1 - channel_mode = manual_memory_channel_mode; + cfg.channel_mode = cfg.manual_memory_channel_mode; #endif #ifdef USE_CHANNEL_MODE_ARGS for (uint8_t i=0; i 1 - manual_memory_channel_mode = channel_mode; + cfg.manual_memory_channel_mode = cfg.channel_mode; #endif #ifdef USE_CHANNEL_MODE_ARGS for (uint8_t i=0; i 254) d = 254; - strobe_delays[st] = d; + cfg.strobe_delays[st] = d; } } #endif @@ -92,10 +92,10 @@ uint8_t strobe_state(Event event, uint16_t arg) { // biking mode brighter #ifdef USE_BIKE_FLASHER_MODE else if (st == bike_flasher_e) { - bike_flasher_brightness += ramp_direction; - if (bike_flasher_brightness < 2) bike_flasher_brightness = 2; - else if (bike_flasher_brightness > MAX_BIKING_LEVEL) bike_flasher_brightness = MAX_BIKING_LEVEL; - set_level(bike_flasher_brightness); + cfg.bike_flasher_brightness += ramp_direction; + if (cfg.bike_flasher_brightness < 2) cfg.bike_flasher_brightness = 2; + else if (cfg.bike_flasher_brightness > MAX_BIKING_LEVEL) cfg.bike_flasher_brightness = MAX_BIKING_LEVEL; + set_level(cfg.bike_flasher_brightness); } #endif @@ -123,7 +123,7 @@ uint8_t strobe_state(Event event, uint16_t arg) { else if (st == party_strobe_e) { #endif if ((arg & 1) == 0) { - if (strobe_delays[st] < 255) strobe_delays[st] ++; + if (cfg.strobe_delays[st] < 255) cfg.strobe_delays[st] ++; } } #endif @@ -134,9 +134,9 @@ uint8_t strobe_state(Event event, uint16_t arg) { // biking mode dimmer #ifdef USE_BIKE_FLASHER_MODE else if (st == bike_flasher_e) { - if (bike_flasher_brightness > 2) - bike_flasher_brightness --; - set_level(bike_flasher_brightness); + if (cfg.bike_flasher_brightness > 2) + cfg.bike_flasher_brightness --; + set_level(cfg.bike_flasher_brightness); } #endif @@ -170,7 +170,7 @@ uint8_t strobe_state(Event event, uint16_t arg) { // runs repeatedly in FSM loop() whenever UI is in strobe_state or momentary strobe inline void strobe_state_iter() { - uint8_t st = strobe_type; // can't use switch() on an enum + uint8_t st = cfg.strobe_type; // can't use switch() on an enum switch(st) { #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) @@ -208,7 +208,7 @@ inline void strobe_state_iter() { #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) inline void party_tactical_strobe_mode_iter(uint8_t st) { // one iteration of main loop() - uint8_t del = strobe_delays[st]; + uint8_t del = cfg.strobe_delays[st]; // TODO: make tac strobe brightness configurable? set_level(STROBE_BRIGHTNESS); if (0) {} // placeholder @@ -238,7 +238,7 @@ inline void police_color_strobe_iter() { uint8_t del = 66; // TODO: make police strobe brightness configurable uint8_t bright = memorized_level; - uint8_t channel = channel_mode; + uint8_t channel = cfg.channel_mode; for (uint8_t i=0; i<10; i++) { if (0 == i) set_channel_mode(POLICE_COLOR_STROBE_CH1); @@ -304,12 +304,12 @@ inline void lightning_storm_iter() { #ifdef USE_BIKE_FLASHER_MODE inline void bike_flasher_iter() { // one iteration of main loop() - uint8_t burst = bike_flasher_brightness << 1; + uint8_t burst = cfg.bike_flasher_brightness << 1; if (burst > MAX_LEVEL) burst = MAX_LEVEL; for(uint8_t i=0; i<4; i++) { set_level(burst); nice_delay_ms(5); - set_level(bike_flasher_brightness); + set_level(cfg.bike_flasher_brightness); nice_delay_ms(65); } nice_delay_ms(720); // no return check necessary on final delay diff --git a/spaghetti-monster/anduril/strobe-modes.h b/spaghetti-monster/anduril/strobe-modes.h index 685c249..0e7c873 100644 --- a/spaghetti-monster/anduril/strobe-modes.h +++ b/spaghetti-monster/anduril/strobe-modes.h @@ -48,9 +48,9 @@ const int NUM_STROBES = strobe_mode_END; // which strobe mode is active? #ifdef USE_CANDLE_MODE -strobe_mode_te strobe_type = candle_mode_e; + #define DEFAULT_STROBE candle_mode_e #else -strobe_mode_te strobe_type = 0; + #define DEFAULT_STROBE 0 #endif #endif @@ -79,8 +79,6 @@ inline void strobe_state_iter(); #endif #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) -// party / tactical strobe timing -uint8_t strobe_delays[] = { 41, 67 }; // party strobe 24 Hz, tactical strobe 10 Hz inline void party_tactical_strobe_mode_iter(uint8_t st); #endif @@ -95,7 +93,6 @@ inline void lightning_storm_iter(); // bike mode config options #ifdef USE_BIKE_FLASHER_MODE #define MAX_BIKING_LEVEL 120 // should be 127 or less -uint8_t bike_flasher_brightness = MAX_1x7135; inline void bike_flasher_iter(); #endif diff --git a/spaghetti-monster/anduril/sunset-timer.c b/spaghetti-monster/anduril/sunset-timer.c index bad317c..bb59ec9 100644 --- a/spaghetti-monster/anduril/sunset-timer.c +++ b/spaghetti-monster/anduril/sunset-timer.c @@ -10,7 +10,7 @@ uint8_t sunset_timer_state(Event event, uint16_t arg) { #if defined(USE_SIMPLE_UI) && !defined(USE_EXTENDED_SIMPLE_UI) // No timer functions in Simple UI - if (simple_ui_active) return EVENT_NOT_HANDLED; + if (cfg.simple_ui_active) return EVENT_NOT_HANDLED; #endif // reset on start diff --git a/spaghetti-monster/anduril/tactical-mode.c b/spaghetti-monster/anduril/tactical-mode.c index 7e9d66b..2447a11 100644 --- a/spaghetti-monster/anduril/tactical-mode.c +++ b/spaghetti-monster/anduril/tactical-mode.c @@ -22,8 +22,6 @@ #include "tactical-mode.h" -// TODO: save these in eeprom -uint8_t tactical_levels[] = { TACTICAL_LEVELS }; // high, low, strobe uint8_t tactical_state(Event event, uint16_t arg) { // momentary(ish) tactical mode @@ -42,14 +40,14 @@ uint8_t tactical_state(Event event, uint16_t arg) { if (click <= 3) { momentary_active = 1; uint8_t lvl; - lvl = tactical_levels[click-1]; + lvl = cfg.tactical_levels[click-1]; if ((1 <= lvl) && (lvl <= RAMP_SIZE)) { // steady output memorized_level = lvl; momentary_mode = 0; } else { // momentary strobe mode momentary_mode = 1; if (lvl > RAMP_SIZE) { - strobe_type = (lvl - RAMP_SIZE - 1) % strobe_mode_END; + cfg.strobe_type = (lvl - RAMP_SIZE - 1) % strobe_mode_END; } } } @@ -92,7 +90,7 @@ uint8_t tactical_state(Event event, uint16_t arg) { // (unnecessary since this entire mode is blocked in simple UI) /* #ifdef USE_SIMPLE_UI - if (simple_ui_active) { + if (cfg.simple_ui_active) { return EVENT_NOT_HANDLED; } #endif @@ -113,7 +111,7 @@ void tactical_config_save(uint8_t step, uint8_t value) { // each value is 1 to 150, or other: // - 1..150 is a ramp level // - other means "strobe mode" - tactical_levels[step - 1] = value; + cfg.tactical_levels[step - 1] = value; } uint8_t tactical_config_state(Event event, uint16_t arg) { diff --git a/spaghetti-monster/anduril/tactical-mode.h b/spaghetti-monster/anduril/tactical-mode.h index 4403314..14bf7ff 100644 --- a/spaghetti-monster/anduril/tactical-mode.h +++ b/spaghetti-monster/anduril/tactical-mode.h @@ -20,14 +20,13 @@ #ifndef TACTICAL_MODE_H #define TACTICAL_MODE_H -// tactical(ish) mode -uint8_t tactical_state(Event event, uint16_t arg); - #ifndef TACTICAL_LEVELS // high, low, tactical strobe #define TACTICAL_LEVELS 120,30,(RAMP_SIZE+2) #endif -uint8_t tactical_levels[]; + +// tactical(ish) mode +uint8_t tactical_state(Event event, uint16_t arg); uint8_t tactical_config_state(Event event, uint16_t arg); diff --git a/spaghetti-monster/anduril/tempcheck-mode.c b/spaghetti-monster/anduril/tempcheck-mode.c index f6e1ebe..2e3b56f 100644 --- a/spaghetti-monster/anduril/tempcheck-mode.c +++ b/spaghetti-monster/anduril/tempcheck-mode.c @@ -51,18 +51,18 @@ void thermal_config_save(uint8_t step, uint8_t value) { if (value) { // item 1: calibrate room temperature if (step == 1) { - int8_t rawtemp = temperature - therm_cal_offset; - therm_cal_offset = value - rawtemp; + int8_t rawtemp = temperature - cfg.therm_cal_offset; + cfg.therm_cal_offset = value - rawtemp; adc_reset = 2; // invalidate all recent temperature data } // item 2: set maximum heat limit else { - therm_ceil = 30 + value - 1; + cfg.therm_ceil = 30 + value - 1; } } - if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL; + if (cfg.therm_ceil > MAX_THERM_CEIL) cfg.therm_ceil = MAX_THERM_CEIL; } uint8_t thermal_config_state(Event event, uint16_t arg) { diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 60eb843..9dc8866 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -149,7 +149,7 @@ static inline uint8_t calc_voltage_divider(uint16_t value) { uint8_t result = ((value / adc_per_volt) + VOLTAGE_FUDGE_FACTOR #ifdef USE_VOLTAGE_CORRECTION - + voltage_correction - 7 + + VOLT_CORR - 7 #endif ) >> 1; return result; @@ -349,7 +349,7 @@ static inline void ADC_voltage_handler() { voltage = ((uint16_t)(2*1.1*1024*10)/(measurement>>6) + VOLTAGE_FUDGE_FACTOR #ifdef USE_VOLTAGE_CORRECTION - + voltage_correction - 7 + + VOLT_CORR - 7 #endif ) >> 1; #endif @@ -428,10 +428,10 @@ static inline void ADC_temperature_handler() { // Convert ADC units to Celsius (ish) #ifndef USE_EXTERNAL_TEMP_SENSOR // onboard sensor for attiny25/45/85/1634 - temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)therm_cal_offset - 275; + temperature = (measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL - 275; #else // external sensor - temperature = EXTERN_TEMP_FORMULA(measurement>>1) + THERM_CAL_OFFSET + (int16_t)therm_cal_offset; + temperature = EXTERN_TEMP_FORMULA(measurement>>1) + THERM_CAL_OFFSET + (int16_t)TH_CAL; #endif // how much has the temperature changed between now and a few seconds ago? @@ -447,10 +447,10 @@ static inline void ADC_temperature_handler() { pt = measurement + (diff * THERM_LOOKAHEAD); // convert temperature limit from C to raw 16-bit ADC units - // C = (ADC>>6) - 275 + THERM_CAL_OFFSET + therm_cal_offset; + // C = (ADC>>6) - 275 + THERM_CAL_OFFSET + TH_CAL; // ... so ... - // (C + 275 - THERM_CAL_OFFSET - therm_cal_offset) << 6 = ADC; - uint16_t ceil = (therm_ceil + 275 - therm_cal_offset - THERM_CAL_OFFSET) << 1; + // (C + 275 - THERM_CAL_OFFSET - TH_CAL) << 6 = ADC; + uint16_t ceil = (TH_CEIL + 275 - TH_CAL - THERM_CAL_OFFSET) << 1; int16_t offset = pt - ceil; // bias small errors toward zero, while leaving large errors mostly unaffected diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index db2bb7b..77f625a 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -63,9 +63,14 @@ void adc_deferred(); // do the actual ADC-related calculations static inline void ADC_voltage_handler(); uint8_t voltage = 0; #ifdef USE_VOLTAGE_CORRECTION -// same 0.05V units as fudge factor, -// but 7 is neutral, and the expected range is from 1 to 13 -uint8_t voltage_correction = 7; + #ifdef USE_CFG + #define VOLT_CORR cfg.voltage_correction + #else + // same 0.05V units as fudge factor, + // but 7 is neutral, and the expected range is from 1 to 13 + uint8_t voltage_correction = 7; + #define VOLT_CORR voltage_correction + #endif #endif #ifdef USE_LVP void low_voltage(); @@ -98,8 +103,15 @@ void battcheck(); #endif // temperature now, in C (ish) int16_t temperature; -uint8_t therm_ceil = DEFAULT_THERM_CEIL; -int8_t therm_cal_offset = 0; +#ifdef USE_CFG + #define TH_CEIL cfg.therm_ceil + #define TH_CAL cfg.therm_cal_offset +#else + #define TH_CEIL therm_ceil + #define TH_CAL therm_cal_offset + uint8_t therm_ceil = DEFAULT_THERM_CEIL; + int8_t therm_cal_offset = 0; +#endif static inline void ADC_temperature_handler(); #endif // ifdef USE_THERMAL_REGULATION diff --git a/spaghetti-monster/fsm-eeprom.h b/spaghetti-monster/fsm-eeprom.h index 3621106..cda290b 100644 --- a/spaghetti-monster/fsm-eeprom.h +++ b/spaghetti-monster/fsm-eeprom.h @@ -33,9 +33,10 @@ #endif #ifdef USE_EEPROM -#if EEPROM_BYTES >= (EEPSIZE/2) -#error Requested EEPROM_BYTES too big. -#endif +// this fails when EEPROM_BYTES is a sizeof() +//#if EEPROM_BYTES >= (EEPSIZE/2) +//#error Requested EEPROM_BYTES too big. +//#endif #ifdef EEPROM_OVERRIDE uint8_t *eeprom; #else diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c index a55c74b..14b0db8 100644 --- a/spaghetti-monster/fsm-ramping.c +++ b/spaghetti-monster/fsm-ramping.c @@ -16,7 +16,7 @@ void set_channel_mode(uint8_t mode) { set_level(0); // change the channel - channel_mode = mode; + CH_MODE = mode; // update the LEDs set_level(cur_level); @@ -61,8 +61,8 @@ void set_level(uint8_t level) { // TODO: allow different jump start behavior per channel mode if ((! actual_level) && level - && (level < jump_start_level)) { - set_level(jump_start_level); + && (level < JUMP_START_LEVEL)) { + set_level(JUMP_START_LEVEL); delay_4ms(JUMP_START_TIME/4); } #endif @@ -72,7 +72,7 @@ void set_level(uint8_t level) { #endif // call the relevant hardware-specific set_level_*() - SetLevelFuncPtr set_level_func = channel_modes[channel_mode]; + SetLevelFuncPtr set_level_func = channel_modes[CH_MODE]; set_level_func(level); actual_level = level; @@ -138,54 +138,52 @@ void set_level_3ch_stacked(uint8_t level) { // TODO: 2ch stacked w/ dynamic PWM // TODO: 2ch stacked w/ dynamic PWM and opamp enable pins? -#ifdef USE_SET_LEVEL_2CH_BLEND -// warm + cool blend w/ middle sag correction -void set_level_2ch_blend(uint8_t level) { +#ifdef USE_CALC_2CH_BLEND +// calculate a "tint ramp" blend between 2 channels +// results are placed in *warm and *cool vars +// brightness : total amount of light units to distribute +// top : maximum allowed brightness per channel +// blend : ratio between warm and cool (0 = warm, 128 = 50%, 255 = cool) +void calc_2ch_blend( + PWM_DATATYPE *warm, + PWM_DATATYPE *cool, + PWM_DATATYPE brightness, + PWM_DATATYPE top, + uint8_t blend) { + #ifndef TINT_RAMPING_CORRECTION #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint #endif - BLEND_PWM_DATATYPE vpwm; - - if (level == 0) { - vpwm = 0; - } else { - level --; // PWM array index = level - 1 - vpwm = PWM_GET(blend_pwm_levels, level); - } - // calculate actual PWM levels based on a single-channel ramp - // and a global tint value - uint16_t brightness = vpwm; - uint16_t warm_PWM, cool_PWM; - const uint16_t top = PWM_TOP; - - // auto-tint modes - uint8_t mytint = channel_mode_args[channel_mode]; - + // and a blend value + PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE2 base_PWM = brightness; + #if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0) + uint8_t level = actual_level - 1; + // middle tints sag, so correct for that effect // by adding extra power which peaks at the middle tint // (correction is only necessary when PWM is fast) if (level > HALFSPEED_LEVEL) { base_PWM = brightness + ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64) - * triangle_wave(mytint) / 255); + * triangle_wave(blend) / 255); } // fade the triangle wave out when above 100% power, // so it won't go over 200% if (brightness > top) { base_PWM -= 2 * ( ((brightness - top) * TINT_RAMPING_CORRECTION / 64) - * triangle_wave(mytint) / 255 + * triangle_wave(blend) / 255 ); } // guarantee no more than 200% power if (base_PWM > (top << 1)) { base_PWM = top << 1; } #endif - cool_PWM = (((PWM_DATATYPE2)mytint * (PWM_DATATYPE2)base_PWM) + 127) / 255; + cool_PWM = (((PWM_DATATYPE2)blend * (PWM_DATATYPE2)base_PWM) + 127) / 255; warm_PWM = base_PWM - cool_PWM; // when running at > 100% power, spill extra over to other channel if (cool_PWM > top) { @@ -196,10 +194,76 @@ void set_level_2ch_blend(uint8_t level) { warm_PWM = top; } - WARM_PWM_LVL = warm_PWM; - COOL_PWM_LVL = cool_PWM; + *warm = warm_PWM; + *cool = cool_PWM; } -#endif // ifdef USE_TINT_RAMPING +#endif // ifdef USE_CALC_2CH_BLEND + +#ifdef USE_HSV2RGB +RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v) { + RGB_t color; + + uint16_t region, fpart, high, low, rising, falling; + + if (s == 0) { // grey + color.r = color.g = color.b = v; + return color; + } + + // make hue 0-5 + region = ((uint16_t)h * 6) >> 8; + // find remainder part, make it from 0-255 + fpart = ((uint16_t)h * 6) - (region << 8); + + // calculate graph segments, doing integer multiplication + high = v; + low = (v * (255 - s)) >> 8; + falling = (v * (255 - ((s * fpart) >> 8))) >> 8; + rising = (v * (255 - ((s * (255 - fpart)) >> 8))) >> 8; + + // default floor + color.r = low; + color.g = low; + color.b = low; + + // assign graph shapes based on color cone region + switch (region) { + case 0: + color.r = high; + color.g = rising; + //color.b = low; + break; + case 1: + color.r = falling; + color.g = high; + //color.b = low; + break; + case 2: + //color.r = low; + color.g = high; + color.b = rising; + break; + case 3: + //color.r = low; + color.g = falling; + color.b = high; + break; + case 4: + color.r = rising; + //color.g = low; + color.b = high; + break; + default: + color.r = high; + //color.g = low; + color.b = falling; + break; + } + + return color; +} +#endif // ifdef USE_HSV2RGB + #ifdef USE_LEGACY_SET_LEVEL // (this is mostly just here for reference, temporarily) @@ -339,7 +403,7 @@ inline void set_level_gradually(uint8_t lvl) { // call this every frame or every few frames to change brightness very smoothly void gradual_tick() { // call the relevant hardware-specific function - GradualTickFuncPtr gradual_tick_func = gradual_tick_modes[channel_mode]; + GradualTickFuncPtr gradual_tick_func = gradual_tick_modes[CH_MODE]; gradual_tick_func(); } diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 8a12cc8..5ffd8d9 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -28,11 +28,12 @@ uint8_t actual_level = 0; // TODO: size-optimize the case with only 1 channel mode // (the arrays and stuff shouldn't be needed) -// current multi-channel mode -uint8_t channel_mode = DEFAULT_CHANNEL_MODE; -#ifdef USE_MANUAL_MEMORY -// reset w/ manual memory -uint8_t manual_memory_channel_mode = DEFAULT_CHANNEL_MODE; +#ifdef USE_CFG + #define CH_MODE cfg.channel_mode +#else + // current multi-channel mode + uint8_t channel_mode = DEFAULT_CHANNEL_MODE; + #define CH_MODE channel_mode #endif #if NUM_CHANNEL_MODES > 1 @@ -62,36 +63,49 @@ StatePtr channel_3H_modes[NUM_CHANNEL_MODES]; //#ifdef USE_CHANNEL_MODE_TOGGLES #if NUM_CHANNEL_MODES > 1 // user can take unwanted modes out of the rotation -// TODO: save to eeprom -// array -//uint8_t channel_modes_enabled[NUM_CHANNEL_MODES] = { CHANNEL_MODES_ENABLED }; // bitmask -uint8_t channel_modes_enabled = CHANNEL_MODES_ENABLED; -#define channel_mode_enabled(n) ((channel_modes_enabled >> n) & 1) -#define channel_mode_enable(n) channel_modes_enabled |= (1 << n) -#define channel_mode_disable(n) channel_modes_enabled &= ((1 << n) ^ 0xff) +#ifdef USE_CFG + #define channel_mode_enabled(n) ((cfg.channel_modes_enabled >> n) & 1) + #define channel_mode_enable(n) cfg.channel_modes_enabled |= (1 << n) + #define channel_mode_disable(n) cfg.channel_modes_enabled &= ((1 << n) ^ 0xff) +#else + uint8_t channel_modes_enabled = CHANNEL_MODES_ENABLED; + #define channel_mode_enabled(n) ((channel_modes_enabled >> n) & 1) + #define channel_mode_enable(n) channel_modes_enabled |= (1 << n) + #define channel_mode_disable(n) channel_modes_enabled &= ((1 << n) ^ 0xff) + #endif #endif -#ifdef USE_CHANNEL_MODE_ARGS -// one byte of extra data per channel mode, like for tint value -uint8_t channel_mode_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; +#ifndef USE_CFG + #ifdef USE_CHANNEL_MODE_ARGS + // one byte of extra data per channel mode, like for tint value + uint8_t channel_mode_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; + #endif #endif -// TODO: remove this after implementing channel modes -//#ifdef USE_TINT_RAMPING -//#ifdef TINT_RAMP_TOGGLE_ONLY -//uint8_t tint = 0; -//#else -//uint8_t tint = 128; -//#endif -//#define USE_TRIANGLE_WAVE -//#endif - void set_channel_mode(uint8_t mode); void set_level(uint8_t level); //void set_level_smooth(uint8_t level); +#ifdef USE_CALC_2CH_BLEND +void calc_2ch_blend( + PWM_DATATYPE *warm, + PWM_DATATYPE *cool, + PWM_DATATYPE brightness, + PWM_DATATYPE top, + uint8_t blend); +#endif + +#ifdef USE_HSV2RGB +typedef struct RGB_t { + uint8_t r; + uint8_t g; + uint8_t b; +} RGB_t; +RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v); +#endif // ifdef USE_HSV2RGB + #ifdef USE_SET_LEVEL_GRADUALLY // adjust brightness very smoothly uint8_t gradual_target; @@ -213,13 +227,18 @@ PROGMEM const PWM_DATATYPE pwm_tops[] = { PWM_TOPS }; // FIXME: jump start should be per channel / channel mode #ifdef USE_JUMP_START -#ifndef JUMP_START_TIME -#define JUMP_START_TIME 8 // in ms, should be 4, 8, or 12 -#endif -#ifndef DEFAULT_JUMP_START_LEVEL -#define DEFAULT_JUMP_START_LEVEL 10 -#endif -uint8_t jump_start_level = DEFAULT_JUMP_START_LEVEL; + #ifndef JUMP_START_TIME + #define JUMP_START_TIME 8 // in ms, should be 4, 8, or 12 + #endif + #ifndef DEFAULT_JUMP_START_LEVEL + #define DEFAULT_JUMP_START_LEVEL 10 + #endif + #ifdef USE_CFG + #define JUMP_START_LEVEL cfg.jump_start_level + #else + #define JUMP_START_LEVEL jump_start_level + uint8_t jump_start_level = DEFAULT_JUMP_START_LEVEL; + #endif #endif // RAMP_SIZE / MAX_LVL -- cgit v1.2.3 From 583854e37efde7f461e073e735a1736b02d28c70 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 17 Apr 2023 00:08:32 -0600 Subject: switched the rest of FSM + Anduril to use SPDX license headers instead of full GPL headers (or all too often, nothing at all) There are a few "FIXME" entries where I'm not sure about the correct copyright. --- hwdef-BLF_GT.h | 9 ++++--- hwdef-BLF_GT_Mini.h | 9 +++---- hwdef-BLF_LT1-t1616.h | 16 +++++------- hwdef-BLF_LT1.h | 10 ++++---- hwdef-BLF_Q8-T1616.h | 14 +++++----- hwdef-BLF_Q8.h | 11 ++++---- hwdef-Emisar_D1.h | 9 +++---- hwdef-Emisar_D18.h | 9 ++++--- hwdef-Emisar_D1S.h | 9 +++---- hwdef-Emisar_D4.h | 9 ++++--- hwdef-Emisar_D4S.h | 9 +++---- hwdef-Emisar_D4Sv2-tintramp.h | 9 ++++--- hwdef-Emisar_D4Sv2.h | 9 ++++--- hwdef-Emisar_D4v2.h | 8 +++--- hwdef-FF_PL47.h | 11 ++++---- hwdef-FF_ROT66.h | 11 ++++---- hwdef-FW3A.h | 9 ++++--- hwdef-Mateminco_MF01-Mini.h | 9 ++++--- hwdef-Mateminco_MF01S.h | 9 ++++--- hwdef-Mateminco_MT35-Mini.h | 9 ++++--- hwdef-Noctigon_DM11-12V.h | 9 ++++--- hwdef-Noctigon_DM11-SBT90.h | 9 ++++--- hwdef-Noctigon_DM11.h | 9 ++++--- hwdef-Noctigon_K1-12V.h | 11 ++++---- hwdef-Noctigon_K1-SBT90.h | 9 ++++--- hwdef-Noctigon_K1.h | 9 ++++--- hwdef-Noctigon_K9.3.h | 10 ++++---- hwdef-Noctigon_KR4-12V.h | 9 ++++--- hwdef-Noctigon_KR4-tintramp.h | 9 ++++--- hwdef-Noctigon_KR4.h | 10 ++++---- hwdef-Sofirn_LT1S-Pro.c | 1 - hwdef-Sofirn_LT1S-Pro.h | 14 +++++----- hwdef-Sofirn_SP10-Pro.h | 26 +++++++++---------- hwdef-TK_Saber.h | 9 ++++--- hwdef-Wurkkos_TS10.h | 20 +++++++-------- hwdef-Wurkkos_TS25.h | 17 +++++------- hwdef-fw3x-lume1.h | 7 ++--- hwdef-gchart-fet1-t1616.h | 24 ++++++++--------- hwdef-thefreeman-lin16dac.h | 29 ++++++++++----------- spaghetti-monster/anduril/anduril.c | 23 +++-------------- spaghetti-monster/anduril/aux-leds.c | 28 +++----------------- spaghetti-monster/anduril/aux-leds.h | 27 +++---------------- spaghetti-monster/anduril/battcheck-mode-fsm.h | 27 +++---------------- spaghetti-monster/anduril/battcheck-mode.c | 28 +++----------------- spaghetti-monster/anduril/battcheck-mode.h | 27 +++---------------- spaghetti-monster/anduril/beacon-mode.c | 28 +++----------------- spaghetti-monster/anduril/beacon-mode.h | 27 +++---------------- spaghetti-monster/anduril/candle-mode.c | 28 +++----------------- spaghetti-monster/anduril/candle-mode.h | 27 +++---------------- spaghetti-monster/anduril/cfg-blf-gt-mini.h | 4 +++ spaghetti-monster/anduril/cfg-blf-gt.h | 4 +++ spaghetti-monster/anduril/cfg-blf-lantern-t1616.h | 4 +++ spaghetti-monster/anduril/cfg-blf-lantern.h | 4 +++ spaghetti-monster/anduril/cfg-blf-q8-t1616.h | 4 +++ spaghetti-monster/anduril/cfg-blf-q8.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d1.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d18-219.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d18.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d1s.h | 4 +++ .../anduril/cfg-emisar-d1v2-7135-fet.h | 6 ++++- .../anduril/cfg-emisar-d1v2-linear-fet.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h | 6 ++++- spaghetti-monster/anduril/cfg-emisar-d4-219c.h | 6 ++++- spaghetti-monster/anduril/cfg-emisar-d4.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d4s-219c.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d4s.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d4sv2-219.h | 4 +++ .../anduril/cfg-emisar-d4sv2-tintramp-fet.h | 4 +++ .../anduril/cfg-emisar-d4sv2-tintramp.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d4sv2.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d4v2-219.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h | 4 +++ spaghetti-monster/anduril/cfg-emisar-d4v2.h | 5 ++-- spaghetti-monster/anduril/cfg-ff-e01.h | 4 +++ spaghetti-monster/anduril/cfg-ff-pl47-219.h | 4 +++ spaghetti-monster/anduril/cfg-ff-pl47.h | 4 +++ spaghetti-monster/anduril/cfg-ff-pl47g2.h | 4 +++ spaghetti-monster/anduril/cfg-ff-rot66-219.h | 4 +++ spaghetti-monster/anduril/cfg-ff-rot66.h | 4 +++ spaghetti-monster/anduril/cfg-ff-rot66g2.h | 4 +++ spaghetti-monster/anduril/cfg-fw3a-219.h | 4 +++ spaghetti-monster/anduril/cfg-fw3a-nofet.h | 4 +++ spaghetti-monster/anduril/cfg-fw3a.h | 4 +++ spaghetti-monster/anduril/cfg-fw3x-lume1.h | 7 ++++- spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h | 4 +++ .../anduril/cfg-mateminco-mf01-mini.h | 4 +++ spaghetti-monster/anduril/cfg-mateminco-mf01s.h | 4 +++ .../anduril/cfg-mateminco-mt35-mini.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h | 4 +++ .../anduril/cfg-noctigon-dm11-nofet.h | 4 +++ .../anduril/cfg-noctigon-dm11-sbt90.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-dm11.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-k1-12v.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-k1-sbt90.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-k1.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-k9.3-219.h | 4 +++ .../anduril/cfg-noctigon-k9.3-nofet.h | 4 +++ .../anduril/cfg-noctigon-k9.3-tintramp-219.h | 4 +++ .../anduril/cfg-noctigon-k9.3-tintramp-fet.h | 4 +++ .../anduril/cfg-noctigon-k9.3-tintramp-nofet.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-k9.3.c | 5 ++++ spaghetti-monster/anduril/cfg-noctigon-k9.3.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-kr4-12v.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-kr4-219.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-kr4-219b.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h | 4 +++ .../anduril/cfg-noctigon-kr4-tintramp.h | 4 +++ spaghetti-monster/anduril/cfg-noctigon-kr4.h | 4 +++ spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.c | 22 ---------------- spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 4 ++- spaghetti-monster/anduril/cfg-sofirn-sc21-pro.h | 4 +++ spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h | 4 +++ spaghetti-monster/anduril/cfg-sofirn-sp36-t1616.h | 4 +++ spaghetti-monster/anduril/cfg-sofirn-sp36.h | 4 +++ .../anduril/cfg-thefreeman-lin16dac.h | 4 +++ spaghetti-monster/anduril/cfg-wurkkos-ts10.h | 6 ++++- spaghetti-monster/anduril/cfg-wurkkos-ts25.h | 6 ++++- spaghetti-monster/anduril/channel-modes.c | 10 +++----- spaghetti-monster/anduril/channel-modes.h | 8 +++--- spaghetti-monster/anduril/config-default.h | 25 +++--------------- spaghetti-monster/anduril/factory-reset-fsm.h | 26 +++---------------- spaghetti-monster/anduril/ff-strobe-modes.c | 27 +++---------------- spaghetti-monster/anduril/ff-strobe-modes.h | 26 +++---------------- spaghetti-monster/anduril/hank-cfg.h | 2 +- spaghetti-monster/anduril/lockout-mode-fsm.h | 26 +++---------------- spaghetti-monster/anduril/lockout-mode.c | 29 ++++----------------- spaghetti-monster/anduril/lockout-mode.h | 26 +++---------------- spaghetti-monster/anduril/misc.c | 27 +++---------------- spaghetti-monster/anduril/misc.h | 26 +++---------------- spaghetti-monster/anduril/momentary-mode.c | 27 +++---------------- spaghetti-monster/anduril/momentary-mode.h | 26 +++---------------- spaghetti-monster/anduril/off-mode.c | 29 ++++----------------- spaghetti-monster/anduril/off-mode.h | 26 +++---------------- spaghetti-monster/anduril/ramp-mode-fsm.h | 28 ++++---------------- spaghetti-monster/anduril/sos-mode.c | 27 +++---------------- spaghetti-monster/anduril/sos-mode.h | 26 +++---------------- spaghetti-monster/anduril/strobe-modes-fsm.h | 25 +++--------------- spaghetti-monster/anduril/strobe-modes.c | 29 ++++----------------- spaghetti-monster/anduril/strobe-modes.h | 27 ++++--------------- spaghetti-monster/anduril/tactical-mode.c | 27 +++---------------- spaghetti-monster/anduril/tactical-mode.h | 26 +++---------------- spaghetti-monster/anduril/tempcheck-mode.c | 27 +++---------------- spaghetti-monster/anduril/tempcheck-mode.h | 26 +++---------------- spaghetti-monster/anduril/tint-ramping.c | 8 +++--- spaghetti-monster/anduril/tint-ramping.h | 8 +++--- spaghetti-monster/anduril/version-check-mode.c | 27 +++---------------- spaghetti-monster/anduril/version-check-mode.h | 26 +++---------------- spaghetti-monster/fsm-adc.c | 27 ++++--------------- spaghetti-monster/fsm-adc.h | 27 +++---------------- spaghetti-monster/fsm-eeprom.c | 28 ++++---------------- spaghetti-monster/fsm-eeprom.h | 25 +++--------------- spaghetti-monster/fsm-events.c | 27 ++++--------------- spaghetti-monster/fsm-events.h | 26 +++---------------- spaghetti-monster/fsm-main.c | 27 ++++--------------- spaghetti-monster/fsm-main.h | 25 +++--------------- spaghetti-monster/fsm-misc.c | 26 +++---------------- spaghetti-monster/fsm-misc.h | 25 +++--------------- spaghetti-monster/fsm-pcint.c | 26 +++---------------- spaghetti-monster/fsm-pcint.h | 25 +++--------------- spaghetti-monster/fsm-ramping.c | 11 +++----- spaghetti-monster/fsm-ramping.h | 22 +++------------- spaghetti-monster/fsm-random.c | 25 +++--------------- spaghetti-monster/fsm-random.h | 25 +++--------------- spaghetti-monster/fsm-standby.c | 27 ++++--------------- spaghetti-monster/fsm-standby.h | 25 +++--------------- spaghetti-monster/fsm-states.c | 25 +++--------------- spaghetti-monster/fsm-states.h | 27 ++++--------------- spaghetti-monster/fsm-wdt.c | 27 ++++--------------- spaghetti-monster/fsm-wdt.h | 25 +++--------------- spaghetti-monster/spaghetti-monster.h | 22 +++++----------- tk-attiny.h | 29 +++++---------------- tk-calibration.h | 30 +++++----------------- tk-delay.h | 27 +++---------------- tk-random.h | 26 +++---------------- tk-voltage.h | 27 +++---------------- tk.h | 7 ++--- 176 files changed, 778 insertions(+), 1660 deletions(-) delete mode 100644 spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.c diff --git a/hwdef-BLF_GT.h b/hwdef-BLF_GT.h index 51b391d..94d510c 100644 --- a/hwdef-BLF_GT.h +++ b/hwdef-BLF_GT.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_BLF_GT_H -#define HWDEF_BLF_GT_H +// BLF GT driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* BLF GT driver layout +/* * ---- * Reset -|1 8|- VCC (unused) * eswitch -|2 7|- Voltage divider @@ -57,4 +59,3 @@ #define LAYOUT_DEFINED -#endif diff --git a/hwdef-BLF_GT_Mini.h b/hwdef-BLF_GT_Mini.h index 43f74f3..1706749 100644 --- a/hwdef-BLF_GT_Mini.h +++ b/hwdef-BLF_GT_Mini.h @@ -1,8 +1,8 @@ -#ifndef HWDEF_BLF_GT_MINI_H -#define HWDEF_BLF_GT_MINI_H +// BLF/Lumintop GT Mini driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* BLF/Lumintop GT Mini driver layout - */ // exactly the same as a D1S, but with a lighted button #include "hwdef-Emisar_D1S.h" @@ -11,4 +11,3 @@ #define AUXLED_PIN PB4 // pin 3 #endif -#endif diff --git a/hwdef-BLF_LT1-t1616.h b/hwdef-BLF_LT1-t1616.h index 8e5c58b..3e1d946 100644 --- a/hwdef-BLF_LT1-t1616.h +++ b/hwdef-BLF_LT1-t1616.h @@ -1,16 +1,16 @@ -#ifndef HWDEF_BLF_LANTERN_T1616_H -#define HWDEF_BLF_LANTERN_T1616_H +// BLF LT1 driver layout using the Attiny1616 +// Copyright (C) 2021-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* BLF LT1 driver layout using the Attiny1616 - -Driver pinout: +/* + * Driver pinout: * eSwitch: PA5 * Aux LED: PB5 * PWM FET: PB0 (TCA0 WO0) * PWM 1x7135: PB1 (TCA0 WO1) * Voltage: VCC - -*/ + */ #define LAYOUT_DEFINED @@ -103,5 +103,3 @@ inline void hwdef_setup() { TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; } - -#endif diff --git a/hwdef-BLF_LT1.h b/hwdef-BLF_LT1.h index 4e81c42..e7c4791 100644 --- a/hwdef-BLF_LT1.h +++ b/hwdef-BLF_LT1.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_BLF_LT1_H -#define HWDEF_BLF_LT1_H +// BLF LT1 driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* BLF LT1 driver layout +/* * ---- * Reset -|1 8|- VCC * eswitch -|2 7|- (unused) @@ -54,5 +56,3 @@ uint16_t PWM1_LVL; #define LAYOUT_DEFINED - -#endif diff --git a/hwdef-BLF_Q8-T1616.h b/hwdef-BLF_Q8-T1616.h index d6ad760..25734ba 100644 --- a/hwdef-BLF_Q8-T1616.h +++ b/hwdef-BLF_Q8-T1616.h @@ -1,15 +1,15 @@ -#ifndef HWDEF_BLF_Q8_T1616_H -#define HWDEF_BLF_Q8_T1616_H +// BLF Q8 driver layout using the Attiny1616 +// Copyright (C) 2021-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* BLF Q8 driver layout using the Attiny1616 - -Driver pinout: +/* + * Driver pinout: * eSwitch: PA5 * Aux LED: PB5 * PWM FET: PB0 (TCA0 WO0) * PWM 1x7135: PB1 (TCA0 WO1) * Voltage: VCC - */ @@ -103,5 +103,3 @@ inline void hwdef_setup() { TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; } - -#endif diff --git a/hwdef-BLF_Q8.h b/hwdef-BLF_Q8.h index 5dac5d2..da55bd4 100644 --- a/hwdef-BLF_Q8.h +++ b/hwdef-BLF_Q8.h @@ -1,9 +1,9 @@ -#ifndef HWDEF_BLF_Q8_H -#define HWDEF_BLF_Q8_H +// BLF Q8 driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* BLF Q8 driver layout - * Q8 driver is the same as a D4, basically - */ +// Q8 driver is the same as a D4, basically // ... except the Q8 has a lighted button #ifndef AUXLED_PIN @@ -18,4 +18,3 @@ // Q8 driver is the same as a D4, basically #include "hwdef-Emisar_D4.h" -#endif diff --git a/hwdef-Emisar_D1.h b/hwdef-Emisar_D1.h index caf1d4e..bf3a224 100644 --- a/hwdef-Emisar_D1.h +++ b/hwdef-Emisar_D1.h @@ -1,9 +1,8 @@ -#ifndef HWDEF_EMISAR_D1_H -#define HWDEF_EMISAR_D1_H +// Emisar D1 driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Emisar D1 driver layout - */ // D1 driver is exactly the same as a D4 #include "hwdef-Emisar_D4.h" -#endif diff --git a/hwdef-Emisar_D18.h b/hwdef-Emisar_D18.h index 3a238eb..b9f5b2e 100644 --- a/hwdef-Emisar_D18.h +++ b/hwdef-Emisar_D18.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_EMISAR_D18_H -#define HWDEF_EMISAR_D18_H +// Emisar D18 (FET+13+1) driver layout +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Emisar D18 (FET+13+1) driver layout +/* * ---- * Reset -|1 8|- VCC * eswitch -|2 7|- aux LED? @@ -45,4 +47,3 @@ #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Emisar_D1S.h b/hwdef-Emisar_D1S.h index 2e9fffa..15cbedb 100644 --- a/hwdef-Emisar_D1S.h +++ b/hwdef-Emisar_D1S.h @@ -1,9 +1,8 @@ -#ifndef HWDEF_EMISAR_D1S_H -#define HWDEF_EMISAR_D1S_H +// Emisar D1S driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Emisar D1S driver layout - */ // D1S driver is exactly the same as a D4 #include "hwdef-Emisar_D4.h" -#endif diff --git a/hwdef-Emisar_D4.h b/hwdef-Emisar_D4.h index d062d6f..fdb42a1 100644 --- a/hwdef-Emisar_D4.h +++ b/hwdef-Emisar_D4.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_EMISAR_D4_H -#define HWDEF_EMISAR_D4_H +// Emisar D4 driver layout +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Emisar D4 driver layout +/* * ---- * Reset -|1 8|- VCC * eswitch -|2 7|- @@ -44,4 +46,3 @@ #define FAST 0xA3 // fast PWM both channels #define PHASE 0xA1 // phase-correct PWM both channels -#endif diff --git a/hwdef-Emisar_D4S.h b/hwdef-Emisar_D4S.h index 05a60f9..97d8529 100644 --- a/hwdef-Emisar_D4S.h +++ b/hwdef-Emisar_D4S.h @@ -1,8 +1,8 @@ -#ifndef HWDEF_EMISAR_D4S_H -#define HWDEF_EMISAR_D4S_H +// Emisar D4S driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Emisar D4S driver layout - */ // same as a D4, basically #include "hwdef-Emisar_D4.h" @@ -11,4 +11,3 @@ #define AUXLED_PIN PB4 // pin 3 #endif -#endif diff --git a/hwdef-Emisar_D4Sv2-tintramp.h b/hwdef-Emisar_D4Sv2-tintramp.h index 0f4a77a..2709bc4 100644 --- a/hwdef-Emisar_D4Sv2-tintramp.h +++ b/hwdef-Emisar_D4Sv2-tintramp.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_D4SV2_TINTRAMP_H -#define HWDEF_D4SV2_TINTRAMP_H +// Emisar D4Sv2 w/ tint ramping +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Emisar D4Sv2 w/ tint ramping +/* * (based on the Noctigon K9.3 driver layout (attiny1634)) * * Pin / Name / Function @@ -185,4 +187,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Emisar_D4Sv2.h b/hwdef-Emisar_D4Sv2.h index d68b7ac..bd63649 100644 --- a/hwdef-Emisar_D4Sv2.h +++ b/hwdef-Emisar_D4Sv2.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_EMISAR_D4SV2_H -#define HWDEF_EMISAR_D4SV2_H +// Emisar D4Sv2 driver layout (attiny1634) +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Emisar D4Sv2 driver layout (attiny1634) +/* * (same layout as D4v2, except it's a FET+3+1 instead of FET+1) * * Pin / Name / Function @@ -119,4 +121,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Emisar_D4v2.h b/hwdef-Emisar_D4v2.h index 51e30f8..2864cd4 100644 --- a/hwdef-Emisar_D4v2.h +++ b/hwdef-Emisar_D4v2.h @@ -1,9 +1,9 @@ +// hwdef for Emisar D4v2 (attiny1634) +// Copyright (C) 2018 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once -/* hwdef for Emisar D4v2 (attiny1634) - * Copyright (C) 2019 Selene ToyKeeper - * SPDX-License-Identifier: GPL-3.0-or-later - * +/* * Pin / Name / Function * 1 PA6 FET PWM (PWM1B) * 2 PA5 red aux LED (PWM0B) diff --git a/hwdef-FF_PL47.h b/hwdef-FF_PL47.h index 5cd9684..0171d15 100644 --- a/hwdef-FF_PL47.h +++ b/hwdef-FF_PL47.h @@ -1,9 +1,9 @@ -#ifndef HWDEF_FF_PL47_H -#define HWDEF_FF_PL47_H +// Fireflies PL47 driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Fireflies PL47 driver layout - * same as a D4S, basically, except ... - */ +// same as a D4S, basically, except ... // ... the PL47 has aux LEDs on pin 7 #ifndef AUXLED_PIN @@ -24,4 +24,3 @@ #undef FSM_EMISAR_D4S_DRIVER #undef FSM_EMISAR_D4_DRIVER -#endif diff --git a/hwdef-FF_ROT66.h b/hwdef-FF_ROT66.h index 7348ab2..e84b565 100644 --- a/hwdef-FF_ROT66.h +++ b/hwdef-FF_ROT66.h @@ -1,9 +1,9 @@ -#ifndef HWDEF_FF_ROT66_H -#define HWDEF_FF_ROT66_H +// Fireflies ROT66 driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Fireflies ROT66 driver layout - * same as a FW3A, basically, except ... - */ +// same as a FW3A, basically, except ... // ... except the ROT66 has a lighted button #ifndef AUXLED_PIN @@ -22,4 +22,3 @@ #undef VISION_PIN #endif -#endif diff --git a/hwdef-FW3A.h b/hwdef-FW3A.h index e8875d7..f2b5c8d 100644 --- a/hwdef-FW3A.h +++ b/hwdef-FW3A.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_FW3A_H -#define HWDEF_FW3A_H +// BLF/TLF FW3A driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* BLF/TLF FW3A driver layout +/* * ---- * Reset -|1 8|- VCC * eswitch -|2 7|- optic nerve @@ -47,4 +49,3 @@ #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Mateminco_MF01-Mini.h b/hwdef-Mateminco_MF01-Mini.h index c0de533..557e641 100644 --- a/hwdef-Mateminco_MF01-Mini.h +++ b/hwdef-Mateminco_MF01-Mini.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_MF01_MINI_H -#define HWDEF_MF01_MINI_H +// MF01-Mini driver layout +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* MF01-Mini driver layout +/* * ---- * Reset -|1 8|- VCC * eswitch -|2 7|- aux LEDs @@ -46,4 +48,3 @@ #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Mateminco_MF01S.h b/hwdef-Mateminco_MF01S.h index 78a64a6..0ae30a6 100644 --- a/hwdef-Mateminco_MF01S.h +++ b/hwdef-Mateminco_MF01S.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_MF01S_H -#define HWDEF_MF01S_H +// MF01S driver layout +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* MF01S driver layout +/* * ---- * Reset -|1 8|- VCC (unused) * eswitch -|2 7|- Voltage divider (2S) @@ -57,4 +59,3 @@ #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Mateminco_MT35-Mini.h b/hwdef-Mateminco_MT35-Mini.h index 344f658..995a514 100644 --- a/hwdef-Mateminco_MT35-Mini.h +++ b/hwdef-Mateminco_MT35-Mini.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_MT35_MINI_H -#define HWDEF_MT35_MINI_H +// Mateminco MT35-Mini / Astrolux FT03 +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Mateminco MT35-Mini / Astrolux FT03 +/* * ---- * Reset -|1 8|- VCC * eswitch -|2 7|- Aux LED @@ -44,4 +46,3 @@ #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Noctigon_DM11-12V.h b/hwdef-Noctigon_DM11-12V.h index a0d9715..104b6ae 100644 --- a/hwdef-Noctigon_DM11-12V.h +++ b/hwdef-Noctigon_DM11-12V.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_NOCTIGON_DM11_12V_H -#define HWDEF_NOCTIGON_DM11_12V_H +// Noctigon DM11 (12V) driver layout (attiny1634) +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Noctigon DM11 (12V) driver layout (attiny1634) +/* * (based on Noctigon K1) * * Pin / Name / Function @@ -162,4 +164,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Noctigon_DM11-SBT90.h b/hwdef-Noctigon_DM11-SBT90.h index 8d7aa3d..c56b8ce 100644 --- a/hwdef-Noctigon_DM11-SBT90.h +++ b/hwdef-Noctigon_DM11-SBT90.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_NOCTIGON_DM11SBT90_H -#define HWDEF_NOCTIGON_DM11SBT90_H +// Noctigon DM11-SBT90.2 driver layout (attiny1634) +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Noctigon DM11-SBT90.2 driver layout (attiny1634) +/* * (based on Noctigon K1 and DM11) * * Pin / Name / Function @@ -154,4 +156,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Noctigon_DM11.h b/hwdef-Noctigon_DM11.h index ea51432..619e12d 100644 --- a/hwdef-Noctigon_DM11.h +++ b/hwdef-Noctigon_DM11.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_NOCTIGON_DM11_H -#define HWDEF_NOCTIGON_DM11_H +// Noctigon DM11 driver layout (attiny1634) +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Noctigon DM11 driver layout (attiny1634) +/* * (based on Noctigon K1) * * Pin / Name / Function @@ -153,4 +155,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Noctigon_K1-12V.h b/hwdef-Noctigon_K1-12V.h index b17aad0..33ed34d 100644 --- a/hwdef-Noctigon_K1-12V.h +++ b/hwdef-Noctigon_K1-12V.h @@ -1,9 +1,9 @@ -#ifndef HWDEF_NOCTIGON_K1_12V_H -#define HWDEF_NOCTIGON_K1_12V_H +// Noctigon K1 12V driver layout (attiny1634) +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Noctigon K1 driver layout (attiny1634) - * (originally known as Emisar D1S V2) - * +/* * Pin / Name / Function * 1 PA6 (none) (PWM1B) (reserved for DD drivers) * 2 PA5 R: red aux LED (PWM0B) @@ -135,4 +135,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Noctigon_K1-SBT90.h b/hwdef-Noctigon_K1-SBT90.h index c19a4a6..9d91c1c 100644 --- a/hwdef-Noctigon_K1-SBT90.h +++ b/hwdef-Noctigon_K1-SBT90.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_NOCTIGON_K1SBT90_H -#define HWDEF_NOCTIGON_K1SBT90_H +// Noctigon K1-SBT90.2 driver layout (attiny1634) +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Noctigon K1-SBT90.2 driver layout (attiny1634) +/* * (mostly the same as KR4 driver) * * Pin / Name / Function @@ -140,4 +142,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Noctigon_K1.h b/hwdef-Noctigon_K1.h index 4c0ce05..2e44e23 100644 --- a/hwdef-Noctigon_K1.h +++ b/hwdef-Noctigon_K1.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_NOCTIGON_K1_H -#define HWDEF_NOCTIGON_K1_H +// Noctigon K1 driver layout (attiny1634) +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Noctigon K1 driver layout (attiny1634) +/* * (originally known as Emisar D1S V2) * * Pin / Name / Function @@ -131,4 +133,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Noctigon_K9.3.h b/hwdef-Noctigon_K9.3.h index 6032b4c..2f1ffe0 100644 --- a/hwdef-Noctigon_K9.3.h +++ b/hwdef-Noctigon_K9.3.h @@ -1,8 +1,9 @@ -#ifndef HWDEF_NOCTIGON_K93_H -#define HWDEF_NOCTIGON_K93_H +// Noctigon K9.3 driver layout (attiny1634) +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Noctigon K9.3 driver layout (attiny1634) - * +/* * Pin / Name / Function * 1 PA6 2nd LED PWM (linear) (PWM1B) * 2 PA5 R: red aux LED (PWM0B) @@ -161,4 +162,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Noctigon_KR4-12V.h b/hwdef-Noctigon_KR4-12V.h index e6cf18a..57d39f2 100644 --- a/hwdef-Noctigon_KR4-12V.h +++ b/hwdef-Noctigon_KR4-12V.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_NOCTIGON_KR4_12V_H -#define HWDEF_NOCTIGON_KR4_12V_H +// Noctigon KR4 (12V) driver layout (attiny1634) +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Noctigon KR4 (12V) driver layout (attiny1634) +/* * (based on Noctigon DM11-12V and KR4) * * Pin / Name / Function @@ -154,4 +156,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Noctigon_KR4-tintramp.h b/hwdef-Noctigon_KR4-tintramp.h index 3bd57fe..78a4d6b 100644 --- a/hwdef-Noctigon_KR4-tintramp.h +++ b/hwdef-Noctigon_KR4-tintramp.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_KR4_TINTRAMP_H -#define HWDEF_KR4_TINTRAMP_H +// Noctigon KR4 w/ tint ramping +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Noctigon KR4 w/ tint ramping +/* * (same driver as D4Sv2-tintramp, but with the switch on a different pin) * * Pin / Name / Function @@ -43,4 +45,3 @@ // the rest of the config is the same as D4Sv2-tintramp #include "hwdef-Emisar_D4Sv2-tintramp.h" -#endif diff --git a/hwdef-Noctigon_KR4.h b/hwdef-Noctigon_KR4.h index 487d3ac..1c863cb 100644 --- a/hwdef-Noctigon_KR4.h +++ b/hwdef-Noctigon_KR4.h @@ -1,8 +1,9 @@ -#ifndef HWDEF_NOCTIGON_KR4_H -#define HWDEF_NOCTIGON_KR4_H +// Noctigon KR4 / D4V2.5 driver layout (attiny1634) +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Noctigon KR4 / D4V2.5 driver layout (attiny1634) - * +/* * Pin / Name / Function * 1 PA6 FET PWM (direct drive) (PWM1B) * 2 PA5 R: red aux LED (PWM0B) @@ -158,4 +159,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Sofirn_LT1S-Pro.c b/hwdef-Sofirn_LT1S-Pro.c index f617933..8e2163f 100644 --- a/hwdef-Sofirn_LT1S-Pro.c +++ b/hwdef-Sofirn_LT1S-Pro.c @@ -1,7 +1,6 @@ // BLF LT1S Pro hwdef functions // Copyright (C) 2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later - #pragma once diff --git a/hwdef-Sofirn_LT1S-Pro.h b/hwdef-Sofirn_LT1S-Pro.h index b50ccc7..4ee466b 100644 --- a/hwdef-Sofirn_LT1S-Pro.h +++ b/hwdef-Sofirn_LT1S-Pro.h @@ -1,17 +1,17 @@ -/* BLF LT1S Pro driver layout using the Attiny1616 +// BLF LT1S Pro driver layout using the Attiny1616 +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -Driver pinout: +/* + * Driver pinout: * eSwitch: PA5 * Aux LED: PB5 * WW PWM: PB0 (TCA0 WO0) * CW PWM: PB1 (TCA0 WO1) * Red PWM: PB2 (TCA0 WO2) * Voltage: VCC - -*/ - -#pragma once - + */ #define HWDEF_C_FILE hwdef-Sofirn_LT1S-Pro.c diff --git a/hwdef-Sofirn_SP10-Pro.h b/hwdef-Sofirn_SP10-Pro.h index d7c2081..6bc26ea 100644 --- a/hwdef-Sofirn_SP10-Pro.h +++ b/hwdef-Sofirn_SP10-Pro.h @@ -1,16 +1,16 @@ -#ifndef HWDEF_SOFIRN_SP10_H -#define HWDEF_SOFIRN_SP10_H +// Sofirn SP10 Pro pinout +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* Sofirn SP10 Pro pinout - -ATTINY1616 Mapping: -PB5 : PWM small channel (TCA0 - WO2 Alternate MUX) -PB3 : eSwitch -PB0 : PWM big channel (TCA0 - WO0) -PB4 : Voltage divider (ADC0 - AIN9) -PA1 : Boost Enable - -*/ +/* + * ATTINY1616 Mapping: + * PB5 : PWM small channel (TCA0 - WO2 Alternate MUX) + * PB3 : eSwitch + * PB0 : PWM big channel (TCA0 - WO0) + * PB4 : Voltage divider (ADC0 - AIN9) + * PA1 : Boost Enable + */ #define LAYOUT_DEFINED @@ -140,5 +140,3 @@ FUSES = { .BOOTEND = FUSE_BOOTEND_DEFAULT, // Boot Section End }; - -#endif diff --git a/hwdef-TK_Saber.h b/hwdef-TK_Saber.h index e6476b8..8ef58d6 100644 --- a/hwdef-TK_Saber.h +++ b/hwdef-TK_Saber.h @@ -1,7 +1,9 @@ -#ifndef HWDEF_TK_SABER_H -#define HWDEF_TK_SABER_H +// TK 4-color lightsaber driver layout +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* TK 4-color lightsaber driver layout +/* * ---- * Reset -|1 8|- VCC * PWM 4 (A) -|2 7|- e-switch @@ -33,4 +35,3 @@ #define LAYOUT_DEFINED -#endif diff --git a/hwdef-Wurkkos_TS10.h b/hwdef-Wurkkos_TS10.h index 6cfe050..1d138be 100644 --- a/hwdef-Wurkkos_TS10.h +++ b/hwdef-Wurkkos_TS10.h @@ -1,17 +1,17 @@ -#ifndef HWDEF_BLF_Q8_T1616_H -#define HWDEF_BLF_Q8_T1616_H - -/* BLF Q8 driver layout using the Attiny1616 - -Driver pinout: +// Wurkkos TS10 driver layout +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * (based on BLF Q8-t1616 driver layout) + * Driver pinout: * eSwitch: PA5 * Aux LED: PB5 * PWM FET: PB0 (TCA0 WO0) * PWM 1x7135: PB1 (TCA0 WO1) * Voltage: VCC - -*/ - + */ #define LAYOUT_DEFINED @@ -113,5 +113,3 @@ inline void hwdef_setup() { TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; } - -#endif diff --git a/hwdef-Wurkkos_TS25.h b/hwdef-Wurkkos_TS25.h index cadd366..cf34754 100644 --- a/hwdef-Wurkkos_TS25.h +++ b/hwdef-Wurkkos_TS25.h @@ -1,9 +1,10 @@ -#ifndef HWDEF_WURKKOS_TS25_T1616_H -#define HWDEF_WURKKOS_TS25_T1616_H +// Wurkkos TS25 driver layout +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once -/* BLF Q8 driver layout using the Attiny1616 - -Driver pinout: +/* + * Driver pinout: * eSwitch: PA5 * PWM FET: PB0 (TCA0 WO0) * PWM 1x7135: PB1 (TCA0 WO1) @@ -11,9 +12,7 @@ Driver pinout: * Aux Blue: PC1 * Aux Red: PC2 * Aux Green: PC3 - -*/ - + */ #define LAYOUT_DEFINED @@ -115,5 +114,3 @@ inline void hwdef_setup() { TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; } - -#endif diff --git a/hwdef-fw3x-lume1.h b/hwdef-fw3x-lume1.h index 09c5bfe..f2e9141 100644 --- a/hwdef-fw3x-lume1.h +++ b/hwdef-fw3x-lume1.h @@ -1,5 +1,7 @@ -#ifndef HWDEF_FW3X_LUME1_H -#define HWDEF_FW3X_LUME1_H +// lume1 Driver Rev B for FW3x driver layout (attiny1634) +// Copyright (C) 2020-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once /* lume1 Driver Rev B for FW3x driver layout (attiny1634) * www.loneoceans.com/labs/ for more information @@ -166,4 +168,3 @@ inline void hwdef_setup() { #define LAYOUT_DEFINED -#endif diff --git a/hwdef-gchart-fet1-t1616.h b/hwdef-gchart-fet1-t1616.h index 2435b99..9625738 100644 --- a/hwdef-gchart-fet1-t1616.h +++ b/hwdef-gchart-fet1-t1616.h @@ -1,14 +1,14 @@ -#ifndef HWDEF_GCH_FET1_T1616_H -#define HWDEF_GCH_FET1_T1616_H - -/* gChart's custom FET+1 driver layout - -PB0 - PWM for FET (TCA - WO0) -PB1 - PWM for 7135 (TCA - WO1) -PB2 - Switch pin, internal pullup -PB3 - Aux LED with 4700 Ohm series resistor -Read voltage from VCC pin, has diode with ~0.4v drop - +// gChart's custom FET+1 driver layout +// Copyright (C) 2020-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * PB0 - PWM for FET (TCA - WO0) + * PB1 - PWM for 7135 (TCA - WO1) + * PB2 - Switch pin, internal pullup + * PB3 - Aux LED with 4700 Ohm series resistor + * Read voltage from VCC pin, has diode with ~0.4v drop */ @@ -102,5 +102,3 @@ inline void hwdef_setup() { TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; } - -#endif diff --git a/hwdef-thefreeman-lin16dac.h b/hwdef-thefreeman-lin16dac.h index 9d6b145..36e3929 100644 --- a/hwdef-thefreeman-lin16dac.h +++ b/hwdef-thefreeman-lin16dac.h @@ -1,17 +1,16 @@ -#ifndef HWDEF_THEFREEMAN_LIN18_H -#define HWDEF_THEFREEMAN_LIN18_H - -/* thefreeman's Linear 16 driver using DAC control - -PA6 - DAC for LED brightness control -PA7 - Op-amp enable pin -PB5 - Aux LED -PB4 - Switch pin, internal pullup -PB3 - HDR control, set High to enable the high power channel, set Low for low power -Read voltage from VCC pin, has PFET so no drop - -*/ - +// thefreeman's Linear 16 driver using DAC control +// Copyright (C) 2021-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * PA6 - DAC for LED brightness control + * PA7 - Op-amp enable pin + * PB5 - Aux LED + * PB4 - Switch pin, internal pullup + * PB3 - HDR control, set High to enable the high power channel, set Low for low power + * Read voltage from VCC pin, has PFET so no drop + */ #define LAYOUT_DEFINED @@ -105,5 +104,3 @@ inline void hwdef_setup() { } - -#endif diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index e180cc4..bd05ede 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -1,22 +1,7 @@ -/* - * Anduril: Narsil-inspired UI for SpaghettiMonster. - * (Anduril is Aragorn's sword, the blade Narsil reforged) - * - * Copyright (C) 2017-2020 Selene ToyKeeper - * - * 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 3 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 . - */ +// Anduril: Narsil-inspired UI for SpaghettiMonster. +// (Anduril is Aragorn's sword, the blade Narsil reforged) +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later /* * Usually a program would be structured like this... diff --git a/spaghetti-monster/anduril/aux-leds.c b/spaghetti-monster/anduril/aux-leds.c index bb184f9..d9b23d0 100644 --- a/spaghetti-monster/anduril/aux-leds.c +++ b/spaghetti-monster/anduril/aux-leds.c @@ -1,24 +1,7 @@ -/* - * aux-leds.c: Aux LED functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef AUX_LEDS_C -#define AUX_LEDS_C +// aux-leds.c: Aux LED functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #include "aux-leds.h" @@ -208,6 +191,3 @@ void rgb_led_voltage_readout(uint8_t bright) { } #endif - -#endif - diff --git a/spaghetti-monster/anduril/aux-leds.h b/spaghetti-monster/anduril/aux-leds.h index f496ddc..1938557 100644 --- a/spaghetti-monster/anduril/aux-leds.h +++ b/spaghetti-monster/anduril/aux-leds.h @@ -1,24 +1,7 @@ -/* - * aux-leds.h: Aux LED functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef AUX_LEDS_H -#define AUX_LEDS_H +// aux-leds.h: Aux LED functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) void indicator_led_update(uint8_t mode, uint8_t tick); @@ -78,5 +61,3 @@ const PROGMEM uint8_t rgb_led_colors[] = { #endif #endif - -#endif diff --git a/spaghetti-monster/anduril/battcheck-mode-fsm.h b/spaghetti-monster/anduril/battcheck-mode-fsm.h index 8f19e12..4ab8f06 100644 --- a/spaghetti-monster/anduril/battcheck-mode-fsm.h +++ b/spaghetti-monster/anduril/battcheck-mode-fsm.h @@ -1,26 +1,7 @@ -/* - * battcheck-mode-fsm.h: FSM config for battery check mode in Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef BATTCHECK_MODE_FSM_H -#define BATTCHECK_MODE_FSM_H +// battcheck-mode-fsm.h: FSM config for battery check mode in Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #define USE_BATTCHECK - -#endif diff --git a/spaghetti-monster/anduril/battcheck-mode.c b/spaghetti-monster/anduril/battcheck-mode.c index 5edc6f4..9eb82fe 100644 --- a/spaghetti-monster/anduril/battcheck-mode.c +++ b/spaghetti-monster/anduril/battcheck-mode.c @@ -1,24 +1,7 @@ -/* - * battcheck-mode.c: Battery check mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef BATTCHECK_MODE_C -#define BATTCHECK_MODE_C +// battcheck-mode.c: Battery check mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #include "battcheck-mode.h" @@ -77,6 +60,3 @@ uint8_t voltage_config_state(Event event, uint16_t arg) { } #endif // #ifdef USE_VOLTAGE_CORRECTION - -#endif - diff --git a/spaghetti-monster/anduril/battcheck-mode.h b/spaghetti-monster/anduril/battcheck-mode.h index 965ffd9..b505b68 100644 --- a/spaghetti-monster/anduril/battcheck-mode.h +++ b/spaghetti-monster/anduril/battcheck-mode.h @@ -1,24 +1,7 @@ -/* - * battcheck-mode.h: Battery check mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef BATTCHECK_MODE_H -#define BATTCHECK_MODE_H +// battcheck-mode.h: Battery check mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once uint8_t battcheck_state(Event event, uint16_t arg); @@ -27,5 +10,3 @@ void voltage_config_save(uint8_t step, uint8_t value); uint8_t voltage_config_state(Event event, uint16_t arg); #endif - -#endif diff --git a/spaghetti-monster/anduril/beacon-mode.c b/spaghetti-monster/anduril/beacon-mode.c index 76ada0f..6359b74 100644 --- a/spaghetti-monster/anduril/beacon-mode.c +++ b/spaghetti-monster/anduril/beacon-mode.c @@ -1,24 +1,7 @@ -/* - * beacon-mode.c: Beacon mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef BEACON_MODE_C -#define BEACON_MODE_C +// beacon-mode.c: Beacon mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #include "beacon-mode.h" @@ -68,6 +51,3 @@ uint8_t beacon_state(Event event, uint16_t arg) { return EVENT_NOT_HANDLED; } - -#endif - diff --git a/spaghetti-monster/anduril/beacon-mode.h b/spaghetti-monster/anduril/beacon-mode.h index c0f0b18..df047ad 100644 --- a/spaghetti-monster/anduril/beacon-mode.h +++ b/spaghetti-monster/anduril/beacon-mode.h @@ -1,28 +1,9 @@ -/* - * beacon-mode.h: Beacon mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef BEACON_MODE_H -#define BEACON_MODE_H +// beacon-mode.h: Beacon mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once // beacon mode uint8_t beacon_state(Event event, uint16_t arg); inline void beacon_mode_iter(); - -#endif diff --git a/spaghetti-monster/anduril/candle-mode.c b/spaghetti-monster/anduril/candle-mode.c index 12ffa84..bfb0377 100644 --- a/spaghetti-monster/anduril/candle-mode.c +++ b/spaghetti-monster/anduril/candle-mode.c @@ -1,24 +1,7 @@ -/* - * candle-mode.c: Candle mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef CANDLE_MODE_C -#define CANDLE_MODE_C +// candle-mode.c: Candle mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #include "candle-mode.h" @@ -151,6 +134,3 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { return EVENT_NOT_HANDLED; } - -#endif - diff --git a/spaghetti-monster/anduril/candle-mode.h b/spaghetti-monster/anduril/candle-mode.h index 8859a9c..aab237d 100644 --- a/spaghetti-monster/anduril/candle-mode.h +++ b/spaghetti-monster/anduril/candle-mode.h @@ -1,24 +1,7 @@ -/* - * candle-mode.h: Candle mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef CANDLE_MODE_H -#define CANDLE_MODE_H +// candle-mode.h: Candle mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #ifndef CANDLE_AMPLITUDE #define CANDLE_AMPLITUDE 25 @@ -28,5 +11,3 @@ uint8_t candle_mode_state(Event event, uint16_t arg); // moved to fsm-misc.c because it's also used for tint ramping power correction //uint8_t triangle_wave(uint8_t phase); - -#endif diff --git a/spaghetti-monster/anduril/cfg-blf-gt-mini.h b/spaghetti-monster/anduril/cfg-blf-gt-mini.h index a647ea5..4158f21 100644 --- a/spaghetti-monster/anduril/cfg-blf-gt-mini.h +++ b/spaghetti-monster/anduril/cfg-blf-gt-mini.h @@ -1,4 +1,8 @@ // BLF/Lumintop GT Mini config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "hwdef-BLF_GT_Mini.h" // Same as an Emisar D1S, except it has a lighted button #include "cfg-emisar-d1s.h" diff --git a/spaghetti-monster/anduril/cfg-blf-gt.h b/spaghetti-monster/anduril/cfg-blf-gt.h index 977d877..425ecdc 100644 --- a/spaghetti-monster/anduril/cfg-blf-gt.h +++ b/spaghetti-monster/anduril/cfg-blf-gt.h @@ -1,4 +1,8 @@ // BLF GT config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0321" #include "hwdef-BLF_GT.h" diff --git a/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h b/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h index 06d5395..18caa5b 100644 --- a/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h +++ b/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h @@ -1,4 +1,8 @@ // BLF Lantern config options for Anduril using the Attiny1616 +// Copyright (C) 2021-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0622" #include "hwdef-BLF_LT1-t1616.h" // ATTINY: 1616 diff --git a/spaghetti-monster/anduril/cfg-blf-lantern.h b/spaghetti-monster/anduril/cfg-blf-lantern.h index 251c0db..c6b7bc8 100644 --- a/spaghetti-monster/anduril/cfg-blf-lantern.h +++ b/spaghetti-monster/anduril/cfg-blf-lantern.h @@ -1,4 +1,8 @@ // BLF Lantern config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0621" #include "hwdef-BLF_LT1.h" // ATTINY: 85 diff --git a/spaghetti-monster/anduril/cfg-blf-q8-t1616.h b/spaghetti-monster/anduril/cfg-blf-q8-t1616.h index 204066d..a88ab24 100644 --- a/spaghetti-monster/anduril/cfg-blf-q8-t1616.h +++ b/spaghetti-monster/anduril/cfg-blf-q8-t1616.h @@ -1,4 +1,8 @@ // BLF Q8 config options for Anduril using the Attiny1616 +// Copyright (C) 2021-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0613" #include "hwdef-BLF_Q8-T1616.h" // ATTINY: 1616 diff --git a/spaghetti-monster/anduril/cfg-blf-q8.h b/spaghetti-monster/anduril/cfg-blf-q8.h index a9c48f6..166c8ca 100644 --- a/spaghetti-monster/anduril/cfg-blf-q8.h +++ b/spaghetti-monster/anduril/cfg-blf-q8.h @@ -1,4 +1,8 @@ // BLF Q8 config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0611" #include "hwdef-BLF_Q8.h" diff --git a/spaghetti-monster/anduril/cfg-emisar-d1.h b/spaghetti-monster/anduril/cfg-emisar-d1.h index 2427773..3bcf6a5 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1.h @@ -1,4 +1,8 @@ // Emisar D1 config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "hwdef-Emisar_D1.h" // same as Emisar D4, mostly #include "cfg-emisar-d4.h" diff --git a/spaghetti-monster/anduril/cfg-emisar-d18-219.h b/spaghetti-monster/anduril/cfg-emisar-d18-219.h index 1f3a3c2..126e9f4 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d18-219.h +++ b/spaghetti-monster/anduril/cfg-emisar-d18-219.h @@ -1,4 +1,8 @@ // Emisar D18 (FET+13+1) reduced-FET config options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-emisar-d18.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0142" diff --git a/spaghetti-monster/anduril/cfg-emisar-d18.h b/spaghetti-monster/anduril/cfg-emisar-d18.h index 6644513..d59199c 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d18.h +++ b/spaghetti-monster/anduril/cfg-emisar-d18.h @@ -1,4 +1,8 @@ // Emisar D18 (FET+13+1) config options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0141" #include "hwdef-Emisar_D18.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-emisar-d1s.h b/spaghetti-monster/anduril/cfg-emisar-d1s.h index 47cecf6..43d8160 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1s.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1s.h @@ -1,4 +1,8 @@ // Emisar D1S config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "hwdef-Emisar_D1S.h" // same as Emisar D4, mostly #include "cfg-emisar-d4.h" diff --git a/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h b/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h index aa9780b..15464db 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h @@ -1,7 +1,11 @@ // Emisar D1v2 (7135+FET) config options for Anduril -// (was only made for a short time, not many people have one) +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // ATTINY: 1634 // same as Emisar D4v2, mostly +// (was only made for a short time, not many people have one) #include "cfg-emisar-d4v2.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0123" diff --git a/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h b/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h index 5dd5a2e..c8864bf 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h @@ -1,5 +1,9 @@ // Emisar D1v2 (linear+FET) config options for Anduril // (2022 re-issue / update of old D1) +// Copyright (C) 2022-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // ATTINY: 1634 // similar to a Noctigon KR4, sort of #include "cfg-noctigon-kr4.h" diff --git a/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h b/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h index 1c7aec9..ede1b67 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h @@ -1,5 +1,9 @@ -// Emisar D1v2 (linear+FET) config options for Anduril +// Emisar D1v2 (linear only, no DDFET) config options for Anduril // (2022 re-issue / update of old D1) +// Copyright (C) 2022-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // ATTINY: 1634 // similar to a Noctigon KR4, sort of #include "cfg-noctigon-kr4-nofet.h" diff --git a/spaghetti-monster/anduril/cfg-emisar-d4-219c.h b/spaghetti-monster/anduril/cfg-emisar-d4-219c.h index e525d86..65649e3 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4-219c.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4-219c.h @@ -1,5 +1,9 @@ // Emisar D4-219C config options for Anduril -// same as D4S but with FET modes limited to 80% power +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// same as D4 but with FET modes limited to 80% power // to avoid destroying the LEDs #include "cfg-emisar-d4.h" #undef MODEL_NUMBER diff --git a/spaghetti-monster/anduril/cfg-emisar-d4.h b/spaghetti-monster/anduril/cfg-emisar-d4.h index e77ac38..15a72ac 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4.h @@ -1,4 +1,8 @@ // Emisar D4 config options for Anduril +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0111" #include "hwdef-Emisar_D4.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-emisar-d4s-219c.h b/spaghetti-monster/anduril/cfg-emisar-d4s-219c.h index 6489b34..f86c1b1 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4s-219c.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4s-219c.h @@ -1,4 +1,8 @@ // Emisar D4S-219C config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // same as D4S but with FET modes limited to 80% power // to avoid destroying the LEDs #include "cfg-emisar-d4s.h" diff --git a/spaghetti-monster/anduril/cfg-emisar-d4s.h b/spaghetti-monster/anduril/cfg-emisar-d4s.h index 3c82460..a3dc65f 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4s.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4s.h @@ -1,4 +1,8 @@ // Emisar D4S config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0131" #include "hwdef-Emisar_D4S.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-emisar-d4sv2-219.h b/spaghetti-monster/anduril/cfg-emisar-d4sv2-219.h index 54a2e6b..22775cc 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4sv2-219.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4sv2-219.h @@ -1,4 +1,8 @@ // Emisar D4Sv2-219 config options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-emisar-d4sv2.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0134" diff --git a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp-fet.h b/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp-fet.h index 657e25d..437387c 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp-fet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp-fet.h @@ -1,4 +1,8 @@ // Emisar D4S V2 tint-ramping (plus FET) config options for Anduril (based on Noctigon K9.3) +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-emisar-d4sv2-tintramp.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0136" diff --git a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h b/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h index 3e54dca..bfbcba0 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h @@ -1,4 +1,8 @@ // Emisar D4S V2 tint-ramping config options for Anduril (based on Noctigon K9.3) +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0135" #include "hwdef-Emisar_D4Sv2-tintramp.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-emisar-d4sv2.h b/spaghetti-monster/anduril/cfg-emisar-d4sv2.h index 5f18fbc..1bf2c2e 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4sv2.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4sv2.h @@ -1,4 +1,8 @@ // Emisar D4S V2 config options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0133" #include "hwdef-Emisar_D4Sv2.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-emisar-d4v2-219.h b/spaghetti-monster/anduril/cfg-emisar-d4v2-219.h index dad84f0..e9775ec 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4v2-219.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4v2-219.h @@ -1,4 +1,8 @@ // Emisar D4v2-219 config options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-emisar-d4v2.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0114" diff --git a/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h b/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h index 5e33a05..9c6f0b0 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h @@ -1,4 +1,8 @@ // Emisar D4v2-noFET config options for Anduril +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-emisar-d4v2.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0115" diff --git a/spaghetti-monster/anduril/cfg-emisar-d4v2.h b/spaghetti-monster/anduril/cfg-emisar-d4v2.h index 54de297..670482c 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4v2.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4v2.h @@ -1,6 +1,7 @@ -// Emisar D4 config options for Anduril -// Copyright (C) 2019 Selene ToyKeeper +// Emisar D4v2 config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #define MODEL_NUMBER "0113" #include "hwdef-Emisar_D4v2.h" diff --git a/spaghetti-monster/anduril/cfg-ff-e01.h b/spaghetti-monster/anduril/cfg-ff-e01.h index f26bfb4..6d561b2 100644 --- a/spaghetti-monster/anduril/cfg-ff-e01.h +++ b/spaghetti-monster/anduril/cfg-ff-e01.h @@ -1,4 +1,8 @@ // Fireflies E01 SST-40 thrower config options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // most of the good stuff is in the FFUI config; just copy it #include "../fireflies-ui/cfg-ff-e01.h" #undef MODEL_NUMBER diff --git a/spaghetti-monster/anduril/cfg-ff-pl47-219.h b/spaghetti-monster/anduril/cfg-ff-pl47-219.h index efba8d3..11bd5b1 100644 --- a/spaghetti-monster/anduril/cfg-ff-pl47-219.h +++ b/spaghetti-monster/anduril/cfg-ff-pl47-219.h @@ -1,4 +1,8 @@ // Fireflies PL47-219B config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // same as PL47 but with FET modes limited to 67% power // to avoid destroying the LEDs #include "cfg-ff-pl47.h" diff --git a/spaghetti-monster/anduril/cfg-ff-pl47.h b/spaghetti-monster/anduril/cfg-ff-pl47.h index 54827cf..4ecee44 100644 --- a/spaghetti-monster/anduril/cfg-ff-pl47.h +++ b/spaghetti-monster/anduril/cfg-ff-pl47.h @@ -1,4 +1,8 @@ // Fireflies PL47 config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0421" #include "hwdef-FF_PL47.h" diff --git a/spaghetti-monster/anduril/cfg-ff-pl47g2.h b/spaghetti-monster/anduril/cfg-ff-pl47g2.h index c11ba28..923afac 100644 --- a/spaghetti-monster/anduril/cfg-ff-pl47g2.h +++ b/spaghetti-monster/anduril/cfg-ff-pl47g2.h @@ -1,4 +1,8 @@ // Fireflies PL47 G2 config options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0423" #include "hwdef-FF_PL47.h" diff --git a/spaghetti-monster/anduril/cfg-ff-rot66-219.h b/spaghetti-monster/anduril/cfg-ff-rot66-219.h index 086f8ac..4dad4e2 100644 --- a/spaghetti-monster/anduril/cfg-ff-rot66-219.h +++ b/spaghetti-monster/anduril/cfg-ff-rot66-219.h @@ -1,4 +1,8 @@ // Fireflies ROT66-219 (7x7135) config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // same as regular ROT66, but calibrated for Nichia 219B with 7x7135 chips #include "cfg-ff-rot66.h" #undef MODEL_NUMBER diff --git a/spaghetti-monster/anduril/cfg-ff-rot66.h b/spaghetti-monster/anduril/cfg-ff-rot66.h index d386f17..f357956 100644 --- a/spaghetti-monster/anduril/cfg-ff-rot66.h +++ b/spaghetti-monster/anduril/cfg-ff-rot66.h @@ -1,4 +1,8 @@ // Fireflies ROT66 (14x7135) config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0411" #include "hwdef-FF_ROT66.h" diff --git a/spaghetti-monster/anduril/cfg-ff-rot66g2.h b/spaghetti-monster/anduril/cfg-ff-rot66g2.h index 9737cc4..dca180d 100644 --- a/spaghetti-monster/anduril/cfg-ff-rot66g2.h +++ b/spaghetti-monster/anduril/cfg-ff-rot66g2.h @@ -1,4 +1,8 @@ // Fireflies ROT66 G2 config options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-ff-rot66.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0413" diff --git a/spaghetti-monster/anduril/cfg-fw3a-219.h b/spaghetti-monster/anduril/cfg-fw3a-219.h index c9bf0c1..88739bf 100644 --- a/spaghetti-monster/anduril/cfg-fw3a-219.h +++ b/spaghetti-monster/anduril/cfg-fw3a-219.h @@ -1,4 +1,8 @@ // FW3A-219 config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-fw3a.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0312" diff --git a/spaghetti-monster/anduril/cfg-fw3a-nofet.h b/spaghetti-monster/anduril/cfg-fw3a-nofet.h index 7752c10..e828ac5 100644 --- a/spaghetti-monster/anduril/cfg-fw3a-nofet.h +++ b/spaghetti-monster/anduril/cfg-fw3a-nofet.h @@ -1,4 +1,8 @@ // FW3A with the FET disabled +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-fw3a.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0313" diff --git a/spaghetti-monster/anduril/cfg-fw3a.h b/spaghetti-monster/anduril/cfg-fw3a.h index 24a77c0..f75fe13 100644 --- a/spaghetti-monster/anduril/cfg-fw3a.h +++ b/spaghetti-monster/anduril/cfg-fw3a.h @@ -1,4 +1,8 @@ // FW3A config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0311" #include "hwdef-FW3A.h" diff --git a/spaghetti-monster/anduril/cfg-fw3x-lume1.h b/spaghetti-monster/anduril/cfg-fw3x-lume1.h index 2f90920..280c433 100644 --- a/spaghetti-monster/anduril/cfg-fw3x-lume1.h +++ b/spaghetti-monster/anduril/cfg-fw3x-lume1.h @@ -1,4 +1,9 @@ -/* lume1 for FW3x config options for Anduril +// lume1 for FW3x config options for Anduril +// Copyright (C) 2020-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* * Constant current Buck-Boost + FET driver * For more information: www.loneoceans.com/labs/ * Datasheets: diff --git a/spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h b/spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h index 9036d26..eb17399 100644 --- a/spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h +++ b/spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h @@ -1,4 +1,8 @@ // gChart's custom FET+1 driver config options for Anduril +// Copyright (C) 2020-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "1618" // Golden Ratio... because I can #include "hwdef-gchart-fet1-t1616.h" // ATTINY: 1616 diff --git a/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h b/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h index 894ebaf..47ff84b 100644 --- a/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h +++ b/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h @@ -1,4 +1,8 @@ // Mateminco/Astrolux MF01-Mini options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0521" #include "hwdef-Mateminco_MF01-Mini.h" diff --git a/spaghetti-monster/anduril/cfg-mateminco-mf01s.h b/spaghetti-monster/anduril/cfg-mateminco-mf01s.h index 49dbcf0..20bcccd 100644 --- a/spaghetti-monster/anduril/cfg-mateminco-mf01s.h +++ b/spaghetti-monster/anduril/cfg-mateminco-mf01s.h @@ -1,4 +1,8 @@ // Mateminco/Astrolux MF01S options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0511" #include "hwdef-Mateminco_MF01S.h" diff --git a/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h b/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h index d7264a2..fef1af6 100644 --- a/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h +++ b/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h @@ -1,4 +1,8 @@ // Mateminco MT35 Mini / Astrolux FT03 +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0531" #include "hwdef-Mateminco_MT35-Mini.h" // ATTINY: 85 diff --git a/spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h b/spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h index bd41660..e0fc162 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h +++ b/spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h @@ -1,4 +1,8 @@ // Noctigon DM11 (12V) config options for Anduril +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0273" #include "hwdef-Noctigon_DM11-12V.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-noctigon-dm11-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-dm11-nofet.h index 5a828d6..ad71fa9 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-dm11-nofet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-dm11-nofet.h @@ -1,4 +1,8 @@ // Noctigon DM11-noFET config options for Anduril +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-noctigon-dm11.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0272" diff --git a/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h b/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h index 92c1ded..5a978b5 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h +++ b/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h @@ -1,4 +1,8 @@ // Noctigon DM11-SBT90.2 config options for Anduril +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0274" #include "hwdef-Noctigon_DM11-SBT90.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-noctigon-dm11.h b/spaghetti-monster/anduril/cfg-noctigon-dm11.h index 4c746c9..d9b0b8c 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-dm11.h +++ b/spaghetti-monster/anduril/cfg-noctigon-dm11.h @@ -1,4 +1,8 @@ // Noctigon DM11 config options for Anduril +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0271" #include "hwdef-Noctigon_DM11.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-noctigon-k1-12v.h b/spaghetti-monster/anduril/cfg-noctigon-k1-12v.h index 7f8f4cf..dbd0353 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k1-12v.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k1-12v.h @@ -1,4 +1,8 @@ // Noctigon K1 12V config options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0253" #include "hwdef-Noctigon_K1-12V.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-noctigon-k1-sbt90.h b/spaghetti-monster/anduril/cfg-noctigon-k1-sbt90.h index 9207dbc..81063fa 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k1-sbt90.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k1-sbt90.h @@ -1,4 +1,8 @@ // Noctigon K1-SBT90.2 config options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // (is a K1 host with a KR4-like driver and a really high-powered LED) #define MODEL_NUMBER "0252" #include "hwdef-Noctigon_K1-SBT90.h" diff --git a/spaghetti-monster/anduril/cfg-noctigon-k1.h b/spaghetti-monster/anduril/cfg-noctigon-k1.h index fb2a89c..93244a6 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k1.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k1.h @@ -1,4 +1,8 @@ // Noctigon K1 config options for Anduril +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0251" // (originally known as Emisar D1S v2) #include "hwdef-Noctigon_K1.h" diff --git a/spaghetti-monster/anduril/cfg-noctigon-k9.3-219.h b/spaghetti-monster/anduril/cfg-noctigon-k9.3-219.h index a88ad2c..2f8bdc0 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k9.3-219.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k9.3-219.h @@ -1,4 +1,8 @@ // Noctigon K9.3 (reduced FET) config options for Anduril +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-noctigon-k9.3.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0263" diff --git a/spaghetti-monster/anduril/cfg-noctigon-k9.3-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-k9.3-nofet.h index e91ebc4..ece2bb2 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k9.3-nofet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k9.3-nofet.h @@ -1,4 +1,8 @@ // Noctigon K9.3 (noFET) config options for Anduril +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-noctigon-k9.3.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0262" diff --git a/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-219.h b/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-219.h index 04efa83..4eb8c86 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-219.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-219.h @@ -1,4 +1,8 @@ // Noctigon K9.3 tint-ramping (reduced FET) config options for Anduril +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-noctigon-k9.3-tintramp-fet.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0267" diff --git a/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-fet.h b/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-fet.h index 8535c57..0c8f3c8 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-fet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-fet.h @@ -1,4 +1,8 @@ // Noctigon K9.3 tint-ramping (plus FET) config options for Anduril +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-noctigon-k9.3-tintramp-nofet.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0266" diff --git a/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-nofet.h index 21ab415..b505701 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-nofet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-nofet.h @@ -1,4 +1,8 @@ // Noctigon K9.3 noFET tint-ramping config options for Anduril +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0265" #include "hwdef-Emisar_D4Sv2-tintramp.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-noctigon-k9.3.c b/spaghetti-monster/anduril/cfg-noctigon-k9.3.c index d79c03f..d30d397 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k9.3.c +++ b/spaghetti-monster/anduril/cfg-noctigon-k9.3.c @@ -1,4 +1,9 @@ #error This build is broken. +// Noctigon K9.3 code overrides for Anduril +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + /* * K9.3 has unusual power channels, so it must override some of FSM's code. * There are two sets of LEDs: diff --git a/spaghetti-monster/anduril/cfg-noctigon-k9.3.h b/spaghetti-monster/anduril/cfg-noctigon-k9.3.h index f3a6cdd..dfe1d18 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k9.3.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k9.3.h @@ -1,4 +1,8 @@ // Noctigon K9.3 config options for Anduril +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0261" #include "hwdef-Noctigon_K9.3.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-12v.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-12v.h index a513b3f..52a031d 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4-12v.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-12v.h @@ -1,5 +1,9 @@ // Noctigon KR4 (12V) config options for Anduril // (and Noctigon KR1) +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0216" #include "hwdef-Noctigon_KR4-12V.h" // ATTINY: 1634 diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-219.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-219.h index 28fc595..5d106ef 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4-219.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-219.h @@ -1,4 +1,8 @@ // Noctigon KR4 (reduced FET) config options for Anduril +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-noctigon-kr4.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0213" diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-219b.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-219b.h index 39ac57c..b242048 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4-219b.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-219b.h @@ -1,4 +1,8 @@ // Noctigon KR4 (reduced FET) config options for Anduril +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-noctigon-kr4.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0214" diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h index e4879ef..701d93f 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h @@ -1,4 +1,8 @@ // Noctigon KR4 (fetless) config options for Anduril +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // (and Noctigon KR1) // (and Emisar D4v2 E21A, a.k.a. "D4v2.5") #include "cfg-noctigon-kr4.h" diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-tintramp.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-tintramp.h index f19744d..c36df47 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4-tintramp.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-tintramp.h @@ -1,4 +1,8 @@ // Noctigon KR4 tint-ramping config options for Anduril +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // (basically the same as Emisar D4S V2 tint-ramping, // but switch on a different pin, and no lighted button) // ATTINY: 1634 diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index 8071457..d5d7f8c 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -1,5 +1,9 @@ // Noctigon KR4 config options for Anduril // (and Emisar D4v2.5, which uses KR4 driver plus a button LED) +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0211" #include "hwdef-Noctigon_KR4.h" #include "hank-cfg.h" diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.c b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.c deleted file mode 100644 index 571bbdc..0000000 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.c +++ /dev/null @@ -1,22 +0,0 @@ -// this is inserted into fsm-ramping.c :: set_level() -// (it overrides part of the function, but not all of it) -uint8_t output_mux; // pre-define this variable since the overrides file gets included before the ramp-mode.h file -inline void set_level_override(uint8_t level) { - if (level == 0) { // off - TINT1_LVL = 0; // disable the first white channel - TINT2_LVL = 0; // disable the second white channel - PWM3_LVL = 0; // disable the red LEDs - } else { - level --; - - if (output_mux == 0) { // main white LEDs - PWM3_LVL = 0; // disable the red LEDs - PWM1_LVL = PWM_GET(pwm1_levels, level); // get the PWM value - update_tint(); // set the warm-cool level balance - } else { // red LEDs - TINT1_LVL = 0; // disable the first white channel - TINT2_LVL = 0; // disable the second white channel - PWM3_LVL = PWM_GET(pwm1_levels, level); // set the red LED PWM - } - } -} \ No newline at end of file diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index 282dca2..993619a 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -1,4 +1,6 @@ -// Sofirn LT1S Pro +// Sofirn LT1S Pro config file for Anduril +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once #define MODEL_NUMBER "0623" diff --git a/spaghetti-monster/anduril/cfg-sofirn-sc21-pro.h b/spaghetti-monster/anduril/cfg-sofirn-sc21-pro.h index cee8172..8fd2dee 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-sc21-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-sc21-pro.h @@ -1,4 +1,8 @@ // Sofirn SC21 Pro - same setup as a Wurkkos TS10, but with the aux indicator on while ramping +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #include "cfg-wurkkos-ts10.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0632" diff --git a/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h b/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h index c1f1ed8..3a02fc2 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h @@ -1,4 +1,8 @@ // Sofirn SP10 Pro config options for Anduril +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0631" #include "hwdef-Sofirn_SP10-Pro.h" // ATTINY: 1616 diff --git a/spaghetti-monster/anduril/cfg-sofirn-sp36-t1616.h b/spaghetti-monster/anduril/cfg-sofirn-sp36-t1616.h index ce1c04a..cb29e4f 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-sp36-t1616.h +++ b/spaghetti-monster/anduril/cfg-sofirn-sp36-t1616.h @@ -1,4 +1,8 @@ // Sofirn SP36 (small Q8) config options for Anduril using the Attiny1616 +// Copyright (C) 2021-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // same as the BLF Q8, mostly #include "cfg-blf-q8-t1616.h" #undef MODEL_NUMBER diff --git a/spaghetti-monster/anduril/cfg-sofirn-sp36.h b/spaghetti-monster/anduril/cfg-sofirn-sp36.h index af8c18b..3661686 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-sp36.h +++ b/spaghetti-monster/anduril/cfg-sofirn-sp36.h @@ -1,4 +1,8 @@ // Sofirn SP36 (small Q8) config options for Anduril +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // same as the BLF Q8, mostly #include "cfg-blf-q8.h" #undef MODEL_NUMBER diff --git a/spaghetti-monster/anduril/cfg-thefreeman-lin16dac.h b/spaghetti-monster/anduril/cfg-thefreeman-lin16dac.h index 64dcd8c..2e155ec 100644 --- a/spaghetti-monster/anduril/cfg-thefreeman-lin16dac.h +++ b/spaghetti-monster/anduril/cfg-thefreeman-lin16dac.h @@ -1,4 +1,8 @@ // thefreeman's Linear 16 driver using DAC control +// Copyright (C) 2021-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0000" // TBD #include "hwdef-thefreeman-lin16dac.h" // ATTINY: 1616 diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts10.h b/spaghetti-monster/anduril/cfg-wurkkos-ts10.h index 6f92abf..bef2ad8 100644 --- a/spaghetti-monster/anduril/cfg-wurkkos-ts10.h +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts10.h @@ -1,4 +1,8 @@ // Wurkkos TS10 (originally used Sofirn SP36-t1616 firmware) config options for Anduril using the Attiny1616 +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + // same as the BLF Q8 T1616, mostly (added Dynamic PWM) #define MODEL_NUMBER "0714" #include "hwdef-Wurkkos_TS10.h" @@ -79,4 +83,4 @@ #endif #ifdef BLINK_AT_RAMP_CEIL #undef BLINK_AT_RAMP_CEIL -#endif \ No newline at end of file +#endif diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts25.h b/spaghetti-monster/anduril/cfg-wurkkos-ts25.h index a339cdb..3196a9a 100644 --- a/spaghetti-monster/anduril/cfg-wurkkos-ts25.h +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts25.h @@ -1,4 +1,8 @@ // Wurkkos TS25, modelled after the TS10 but with RGB Aux +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + #define MODEL_NUMBER "0715" #include "hwdef-Wurkkos_TS25.h" // ATTINY: 1616 @@ -75,4 +79,4 @@ #endif #ifdef BLINK_AT_RAMP_CEIL #undef BLINK_AT_RAMP_CEIL -#endif \ No newline at end of file +#endif diff --git a/spaghetti-monster/anduril/channel-modes.c b/spaghetti-monster/anduril/channel-modes.c index f3a21cf..51f294c 100644 --- a/spaghetti-monster/anduril/channel-modes.c +++ b/spaghetti-monster/anduril/channel-modes.c @@ -1,14 +1,11 @@ -/* - * channel-modes.c: Multi-channel functions for Anduril. - * Copyright (C) 2017-2023 Selene ToyKeeper - * SPDX-License-Identifier: GPL-3.0-or-later - */ +// channel-modes.c: Multi-channel functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once #include "channel-modes.h" - uint8_t channel_mode_state(Event event, uint16_t arg) { #ifdef USE_CHANNEL_MODE_ARGS static int8_t tint_ramp_direction = 1; @@ -144,3 +141,4 @@ uint8_t channel_mode_config_state(Event event, uint16_t arg) { ); } #endif + diff --git a/spaghetti-monster/anduril/channel-modes.h b/spaghetti-monster/anduril/channel-modes.h index c10af5b..67d6bbb 100644 --- a/spaghetti-monster/anduril/channel-modes.h +++ b/spaghetti-monster/anduril/channel-modes.h @@ -1,8 +1,6 @@ -/* - * channel-modes.h: Multi-channel functions for Anduril. - * Copyright (C) 2017-2023 Selene ToyKeeper - * SPDX-License-Identifier: GPL-3.0-or-later - */ +// channel-modes.h: Multi-channel functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/spaghetti-monster/anduril/config-default.h b/spaghetti-monster/anduril/config-default.h index 171c8b3..514b9a8 100644 --- a/spaghetti-monster/anduril/config-default.h +++ b/spaghetti-monster/anduril/config-default.h @@ -1,24 +1,8 @@ -/* - * config-default.h: Default configuration for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// config-default.h: Default configuration for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef CONFIG_DEFAULT_H -#define CONFIG_DEFAULT_H +#pragma once /* * This file specifies the default settings for Anduril. @@ -197,4 +181,3 @@ // those oscillations //#define USE_LOWPASS_WHILE_ASLEEP -#endif diff --git a/spaghetti-monster/anduril/factory-reset-fsm.h b/spaghetti-monster/anduril/factory-reset-fsm.h index a8fb0d9..3cb0875 100644 --- a/spaghetti-monster/anduril/factory-reset-fsm.h +++ b/spaghetti-monster/anduril/factory-reset-fsm.h @@ -1,28 +1,10 @@ -/* - * factory-reset-fsm.h: FSM config options to enable factory reset in Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// factory-reset-fsm.h: FSM config options to enable factory reset in Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FACTORY_RESET_FSM_H -#define FACTORY_RESET_FSM_H +#pragma once #ifdef USE_SOFT_FACTORY_RESET #define USE_REBOOT #endif - -#endif diff --git a/spaghetti-monster/anduril/ff-strobe-modes.c b/spaghetti-monster/anduril/ff-strobe-modes.c index 4c12630..9e7f2bb 100644 --- a/spaghetti-monster/anduril/ff-strobe-modes.c +++ b/spaghetti-monster/anduril/ff-strobe-modes.c @@ -1,24 +1,8 @@ -/* - * ff-strobe-modes.c: Fireflies Flashlights strobe modes for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// ff-strobe-modes.c: Fireflies Flashlights strobe modes for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FF_STROBE_MODES_C -#define FF_STROBE_MODES_C +#pragma once #include "ff-strobe-modes.h" @@ -76,6 +60,3 @@ inline void police_strobe_iter() { } #endif - -#endif - diff --git a/spaghetti-monster/anduril/ff-strobe-modes.h b/spaghetti-monster/anduril/ff-strobe-modes.h index a3e0a27..d7adfec 100644 --- a/spaghetti-monster/anduril/ff-strobe-modes.h +++ b/spaghetti-monster/anduril/ff-strobe-modes.h @@ -1,24 +1,8 @@ -/* - * ff-strobe-modes.h: Fireflies Flashlights strobe modes for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// ff-strobe-modes.h: Fireflies Flashlights strobe modes for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FF_STROBE_MODES_H -#define FF_STROBE_MODES_H +#pragma once uint8_t boring_strobe_state(Event event, uint16_t arg); inline void boring_strobe_state_iter(); @@ -29,5 +13,3 @@ inline void police_strobe_iter(); #endif #define NUM_BORING_STROBES 2 - -#endif diff --git a/spaghetti-monster/anduril/hank-cfg.h b/spaghetti-monster/anduril/hank-cfg.h index f24ea67..f6b626a 100644 --- a/spaghetti-monster/anduril/hank-cfg.h +++ b/spaghetti-monster/anduril/hank-cfg.h @@ -1,5 +1,5 @@ // Intl-Outdoor (Hank)'s config options for Anduril -// Copyright (C) 2021 Selene ToyKeeper +// Copyright (C) 2021-2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/spaghetti-monster/anduril/lockout-mode-fsm.h b/spaghetti-monster/anduril/lockout-mode-fsm.h index bc18ed3..ede251c 100644 --- a/spaghetti-monster/anduril/lockout-mode-fsm.h +++ b/spaghetti-monster/anduril/lockout-mode-fsm.h @@ -1,29 +1,11 @@ -/* - * lockout-mode-fsm.h: FSM config for lockout mode in Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// lockout-mode-fsm.h: FSM config for lockout mode in Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef LOCKOUT_MODE_FSM_H -#define LOCKOUT_MODE_FSM_H +#pragma once // autolock function requires the ability to measure time while "off" #ifdef USE_AUTOLOCK #define TICK_DURING_STANDBY #endif - -#endif diff --git a/spaghetti-monster/anduril/lockout-mode.c b/spaghetti-monster/anduril/lockout-mode.c index 3bf7ce0..2439580 100644 --- a/spaghetti-monster/anduril/lockout-mode.c +++ b/spaghetti-monster/anduril/lockout-mode.c @@ -1,24 +1,8 @@ -/* - * lockout-mode.c: Lockout mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef LOCKOUT_MODE_C -#define LOCKOUT_MODE_C +// lockout-mode.c: Lockout mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once #include "lockout-mode.h" @@ -215,6 +199,3 @@ uint8_t autolock_config_state(Event event, uint16_t arg) { } #endif // #ifdef USE_AUTOLOCK - -#endif - diff --git a/spaghetti-monster/anduril/lockout-mode.h b/spaghetti-monster/anduril/lockout-mode.h index 37b02ab..c2703a0 100644 --- a/spaghetti-monster/anduril/lockout-mode.h +++ b/spaghetti-monster/anduril/lockout-mode.h @@ -1,24 +1,8 @@ -/* - * lockout-mode.h: Lockout mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// lockout-mode.h: Lockout mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef LOCKOUT_MODE_H -#define LOCKOUT_MODE_H +#pragma once // soft lockout uint8_t lockout_state(Event event, uint16_t arg); @@ -30,5 +14,3 @@ uint8_t lockout_state(Event event, uint16_t arg); uint8_t autolock_config_state(Event event, uint16_t arg); #endif - -#endif diff --git a/spaghetti-monster/anduril/misc.c b/spaghetti-monster/anduril/misc.c index 9c7f0dd..d78c542 100644 --- a/spaghetti-monster/anduril/misc.c +++ b/spaghetti-monster/anduril/misc.c @@ -1,24 +1,8 @@ -/* - * misc.c: Misc extra functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// misc.c: Misc extra functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef MISC_C -#define MISC_C +#pragma once #include "misc.h" @@ -62,6 +46,3 @@ void blip() { set_level(temp); } - -#endif - diff --git a/spaghetti-monster/anduril/misc.h b/spaghetti-monster/anduril/misc.h index 5febbc7..0f2992a 100644 --- a/spaghetti-monster/anduril/misc.h +++ b/spaghetti-monster/anduril/misc.h @@ -1,28 +1,10 @@ -/* - * misc.h: Misc extra functions for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// misc.h: Misc extra functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef MISC_H -#define MISC_H +#pragma once //void blink_confirm(uint8_t num); // no longer used void blink_once(); void blip(); - -#endif diff --git a/spaghetti-monster/anduril/momentary-mode.c b/spaghetti-monster/anduril/momentary-mode.c index 08879a1..2d8d57b 100644 --- a/spaghetti-monster/anduril/momentary-mode.c +++ b/spaghetti-monster/anduril/momentary-mode.c @@ -1,24 +1,8 @@ -/* - * momentary-mode.c: Momentary mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// momentary-mode.c: Momentary mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef MOMENTARY_MODE_C -#define MOMENTARY_MODE_C +#pragma once #include "momentary-mode.h" @@ -81,6 +65,3 @@ uint8_t momentary_state(Event event, uint16_t arg) { return EVENT_NOT_HANDLED; } - -#endif - diff --git a/spaghetti-monster/anduril/momentary-mode.h b/spaghetti-monster/anduril/momentary-mode.h index c5ccf0f..d774801 100644 --- a/spaghetti-monster/anduril/momentary-mode.h +++ b/spaghetti-monster/anduril/momentary-mode.h @@ -1,29 +1,11 @@ -/* - * momentary-mode.h: Momentary mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// momentary-mode.h: Momentary mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef MOMENTARY_MODE_H -#define MOMENTARY_MODE_H +#pragma once // momentary / signalling mode uint8_t momentary_state(Event event, uint16_t arg); uint8_t momentary_mode = 0; // 0 = ramping, 1 = strobe uint8_t momentary_active = 0; // boolean, true if active *right now* - -#endif diff --git a/spaghetti-monster/anduril/off-mode.c b/spaghetti-monster/anduril/off-mode.c index d9ab5cb..103e29d 100644 --- a/spaghetti-monster/anduril/off-mode.c +++ b/spaghetti-monster/anduril/off-mode.c @@ -1,24 +1,8 @@ -/* - * off-mode.c: "Off" mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef OFF_MODE_C -#define OFF_MODE_C +// off-mode.c: "Off" mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once #include "off-mode.h" @@ -363,6 +347,3 @@ uint8_t off_state(Event event, uint16_t arg) { return EVENT_NOT_HANDLED; } - -#endif - diff --git a/spaghetti-monster/anduril/off-mode.h b/spaghetti-monster/anduril/off-mode.h index 776173c..71d45eb 100644 --- a/spaghetti-monster/anduril/off-mode.h +++ b/spaghetti-monster/anduril/off-mode.h @@ -1,27 +1,9 @@ -/* - * off-mode.h: "Off" mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// off-mode.h: "Off" mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef OFF_MODE_H -#define OFF_MODE_H +#pragma once // when the light is "off" or in standby uint8_t off_state(Event event, uint16_t arg); - -#endif diff --git a/spaghetti-monster/anduril/ramp-mode-fsm.h b/spaghetti-monster/anduril/ramp-mode-fsm.h index 1a062e9..8fb80d1 100644 --- a/spaghetti-monster/anduril/ramp-mode-fsm.h +++ b/spaghetti-monster/anduril/ramp-mode-fsm.h @@ -1,24 +1,8 @@ -/* - * ramp-mode-fsm.h: FSM config for ramping functions in Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef RAMP_MODE_FSM_H -#define RAMP_MODE_FSM_H +// ramp-mode-fsm.h: FSM config for ramping functions in Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once // enable FSM's ramping features #define USE_RAMPING @@ -51,5 +35,3 @@ #define USE_GLOBALS_CONFIG #endif - -#endif diff --git a/spaghetti-monster/anduril/sos-mode.c b/spaghetti-monster/anduril/sos-mode.c index 97245c7..4704297 100644 --- a/spaghetti-monster/anduril/sos-mode.c +++ b/spaghetti-monster/anduril/sos-mode.c @@ -1,24 +1,8 @@ -/* - * sos-mode.c: SOS mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// sos-mode.c: SOS mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef SOS_MODE_C -#define SOS_MODE_C +#pragma once #include "sos-mode.h" @@ -70,6 +54,3 @@ inline void sos_mode_iter() { nice_delay_ms(2000); } - -#endif - diff --git a/spaghetti-monster/anduril/sos-mode.h b/spaghetti-monster/anduril/sos-mode.h index 397aa3f..5af61be 100644 --- a/spaghetti-monster/anduril/sos-mode.h +++ b/spaghetti-monster/anduril/sos-mode.h @@ -1,29 +1,11 @@ -/* - * sos-mode.h: SOS mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// sos-mode.h: SOS mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef SOS_MODE_H -#define SOS_MODE_H +#pragma once #ifdef USE_SOS_MODE_IN_BLINKY_GROUP // automatic SOS emergency signal uint8_t sos_state(Event event, uint16_t arg); #endif - -#endif diff --git a/spaghetti-monster/anduril/strobe-modes-fsm.h b/spaghetti-monster/anduril/strobe-modes-fsm.h index 002a951..da513a4 100644 --- a/spaghetti-monster/anduril/strobe-modes-fsm.h +++ b/spaghetti-monster/anduril/strobe-modes-fsm.h @@ -1,24 +1,8 @@ -/* - * strobe-modes-fsm.h: FSM config for strobe modes in Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// strobe-modes-fsm.h: FSM config for strobe modes in Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef STROBE_MODES_FSM_H -#define STROBE_MODES_FSM_H +#pragma once // enable the random number generator if we need it #if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) @@ -41,4 +25,3 @@ #define USE_STROBE_STATE #endif -#endif diff --git a/spaghetti-monster/anduril/strobe-modes.c b/spaghetti-monster/anduril/strobe-modes.c index 0664418..9963c80 100644 --- a/spaghetti-monster/anduril/strobe-modes.c +++ b/spaghetti-monster/anduril/strobe-modes.c @@ -1,24 +1,8 @@ -/* - * strobe-modes.c: Strobe modes for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef STROBE_MODES_C -#define STROBE_MODES_C +// strobe-modes.c: Strobe modes for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once #include "strobe-modes.h" @@ -326,6 +310,3 @@ inline void bike_flasher_iter() { #include "ff-strobe-modes.c" #endif - -#endif - diff --git a/spaghetti-monster/anduril/strobe-modes.h b/spaghetti-monster/anduril/strobe-modes.h index 0e7c873..9144d0e 100644 --- a/spaghetti-monster/anduril/strobe-modes.h +++ b/spaghetti-monster/anduril/strobe-modes.h @@ -1,24 +1,8 @@ -/* - * strobe-modes.h: Strobe modes for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef STROBE_MODES_H -#define STROBE_MODES_H +// strobe-modes.h: Strobe modes for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once // internal numbering for strobe modes #ifdef USE_STROBE_STATE @@ -106,4 +90,3 @@ inline void bike_flasher_iter(); #include "ff-strobe-modes.h" #endif -#endif diff --git a/spaghetti-monster/anduril/tactical-mode.c b/spaghetti-monster/anduril/tactical-mode.c index 2447a11..2f5c3b0 100644 --- a/spaghetti-monster/anduril/tactical-mode.c +++ b/spaghetti-monster/anduril/tactical-mode.c @@ -1,24 +1,8 @@ -/* - * tactical-mode.c: Tactical (ish) mode for Anduril. - * - * Copyright (C) 2023 Selene ToyKeeper - * - * 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 3 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 . - */ +// tactical-mode.c: Tactical (ish) mode for Anduril. +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef TACTICAL_MODE_C -#define TACTICAL_MODE_C +#pragma once #include "tactical-mode.h" @@ -118,6 +102,3 @@ uint8_t tactical_config_state(Event event, uint16_t arg) { return config_state_base(event, arg, 3, tactical_config_save); } - -#endif - diff --git a/spaghetti-monster/anduril/tactical-mode.h b/spaghetti-monster/anduril/tactical-mode.h index 14bf7ff..8972202 100644 --- a/spaghetti-monster/anduril/tactical-mode.h +++ b/spaghetti-monster/anduril/tactical-mode.h @@ -1,24 +1,8 @@ -/* - * tactical-mode.h: Tactical mode for Anduril. - * - * Copyright (C) 2023 Selene ToyKeeper - * - * 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 3 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 . - */ +// tactical-mode.h: Tactical mode for Anduril. +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef TACTICAL_MODE_H -#define TACTICAL_MODE_H +#pragma once #ifndef TACTICAL_LEVELS // high, low, tactical strobe @@ -29,5 +13,3 @@ uint8_t tactical_state(Event event, uint16_t arg); uint8_t tactical_config_state(Event event, uint16_t arg); - -#endif diff --git a/spaghetti-monster/anduril/tempcheck-mode.c b/spaghetti-monster/anduril/tempcheck-mode.c index 2e3b56f..4a413c9 100644 --- a/spaghetti-monster/anduril/tempcheck-mode.c +++ b/spaghetti-monster/anduril/tempcheck-mode.c @@ -1,24 +1,8 @@ -/* - * tempcheck-mode.c: Temperature check mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// tempcheck-mode.c: Temperature check mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef TEMPCHECK_MODE_C -#define TEMPCHECK_MODE_C +#pragma once #include "tempcheck-mode.h" @@ -70,6 +54,3 @@ uint8_t thermal_config_state(Event event, uint16_t arg) { 2, thermal_config_save); } - -#endif - diff --git a/spaghetti-monster/anduril/tempcheck-mode.h b/spaghetti-monster/anduril/tempcheck-mode.h index 83edd9c..15dd03e 100644 --- a/spaghetti-monster/anduril/tempcheck-mode.h +++ b/spaghetti-monster/anduril/tempcheck-mode.h @@ -1,24 +1,8 @@ -/* - * tempcheck-mode.h: Temperature check mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// tempcheck-mode.h: Temperature check mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef TEMPCHECK_MODE_H -#define TEMPCHECK_MODE_H +#pragma once #define USE_BLINK_NUM // FIXME: this only matters in an earlier header @@ -26,5 +10,3 @@ uint8_t tempcheck_state(Event event, uint16_t arg); uint8_t thermal_config_state(Event event, uint16_t arg); void thermal_config_save(uint8_t step, uint8_t value); - -#endif diff --git a/spaghetti-monster/anduril/tint-ramping.c b/spaghetti-monster/anduril/tint-ramping.c index 13f5d29..9418113 100644 --- a/spaghetti-monster/anduril/tint-ramping.c +++ b/spaghetti-monster/anduril/tint-ramping.c @@ -1,8 +1,6 @@ -/* - * tint-ramping.c: Tint ramping functions for Anduril. - * Copyright (C) 2017-2023 Selene ToyKeeper - * SPDX-License-Identifier: GPL-3.0-or-later - */ +// tint-ramping.c: Tint ramping functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/spaghetti-monster/anduril/tint-ramping.h b/spaghetti-monster/anduril/tint-ramping.h index 9b7f9a8..19b8dde 100644 --- a/spaghetti-monster/anduril/tint-ramping.h +++ b/spaghetti-monster/anduril/tint-ramping.h @@ -1,8 +1,6 @@ -/* - * tint-ramping.h: Tint ramping functions for Anduril. - * Copyright (C) 2017-2023 Selene ToyKeeper - * SPDX-License-Identifier: GPL-3.0-or-later - */ +// tint-ramping.h: Tint ramping functions for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/spaghetti-monster/anduril/version-check-mode.c b/spaghetti-monster/anduril/version-check-mode.c index edb1723..2b7112e 100644 --- a/spaghetti-monster/anduril/version-check-mode.c +++ b/spaghetti-monster/anduril/version-check-mode.c @@ -1,24 +1,8 @@ -/* - * version-check-mode.c: Version check mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// version-check-mode.c: Version check mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef VERSION_CHECK_MODE_C -#define VERSION_CHECK_MODE_C +#pragma once #include "version-check-mode.h" @@ -42,6 +26,3 @@ inline void version_check_iter() { set_state_deferred(off_state, 0); } - -#endif - diff --git a/spaghetti-monster/anduril/version-check-mode.h b/spaghetti-monster/anduril/version-check-mode.h index ce02b73..db2086e 100644 --- a/spaghetti-monster/anduril/version-check-mode.h +++ b/spaghetti-monster/anduril/version-check-mode.h @@ -1,24 +1,8 @@ -/* - * version-check-mode.h: Version check mode for Anduril. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// version-check-mode.h: Version check mode for Anduril. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef VERSION_CHECK_MODE_H -#define VERSION_CHECK_MODE_H +#pragma once #define USE_BLINK_DIGIT // FIXME: does nothing unless defined earlier @@ -33,5 +17,3 @@ const PROGMEM uint8_t version_number[] = VERSION_NUMBER MODEL_NUMBER; uint8_t version_check_state(Event event, uint16_t arg); inline void version_check_iter(); - -#endif diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 9dc8866..5b238aa 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -1,24 +1,8 @@ -/* - * fsm-adc.c: ADC (voltage, temperature) functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef FSM_ADC_C -#define FSM_ADC_C +// fsm-adc.c: ADC (voltage, temperature) functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once // override onboard temperature sensor definition, if relevant #ifdef USE_EXTERNAL_TEMP_SENSOR @@ -557,4 +541,3 @@ void battcheck() { } #endif -#endif diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index 77f625a..16666f9 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -1,25 +1,8 @@ -/* - * fsm-adc.h: ADC (voltage, temperature) functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef FSM_ADC_H -#define FSM_ADC_H +// fsm-adc.h: ADC (voltage, temperature) functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #if defined(USE_LVP) || defined(USE_THERMAL_REGULATION) // use raw value instead of lowpassed value for the next N measurements @@ -120,5 +103,3 @@ inline void ADC_on(); inline void ADC_off(); inline void ADC_start_measurement(); - -#endif diff --git a/spaghetti-monster/fsm-eeprom.c b/spaghetti-monster/fsm-eeprom.c index 4c734a2..66cdd78 100644 --- a/spaghetti-monster/fsm-eeprom.c +++ b/spaghetti-monster/fsm-eeprom.c @@ -1,24 +1,8 @@ -/* - * fsm-eeprom.c: EEPROM API for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef FSM_EEPROM_C -#define FSM_EEPROM_C +// fsm-eeprom.c: EEPROM API for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once #include "fsm-eeprom.h" @@ -126,5 +110,3 @@ void save_eeprom_wl() { } #endif - -#endif diff --git a/spaghetti-monster/fsm-eeprom.h b/spaghetti-monster/fsm-eeprom.h index cda290b..440d2b3 100644 --- a/spaghetti-monster/fsm-eeprom.h +++ b/spaghetti-monster/fsm-eeprom.h @@ -1,24 +1,8 @@ -/* - * fsm-eeprom.h: EEPROM API for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-eeprom.h: EEPROM API for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FSM_EEPROM_H -#define FSM_EEPROM_H +#pragma once #include @@ -66,4 +50,3 @@ void save_eeprom_wl(); // if this marker isn't found, the eeprom is assumed to be blank #define EEP_MARKER 0b10100101 -#endif diff --git a/spaghetti-monster/fsm-events.c b/spaghetti-monster/fsm-events.c index 3279c14..ffa93d1 100644 --- a/spaghetti-monster/fsm-events.c +++ b/spaghetti-monster/fsm-events.c @@ -1,24 +1,8 @@ -/* - * fsm-events.c: Event-handling functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef FSM_EVENTS_C -#define FSM_EVENTS_C +// fsm-events.c: Event-handling functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once #include @@ -212,4 +196,3 @@ uint8_t nice_delay_s() { } */ -#endif diff --git a/spaghetti-monster/fsm-events.h b/spaghetti-monster/fsm-events.h index 79a0aff..10d3317 100644 --- a/spaghetti-monster/fsm-events.h +++ b/spaghetti-monster/fsm-events.h @@ -1,24 +1,8 @@ -/* - * fsm-events.h: Event-handling functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-events.h: Event-handling functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FSM_EVENTS_H -#define FSM_EVENTS_H +#pragma once #include @@ -230,5 +214,3 @@ void delay_4ms(uint8_t ms); #define EV_click15_hold (B_CLICK|B_HOLD|B_PRESS|15) #define EV_click15_hold_release (B_CLICK|B_HOLD|B_RELEASE|B_TIMEOUT|15) - -#endif diff --git a/spaghetti-monster/fsm-main.c b/spaghetti-monster/fsm-main.c index fca1e83..4116d3f 100644 --- a/spaghetti-monster/fsm-main.c +++ b/spaghetti-monster/fsm-main.c @@ -1,24 +1,8 @@ -/* - * fsm-main.c: main() function for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef FSM_MAIN_C -#define FSM_MAIN_C +// fsm-main.c: main() function for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once #include "fsm-main.h" @@ -221,4 +205,3 @@ void handle_deferred_interrupts() { } } -#endif diff --git a/spaghetti-monster/fsm-main.h b/spaghetti-monster/fsm-main.h index 55ae2ff..2e2a111 100644 --- a/spaghetti-monster/fsm-main.h +++ b/spaghetti-monster/fsm-main.h @@ -1,27 +1,10 @@ -/* - * fsm-main.h: main() function for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-main.h: main() function for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FSM_MAIN_H -#define FSM_MAIN_H +#pragma once int main(); // needs to run frequently to execute the logic for WDT and ADC and stuff void handle_deferred_interrupts(); -#endif diff --git a/spaghetti-monster/fsm-misc.c b/spaghetti-monster/fsm-misc.c index 9a10a9c..626ad43 100644 --- a/spaghetti-monster/fsm-misc.c +++ b/spaghetti-monster/fsm-misc.c @@ -1,25 +1,8 @@ -/* - * fsm-misc.c: Miscellaneous function for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef FSM_MISC_C -#define FSM_MISC_C +// fsm-misc.c: Miscellaneous function for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #ifdef USE_DYNAMIC_UNDERCLOCKING void auto_clock_speed() { @@ -302,4 +285,3 @@ void reboot() { } #endif -#endif diff --git a/spaghetti-monster/fsm-misc.h b/spaghetti-monster/fsm-misc.h index 17ed66f..68929c2 100644 --- a/spaghetti-monster/fsm-misc.h +++ b/spaghetti-monster/fsm-misc.h @@ -1,24 +1,8 @@ -/* - * fsm-misc.h: Miscellaneous function for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-misc.h: Miscellaneous function for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FSM_MISC_H -#define FSM_MISC_H +#pragma once #ifdef USE_DYNAMIC_UNDERCLOCKING void auto_clock_speed(); @@ -72,4 +56,3 @@ uint8_t triangle_wave(uint8_t phase); void reboot(); #endif -#endif diff --git a/spaghetti-monster/fsm-pcint.c b/spaghetti-monster/fsm-pcint.c index 4ada5b8..131d0c3 100644 --- a/spaghetti-monster/fsm-pcint.c +++ b/spaghetti-monster/fsm-pcint.c @@ -1,24 +1,8 @@ -/* - * fsm-pcint.c: PCINT (Pin Change Interrupt) functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-pcint.c: PCINT (Pin Change Interrupt) functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FSM_PCINT_C -#define FSM_PCINT_C +#pragma once #include #include @@ -110,5 +94,3 @@ void PCINT_inner(uint8_t pressed) { ticks_since_last_event = 0; } - -#endif diff --git a/spaghetti-monster/fsm-pcint.h b/spaghetti-monster/fsm-pcint.h index a7f3733..cd7ba02 100644 --- a/spaghetti-monster/fsm-pcint.h +++ b/spaghetti-monster/fsm-pcint.h @@ -1,24 +1,8 @@ -/* - * fsm-pcint.h: PCINT (Pin Change Interrupt) functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-pcint.h: PCINT (Pin Change Interrupt) functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FSM_PCINT_H -#define FSM_PCINT_H +#pragma once volatile uint8_t irq_pcint = 0; // pin change interrupt happened? //static volatile uint8_t button_was_pressed; @@ -29,4 +13,3 @@ inline void PCINT_on(); inline void PCINT_off(); void PCINT_inner(uint8_t pressed); -#endif diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c index 14b0db8..280e4b3 100644 --- a/spaghetti-monster/fsm-ramping.c +++ b/spaghetti-monster/fsm-ramping.c @@ -1,10 +1,6 @@ -/* - * fsm-ramping.c: Ramping functions for SpaghettiMonster. - * Handles 1- to 4-channel smooth ramping on a single LED. - * - * Copyright (C) 2017-2023 Selene ToyKeeper - * SPDX-License-Identifier: GPL-3.0-or-later - */ +// fsm-ramping.c: Ramping functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once @@ -557,3 +553,4 @@ GradualTickFuncPtr gradual_tick_modes[NUM_CHANNEL_MODES] = { GRADUAL_TICK_MODES #endif // ifdef USE_RAMPING + diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 5ffd8d9..4511508 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -1,22 +1,6 @@ -/* - * fsm-ramping.h: Ramping functions for SpaghettiMonster. - * Handles 1- to 4-channel smooth ramping on a single LED. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-ramping.h: Ramping functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later #pragma once diff --git a/spaghetti-monster/fsm-random.c b/spaghetti-monster/fsm-random.c index 1f83bce..91fd929 100644 --- a/spaghetti-monster/fsm-random.c +++ b/spaghetti-monster/fsm-random.c @@ -1,24 +1,8 @@ -/* - * fsm-random.c: Random number generator for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-random.c: Random number generator for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FSM_RANDOM_C -#define FSM_RANDOM_C +#pragma once #ifdef USE_PSEUDO_RAND uint8_t pseudo_rand() { @@ -30,4 +14,3 @@ uint8_t pseudo_rand() { } #endif -#endif diff --git a/spaghetti-monster/fsm-random.h b/spaghetti-monster/fsm-random.h index 720f6f2..49aa0cf 100644 --- a/spaghetti-monster/fsm-random.h +++ b/spaghetti-monster/fsm-random.h @@ -1,24 +1,8 @@ -/* - * fsm-random.h: Random number generator for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-random.h: Random number generator for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FSM_RANDOM_H -#define FSM_RANDOM_H +#pragma once #ifdef USE_PSEUDO_RAND uint8_t pseudo_rand(); @@ -26,4 +10,3 @@ uint8_t pseudo_rand(); volatile uint8_t pseudo_rand_seed = 0; #endif -#endif diff --git a/spaghetti-monster/fsm-standby.c b/spaghetti-monster/fsm-standby.c index 0ae6a2f..50e6e30 100644 --- a/spaghetti-monster/fsm-standby.c +++ b/spaghetti-monster/fsm-standby.c @@ -1,24 +1,8 @@ -/* - * fsm-standby.c: standby mode functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef FSM_STANDBY_C -#define FSM_STANDBY_C +// fsm-standby.c: standby mode functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once #include #include @@ -114,4 +98,3 @@ void idle_mode() } #endif -#endif diff --git a/spaghetti-monster/fsm-standby.h b/spaghetti-monster/fsm-standby.h index cd01e72..957e2e1 100644 --- a/spaghetti-monster/fsm-standby.h +++ b/spaghetti-monster/fsm-standby.h @@ -1,24 +1,8 @@ -/* - * fsm-standby.h: standby mode functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-standby.h: standby mode functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FSM_STANDBY_H -#define FSM_STANDBY_H +#pragma once // deferred "off" so we won't suspend in a weird state // (like... during the middle of a strobe pulse) @@ -82,4 +66,3 @@ void sleep_until_eswitch_pressed(); void idle_mode(); #endif -#endif diff --git a/spaghetti-monster/fsm-states.c b/spaghetti-monster/fsm-states.c index e368277..4b94ce9 100644 --- a/spaghetti-monster/fsm-states.c +++ b/spaghetti-monster/fsm-states.c @@ -1,24 +1,8 @@ -/* - * fsm-states.c: State-handling functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-states.c: State-handling functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FSM_STATES_C -#define FSM_STATES_C +#pragma once #include "fsm-states.h" #include "fsm-adc.h" @@ -119,4 +103,3 @@ uint8_t default_state(Event event, uint16_t arg) { } #endif -#endif diff --git a/spaghetti-monster/fsm-states.h b/spaghetti-monster/fsm-states.h index 2c51d0a..156e6cf 100644 --- a/spaghetti-monster/fsm-states.h +++ b/spaghetti-monster/fsm-states.h @@ -1,24 +1,8 @@ -/* - * fsm-states.h: State-handling functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef FSM_STATES_H -#define FSM_STATES_H +// fsm-states.h: State-handling functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once #include "fsm-adc.h" @@ -51,4 +35,3 @@ void set_state_deferred(StatePtr new_state, uint16_t arg); uint8_t default_state(Event event, uint16_t arg); #endif -#endif diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c index ea2efac..847c7fd 100644 --- a/spaghetti-monster/fsm-wdt.c +++ b/spaghetti-monster/fsm-wdt.c @@ -1,24 +1,8 @@ -/* - * fsm-wdt.c: WDT (Watch Dog Timer) functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ - -#ifndef FSM_WDT_C -#define FSM_WDT_C +// fsm-wdt.c: WDT (Watch Dog Timer) functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once #include #include @@ -208,4 +192,3 @@ void WDT_inner() { #endif } -#endif diff --git a/spaghetti-monster/fsm-wdt.h b/spaghetti-monster/fsm-wdt.h index d127551..abf34c5 100644 --- a/spaghetti-monster/fsm-wdt.h +++ b/spaghetti-monster/fsm-wdt.h @@ -1,24 +1,8 @@ -/* - * fsm-wdt.h: WDT (Watch Dog Timer) functions for SpaghettiMonster. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - */ +// fsm-wdt.h: WDT (Watch Dog Timer) functions for SpaghettiMonster. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later -#ifndef FSM_WDT_H -#define FSM_WDT_H +#pragma once #define TICKS_PER_SECOND 62 @@ -34,4 +18,3 @@ volatile uint8_t irq_wdt = 0; // WDT interrupt happened? #endif #endif -#endif diff --git a/spaghetti-monster/spaghetti-monster.h b/spaghetti-monster/spaghetti-monster.h index 853eac3..a6916e3 100644 --- a/spaghetti-monster/spaghetti-monster.h +++ b/spaghetti-monster/spaghetti-monster.h @@ -1,3 +1,9 @@ +// spaghetti-monster.h: UI toolkit / microkernel for e-switch flashlights. +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + /* * SpaghettiMonster: Generic foundation code for e-switch flashlights. * Other possible names: @@ -5,21 +11,6 @@ * - RoundTable * - Mostly Harmless * - ... - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . */ #include "tk-attiny.h" @@ -79,3 +70,4 @@ void loop(); #endif #include "fsm-misc.c" #include "fsm-main.c" + diff --git a/tk-attiny.h b/tk-attiny.h index 110507b..ad2ed3b 100644 --- a/tk-attiny.h +++ b/tk-attiny.h @@ -1,25 +1,9 @@ -#ifndef TK_ATTINY_H -#define TK_ATTINY_H -/* - * Attiny portability header. - * This helps abstract away the differences between various attiny MCUs. - * - * Copyright (C) 2017 Selene ToyKeeper - * - * 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 3 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 . - * - */ +// tk-attiny.h: Attiny portability header. +// Copyright (C) 2014-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// This helps abstract away the differences between various attiny MCUs. // Choose your MCU here, or in the main .c file, or in the build script //#define ATTINY 13 @@ -171,4 +155,3 @@ #error Unable to define MCU macros. #endif -#endif // TK_ATTINY_H diff --git a/tk-calibration.h b/tk-calibration.h index c2ab801..f0b05ab 100644 --- a/tk-calibration.h +++ b/tk-calibration.h @@ -1,25 +1,9 @@ -#ifndef TK_CALIBRATION_H -#define TK_CALIBRATION_H -/* - * Attiny calibration header. - * This allows using a single set of hardcoded values across multiple projects. - * - * Copyright (C) 2015 Selene ToyKeeper - * - * 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 3 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 . - * - */ +// tk-calibration.h: Attiny calibration header. +// Copyright (C) 2015-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// This allows using a single set of hardcoded values across multiple projects. /********************** Voltage ADC calibration **************************/ // These values were measured using RMM's FET+7135. @@ -78,5 +62,3 @@ #define CAP_SHORT 115 #endif - -#endif // TK_CALIBRATION_H diff --git a/tk-delay.h b/tk-delay.h index 29cf463..502e6ab 100644 --- a/tk-delay.h +++ b/tk-delay.h @@ -1,24 +1,7 @@ -#ifndef TK_DELAY_H -#define TK_DELAY_H -/* - * Smaller, more flexible replacement(s) for default _delay_ms() functions. - * - * Copyright (C) 2015 Selene ToyKeeper - * - * 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 3 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 . - * - */ +// tk-delay.h: Smaller, more flexible _delay_ms() functions. +// Copyright (C) 2015-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #ifdef OWN_DELAY #include "tk-attiny.h" @@ -73,5 +56,3 @@ void _delay_s() // because it saves a bit of ROM space to do it this way #include #endif - -#endif // TK_DELAY_H diff --git a/tk-random.h b/tk-random.h index b2ff296..ad65660 100644 --- a/tk-random.h +++ b/tk-random.h @@ -1,24 +1,7 @@ -#ifndef TK_RANDOM_H -#define TK_RANDOM_H -/* - * Smaller, pseudo-random function(s). - * - * Copyright (C) 2015 Selene ToyKeeper - * - * 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 3 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 . - * - */ +// tk-random.h: Smaller pseudo-random function(s). +// Copyright (C) 2015-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once uint8_t pgm_rand() { static uint16_t offset = 255; @@ -29,4 +12,3 @@ uint8_t pgm_rand() { return pgm_read_byte(offset); } -#endif // TK_RANDOM_H diff --git a/tk-voltage.h b/tk-voltage.h index 90a176d..36ce9c8 100644 --- a/tk-voltage.h +++ b/tk-voltage.h @@ -1,24 +1,7 @@ -#ifndef TK_VOLTAGE_H -#define TK_VOLTAGE_H -/* - * Voltage / battcheck functions. - * - * Copyright (C) 2015 Selene ToyKeeper - * - * 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 3 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 . - * - */ +// tk-voltage.h: Voltage / battcheck functions. +// Copyright (C) 2015-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once #include "tk-attiny.h" #include "tk-calibration.h" @@ -193,5 +176,3 @@ inline uint8_t battcheck() { #endif // BATTCHECK_VpT #endif - -#endif // TK_VOLTAGE_H diff --git a/tk.h b/tk.h index b61db08..d618134 100644 --- a/tk.h +++ b/tk.h @@ -1,5 +1,7 @@ -#ifndef TK_H -#define TK_H +// tk.h : misc handy stuff +// Copyright (C) 2015-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once ///// // tk.h @@ -14,4 +16,3 @@ // use it like this: //#include incfile(CONFIGFILE) -#endif -- cgit v1.2.3 From 0bfe6da19da6ea9aeb25e69a6e134825dedd0d79 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 17 Apr 2023 00:57:13 -0600 Subject: LT1S Pro: raised the ramp a bit; it seemed too low in the middle --- spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index 993619a..874d8a8 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -44,9 +44,16 @@ // (also, red LEDs use a QX7138 chip which has max PWM speed of 10 kHz, // and it behaves erratically at full speed, // so PWM here is 576 clock cycles long to keep the speed low enough) +// +// This first ramp seems a bit too low: 0.2 / 1.9 / 10 / 37 / 109 / 272 / 600 lm // level_calc.py 5.99 1 150 7135 1 0.2 600 --pwm dyn:77:16383:575:3 -#define PWM_LEVELS 1,1,2,2,3,4,4,5,6,6,7,8,9,9,10,11,11,12,13,13,14,15,15,16,16,17,18,18,19,19,19,20,20,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,24,24,24,25,26,26,27,28,29,30,32,33,34,36,38,40,42,44,46,48,50,52,55,57,59,62,65,68,70,73,77,80,83,86,90,94,97,101,105,110,114,118,123,128,133,138,143,148,154,160,166,172,178,185,191,198,205,213,220,228,236,244,252,261,270,279,289,298,308,319,329,340,351,363,374,386,399,411,424,438,452,466,480,495,510,526,542,558,575 -#define PWM_TOPS 16383,10869,13246,8043,11458,12772,10093,11043,11450,9664,9991,10091,10048,8868,8838,8730,7814,7724,7589,6864,6748,6604,6024,5899,5398,5287,5159,4754,4638,4287,3963,3876,3594,3511,3265,3038,2829,2770,2586,2417,2260,2115,1981,1857,1742,1636,1537,1445,1360,1281,1207,1138,1073,1013,957,904,855,848,803,760,720,714,677,643,637,630,599,592,585,577,569,579,570,560,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575 +//#define PWM_LEVELS 1,1,2,2,3,4,4,5,6,6,7,8,9,9,10,11,11,12,13,13,14,15,15,16,16,17,18,18,19,19,19,20,20,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,24,24,24,25,26,26,27,28,29,30,32,33,34,36,38,40,42,44,46,48,50,52,55,57,59,62,65,68,70,73,77,80,83,86,90,94,97,101,105,110,114,118,123,128,133,138,143,148,154,160,166,172,178,185,191,198,205,213,220,228,236,244,252,261,270,279,289,298,308,319,329,340,351,363,374,386,399,411,424,438,452,466,480,495,510,526,542,558,575 +//#define PWM_TOPS 16383,10869,13246,8043,11458,12772,10093,11043,11450,9664,9991,10091,10048,8868,8838,8730,7814,7724,7589,6864,6748,6604,6024,5899,5398,5287,5159,4754,4638,4287,3963,3876,3594,3511,3265,3038,2829,2770,2586,2417,2260,2115,1981,1857,1742,1636,1537,1445,1360,1281,1207,1138,1073,1013,957,904,855,848,803,760,720,714,677,643,637,630,599,592,585,577,569,579,570,560,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575 +// +// This ramp is a bit higher: 0.2 / 3 / 19 / 61 / 152 / 320 / 600 lm +// level_calc.py 4.001 1 150 7135 1 0.2 600 --pwm dyn:78:16383:575:3.333 +#define PWM_LEVELS 1,1,2,4,5,6,7,8,9,10,12,13,14,15,17,18,19,21,22,23,24,25,26,27,28,29,30,31,32,33,33,34,34,35,35,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,37,37,38,38,39,40,40,41,43,44,45,47,48,50,52,54,56,59,62,64,67,69,72,75,78,81,84,87,90,94,97,101,104,108,112,116,120,124,128,133,137,142,147,151,156,161,167,172,177,183,189,194,200,206,213,219,226,232,239,246,253,260,268,275,283,291,299,307,316,324,333,342,351,361,370,380,390,400,410,420,431,442,453,464,476,487,499,511,523,536,549,562,575 +#define PWM_TOPS 16383,8174,7823,14429,13603,12806,12046,11328,10652,10017,10402,9742,9134,8575,8615,8089,7605,7536,7093,6684,6307,5959,5636,5337,5060,4802,4562,4337,4127,3929,3633,3468,3216,3077,2862,2744,2559,2390,2234,2091,1960,1838,1727,1623,1528,1439,1357,1280,1209,1143,1081,1024,970,919,872,828,787,770,732,716,682,668,654,624,611,613,600,587,587,574,573,571,569,566,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575 // shared table for white and red #define PWM1_LEVELS PWM_LEVELS #define MAX_1x7135 75 -- cgit v1.2.3 From 561a85c175920074fafea33738d24f54317e2f3a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 17 Apr 2023 01:30:41 -0600 Subject: made "Ramp 3H" do momentary turbo if current channel mode has no args --- hwdef-Sofirn_LT1S-Pro.h | 8 +++++--- spaghetti-monster/anduril/ramp-mode.c | 27 +++++++++++++++++++++++---- spaghetti-monster/anduril/ramp-mode.h | 10 ---------- spaghetti-monster/fsm-ramping.h | 8 ++++++-- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/hwdef-Sofirn_LT1S-Pro.h b/hwdef-Sofirn_LT1S-Pro.h index 4ee466b..d59e7bc 100644 --- a/hwdef-Sofirn_LT1S-Pro.h +++ b/hwdef-Sofirn_LT1S-Pro.h @@ -25,19 +25,21 @@ // * 3. red + white blend #define NUM_CHANNEL_MODES 4 //#define CHANNEL_MODES_ENABLED 1,1,1,1 -#define CHANNEL_MODES_ENABLED 0b00001111 #define CM_WHITE 0 #define CM_AUTO 1 #define CM_RED 2 #define CM_WHITE_RED 3 +#define CHANNEL_MODES_ENABLED 0b00001111 +#define CHANNEL_HAS_ARGS 0b00001001 +// 128=middle CCT, N/A, N/A, 255=100% red +#define CHANNEL_MODE_ARGS 128,0,0,255 + // TODO: blend mode should enable this automatically? #define USE_CHANNEL_MODES // TODO: blend mode should enable this automatically? #define USE_CHANNEL_MODE_ARGS // TODO: or maybe if args are defined, the USE_ should be auto-set? -// 128=middle CCT, N/A, N/A, 255=100% red -#define CHANNEL_MODE_ARGS 128,0,0,255 #define SET_LEVEL_MODES set_level_white_blend, \ set_level_auto_3ch_blend, \ set_level_red, \ diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index 88b141e..5a960c9 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -408,9 +408,18 @@ uint8_t steady_state(Event event, uint16_t arg) { #endif // 3H: momentary turbo (on lights with no tint ramping) - // (or 4H on lights with tint ramping) - // FIXME: handle 3H if channel mode has no args - else if (event == EV_MOMENTARY_TURBO) { + // (or 4H when tint ramping is available) + else if ((event == EV_click3_hold) + #ifdef USE_CHANNEL_MODE_ARGS + || (event == EV_click4_hold) + #endif + ) { + #ifdef USE_CHANNEL_MODE_ARGS + // ramp tint if tint exists in this mode + if ((event == EV_click3_hold) + && (channel_has_args(cfg.channel_mode))) + return EVENT_NOT_HANDLED; + #endif if (! arg) { // first frame only, to allow thermal regulation to work #ifdef USE_2C_STYLE_CONFIG uint8_t tl = style_2c ? MAX_LEVEL : turbo_level; @@ -421,7 +430,17 @@ uint8_t steady_state(Event event, uint16_t arg) { } return MISCHIEF_MANAGED; } - else if (event == EV_MOMENTARY_TURBO_RELEASE) { + else if ((event == EV_click3_hold_release) + #ifdef USE_CHANNEL_MODE_ARGS + || (event == EV_click4_hold_release) + #endif + ) { + #ifdef USE_CHANNEL_MODE_ARGS + // ramp tint if tint exists in this mode + if ((event == EV_click3_hold_release) + && (channel_has_args(cfg.channel_mode))) + return EVENT_NOT_HANDLED; + #endif set_level_and_therm_target(memorized_level); return MISCHIEF_MANAGED; } diff --git a/spaghetti-monster/anduril/ramp-mode.h b/spaghetti-monster/anduril/ramp-mode.h index c50e36a..e4ded1e 100644 --- a/spaghetti-monster/anduril/ramp-mode.h +++ b/spaghetti-monster/anduril/ramp-mode.h @@ -57,16 +57,6 @@ #endif -// move a couple actions depending on whether there are channel modes -#ifdef USE_CHANNEL_MODE_ARGS - #define EV_MOMENTARY_TURBO EV_click4_hold - #define EV_MOMENTARY_TURBO_RELEASE EV_click4_hold_release -#else - #define EV_MOMENTARY_TURBO EV_click3_hold - #define EV_MOMENTARY_TURBO_RELEASE EV_click3_hold_release -#endif - - // default ramp options if not overridden earlier per-driver #ifndef RAMP_STYLE #define RAMP_STYLE 0 // smooth default diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 4511508..a9e333e 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -41,6 +41,7 @@ GradualTickFuncPtr gradual_tick_modes[NUM_CHANNEL_MODES]; #ifdef USE_CUSTOM_CHANNEL_3H_MODES // different 3H behavior per channel? // TODO: move to progmem +// TODO: move to Anduril, not FSM StatePtr channel_3H_modes[NUM_CHANNEL_MODES]; #endif @@ -60,11 +61,14 @@ StatePtr channel_3H_modes[NUM_CHANNEL_MODES]; #endif #endif -#ifndef USE_CFG - #ifdef USE_CHANNEL_MODE_ARGS +#ifdef USE_CHANNEL_MODE_ARGS + #ifndef USE_CFG // one byte of extra data per channel mode, like for tint value uint8_t channel_mode_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; #endif + // bitmask: which modes respond to their "arg", and which don't? + //const uint8_t channel_has_args = CHANNEL_HAS_ARGS; + #define channel_has_args(n) ((CHANNEL_HAS_ARGS >> n) & 1) #endif void set_channel_mode(uint8_t mode); -- cgit v1.2.3 From d64358060b99ebb5b6703a89034d885f1e3f1122 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 19 Apr 2023 00:48:20 -0600 Subject: LT1S Pro: added white-only auto-tint mode, at gchart's request --- hwdef-Sofirn_LT1S-Pro.c | 58 ++++++++++++++++++++++++- hwdef-Sofirn_LT1S-Pro.h | 29 ++++++++----- spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 14 +++--- 3 files changed, 81 insertions(+), 20 deletions(-) diff --git a/hwdef-Sofirn_LT1S-Pro.c b/hwdef-Sofirn_LT1S-Pro.c index 8e2163f..dd93f93 100644 --- a/hwdef-Sofirn_LT1S-Pro.c +++ b/hwdef-Sofirn_LT1S-Pro.c @@ -64,8 +64,33 @@ void set_level_white_blend(uint8_t level) { PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); - PWM_DATATYPE top = PWM_GET(pwm_tops, level); - uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + PWM_DATATYPE top = PWM_GET(pwm_tops, level); + uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + + WARM_PWM_LVL = warm_PWM; + COOL_PWM_LVL = cool_PWM; + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; // reset phase +} + + +// same as white blend, but tint is calculated from the ramp level +void set_level_auto_2ch_blend(uint8_t level) { + if (level == 0) { + WARM_PWM_LVL = 0; + COOL_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + return; + } + + level --; // PWM array index = level - 1 + + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + PWM_DATATYPE top = PWM_GET(pwm_tops, level); + uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); @@ -170,6 +195,35 @@ void gradual_tick_white_blend() { } +// same as white blend, but tint is calculated from the ramp level +void gradual_tick_auto_2ch_blend() { + uint8_t gt = gradual_target; + if (gt < actual_level) gt = actual_level - 1; + else if (gt > actual_level) gt = actual_level + 1; + gt --; + + // figure out what exact PWM levels we're aiming for + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE top = PWM_GET(pwm_tops, gt); + uint8_t blend = 255 * (uint16_t)gt / RAMP_SIZE; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + + // move up/down if necessary + GRADUAL_ADJUST_SIMPLE(warm_PWM, WARM_PWM_LVL); + GRADUAL_ADJUST_SIMPLE(cool_PWM, COOL_PWM_LVL); + + // check for completion + if ( (WARM_PWM_LVL == warm_PWM) + && (COOL_PWM_LVL == cool_PWM) + ) + { + GRADUAL_IS_ACTUAL(); + } +} + + void gradual_tick_auto_3ch_blend() { uint8_t gt = gradual_target; if (gt < actual_level) gt = actual_level - 1; diff --git a/hwdef-Sofirn_LT1S-Pro.h b/hwdef-Sofirn_LT1S-Pro.h index d59e7bc..af0e6f0 100644 --- a/hwdef-Sofirn_LT1S-Pro.h +++ b/hwdef-Sofirn_LT1S-Pro.h @@ -20,20 +20,21 @@ // channel modes: // * 0. warm/cool white blend -// * 1. auto 3ch blend (red -> warm -> cool by ramp level) -// * 2. red only -// * 3. red + white blend -#define NUM_CHANNEL_MODES 4 -//#define CHANNEL_MODES_ENABLED 1,1,1,1 +// * 1. auto 2ch white blend (warm -> cool by ramp level) +// * 2. auto 3ch blend (red -> warm -> cool by ramp level) +// * 3. red only +// * 4. red + white blend +#define NUM_CHANNEL_MODES 5 #define CM_WHITE 0 -#define CM_AUTO 1 -#define CM_RED 2 -#define CM_WHITE_RED 3 +#define CM_AUTO2 1 +#define CM_AUTO3 2 +#define CM_RED 3 +#define CM_WHITE_RED 4 -#define CHANNEL_MODES_ENABLED 0b00001111 -#define CHANNEL_HAS_ARGS 0b00001001 -// 128=middle CCT, N/A, N/A, 255=100% red -#define CHANNEL_MODE_ARGS 128,0,0,255 +#define CHANNEL_MODES_ENABLED 0b00011111 +#define CHANNEL_HAS_ARGS 0b00010001 +// 128=middle CCT, _, _, _, 255=100% red +#define CHANNEL_MODE_ARGS 128,0,0,0,255 // TODO: blend mode should enable this automatically? #define USE_CHANNEL_MODES @@ -41,11 +42,13 @@ #define USE_CHANNEL_MODE_ARGS // TODO: or maybe if args are defined, the USE_ should be auto-set? #define SET_LEVEL_MODES set_level_white_blend, \ + set_level_auto_2ch_blend, \ set_level_auto_3ch_blend, \ set_level_red, \ set_level_red_white_blend // gradual ticking for thermal regulation #define GRADUAL_TICK_MODES gradual_tick_white_blend, \ + gradual_tick_auto_2ch_blend, \ gradual_tick_auto_3ch_blend, \ gradual_tick_red, \ gradual_tick_red_white_blend @@ -108,11 +111,13 @@ // custom channel modes void set_level_red(uint8_t level); void set_level_white_blend(uint8_t level); +void set_level_auto_2ch_blend(uint8_t level); void set_level_auto_3ch_blend(uint8_t level); void set_level_red_white_blend(uint8_t level); void gradual_tick_red(); void gradual_tick_white_blend(); +void gradual_tick_auto_2ch_blend(); void gradual_tick_auto_3ch_blend(); void gradual_tick_red_white_blend(); diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index 874d8a8..76ddbba 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -20,8 +20,8 @@ #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) // channel modes... -// CM_WHITE, CM_AUTO, CM_RED, CM_WHITE_RED -#define DEFAULT_CHANNEL_MODE CM_AUTO +// CM_WHITE, CM_AUTO2, CM_AUTO3, CM_RED, CM_WHITE_RED +#define DEFAULT_CHANNEL_MODE CM_AUTO3 #define FACTORY_RESET_WARN_CHANNEL CM_RED #define FACTORY_RESET_SUCCESS_CHANNEL CM_WHITE @@ -38,7 +38,6 @@ #define TINT_RAMPING_CORRECTION 0 #define RAMP_SIZE 150 -// TODO? 200% power at top of ramp on white blend mode // use dynamic PWM instead of plain 8-bit // (so we can get lower lows and a smoother ramp) // (also, red LEDs use a QX7138 chip which has max PWM speed of 10 kHz, @@ -52,10 +51,13 @@ // // This ramp is a bit higher: 0.2 / 3 / 19 / 61 / 152 / 320 / 600 lm // level_calc.py 4.001 1 150 7135 1 0.2 600 --pwm dyn:78:16383:575:3.333 -#define PWM_LEVELS 1,1,2,4,5,6,7,8,9,10,12,13,14,15,17,18,19,21,22,23,24,25,26,27,28,29,30,31,32,33,33,34,34,35,35,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,37,37,38,38,39,40,40,41,43,44,45,47,48,50,52,54,56,59,62,64,67,69,72,75,78,81,84,87,90,94,97,101,104,108,112,116,120,124,128,133,137,142,147,151,156,161,167,172,177,183,189,194,200,206,213,219,226,232,239,246,253,260,268,275,283,291,299,307,316,324,333,342,351,361,370,380,390,400,410,420,431,442,453,464,476,487,499,511,523,536,549,562,575 +#define PWM1_LEVELS 1,1,2,4,5,6,7,8,9,10,12,13,14,15,17,18,19,21,22,23,24,25,26,27,28,29,30,31,32,33,33,34,34,35,35,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,37,37,38,38,39,40,40,41,43,44,45,47,48,50,52,54,56,59,62,64,67,69,72,75,78,81,84,87,90,94,97,101,104,108,112,116,120,124,128,133,137,142,147,151,156,161,167,172,177,183,189,194,200,206,213,219,226,232,239,246,253,260,268,275,283,291,299,307,316,324,333,342,351,361,370,380,390,400,410,420,431,442,453,464,476,487,499,511,523,536,549,562,575 #define PWM_TOPS 16383,8174,7823,14429,13603,12806,12046,11328,10652,10017,10402,9742,9134,8575,8615,8089,7605,7536,7093,6684,6307,5959,5636,5337,5060,4802,4562,4337,4127,3929,3633,3468,3216,3077,2862,2744,2559,2390,2234,2091,1960,1838,1727,1623,1528,1439,1357,1280,1209,1143,1081,1024,970,919,872,828,787,770,732,716,682,668,654,624,611,613,600,587,587,574,573,571,569,566,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575,575 -// shared table for white and red -#define PWM1_LEVELS PWM_LEVELS +// TODO? 200% power at top of ramp on white blend mode +// 2nd table handles "200% power" turbo +//#define PWM2_LEVELS ... +// tops for PWM2 +//#define PWM3_LEVELS ... #define MAX_1x7135 75 #define MIN_THERM_STEPDOWN 75 // should be above highest dyn_pwm level #define HALFSPEED_LEVEL 12 -- cgit v1.2.3 From 8f05a56ec6a11f7513557af35e3977b4ca42f38d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 19 Apr 2023 02:21:19 -0600 Subject: added stepped tint ramping patch adapted from SammysHP: https://github.com/SammysHP/flashlight-firmware/commit/0df174a6f6cc2676703f55a9b86eb3d9b3896b33 --- spaghetti-monster/anduril/anduril-manual.txt | 195 ++++++++++++++++++----- spaghetti-monster/anduril/channel-modes.c | 55 ++++++- spaghetti-monster/anduril/channel-modes.h | 6 + spaghetti-monster/anduril/config-default.h | 4 + spaghetti-monster/anduril/load-save-config-fsm.h | 3 + spaghetti-monster/anduril/load-save-config.h | 3 + spaghetti-monster/anduril/ramp-mode-fsm.h | 3 +- spaghetti-monster/anduril/ramp-mode.c | 8 +- spaghetti-monster/anduril/ramp-mode.h | 2 +- 9 files changed, 227 insertions(+), 52 deletions(-) diff --git a/spaghetti-monster/anduril/anduril-manual.txt b/spaghetti-monster/anduril/anduril-manual.txt index 1873b8d..fc61948 100644 --- a/spaghetti-monster/anduril/anduril-manual.txt +++ b/spaghetti-monster/anduril/anduril-manual.txt @@ -279,8 +279,9 @@ more than 2 times when the light is off: - 3H: Strobe modes, starting with the most recently used strobe. - 4C: Lockout mode. - 5C: Momentary mode. + - 6C: Tactical mode. - 7C / 7H: Aux LED configuration. - - 9H: Misc configuration menu. (only on some lights) + - 9H: Misc Config menu. (only on some lights) - 10H: Simple UI configuration menu. - 13H: Factory reset (on some lights). - 15C or more: Version check. @@ -485,6 +486,11 @@ In more detail, here is what each mode does: Be careful about heat in this mode, if using it for a long time. + - Police strobe (on some lights) + + 2-color police style strobe. Only works on lights with 2 or more + colors. + - Lightning storm mode Flashes at random brightness and random speed to simulate lightning @@ -519,6 +525,46 @@ To exit this mode, physically disconnect power by unscrewing the tailcap or battery tube. +Tactical Mode +-------------- + +Click 6 times from Off to enter Tactical Mode, or 6 times in Tactical +Mode to exit and go back to "Off". + +Tactical Mode provides instant momentary access to high, low, and +strobe, but each of these is configurable. The inputs are: + + - 1H: High + - 2H: Low + - 3H: Strobe + +Each of these only lasts as long as you hold the button. + +Other commands in Tactical Mode are: + + - 6C: exit (go back to Off Mode) + - 7H: Tactical Mode config menu + - 1st blink: configure tactical slot 1 + - 2nd blink: configure tactical slot 2 + - 3rd blink: configure tactical slot 3 + +To change what is in a tactical slot, press 7H, then release the button +after the 1st, 2nd, or 3rd blink. Then enter a number. Each click adds +1, and each hold adds 10. The number can be: + + - 1 to 150: set the brightness level + - 0: last-used strobe mode + - 151+: go directly to a specific strobe mode + 151 = party strobe + 152 = tactical strobe + 153+ = other strobes, in the same order they're in in the "Off -> 3H" + strobe group + +This assumes the light has a ramp 150 levels long. Strobe modes start +at the ramp size plus 1, so it may be different if a light has a +different ramp size. + + Configuration Menus ------------------- @@ -693,14 +739,18 @@ Misc Config Menu ---------------- Some models may have an extra config menu for settings which don't fit -anywhere else. These settings are, in order: +anywhere else. This menu is located at "Off -> 9H" in the advanced UI. - - Tint ramp style: +These settings are, in order: - 0 = smooth (blend channels in any proportion) - 1 = toggle (only one channel active at a time) + - Tint ramp style: (on some lights) - - Jump Start level: + 0 : smooth ramp (blend channels in any proportion) + 1 : middle tint only + 2 : extreme tints only (only one channel active at a time) + 3+: stepped ramp with 3+ steps + + - Jump Start level: (on some lights) Some lights are prone to starting up slowly at low levels, so they have an option to "jump start" the engine by pulsing a higher power @@ -710,36 +760,71 @@ anywhere else. These settings are, in order: The value can be from 1 to 150, but is usually between 20 and 50. These settings are hardware-specific and may not be present on all -lights. The number of settings in the global menu depends on the +lights. The number of settings in the Misc Config Menu depends on the hardware model and the firmware version. -Tint Ramping ------------- +Channel Modes (a.k.a. Tint Ramping or Multi Channel controls) +------------------------------------------------------------- Some lights have more than one set of LEDs which can be adjusted to -change the color temperature of the light. On these models, there is a -global button mapping which works at all times unless it's overridden by -the mode the light is in: +change the beam color, shape, or other properties. These lights have +features like tint ramping and channel modes. + +On these models, there are some global button mappings which work at all +times unless they're overridden by the mode the light is in: + + - 3C: Next channel mode + - 3H: Adjust current channel mode (ramp tint, for example) + - 9H: Channel mode config menu - - 3H: Tint ramping +Details depend on the exact type of light used. For example, if a light +has LEDs in cool white, warm white, and red... that light might have a +few channel modes: -So, at almost any time, click 3 times but hold the final press, and it -can change the color of the light. This is best done with the light at -a moderately high level, because it makes the changes smooth. Low -levels have more coarse resolution and will typically change in very -visible steps. + - White blend (adjustable CCT / tint ramping) + - Red only + - Auto-tint -At both ends of the tint ramp, there is an "auto tint" mode. This -automatically chooses a tint based on the brightness level... so it can -be warm white while dim, or cool white while bright. Or vice-versa. To -access this, ramp to the end of the tint range, then keep holding until -the light blinks a second time. +On a light like this, the user could press 3C to rotate through these +different channel modes... white, then red, then auto, then back to +white. + +Additionally, in the "white blend" mode, the user could press 3H to +manually adjust the balance between warm white and cool white. + +Finally, if the user decides they don't want all of the modes, they can +turn some off. Press 9H (while on) to start the channel mode config +menu. To disable the auto-tint mode, for example, it is the 3rd mode... +so wait for the 3rd blink, then release the button. Then at the prompt, +enter a value of 0 (wait for the prompt to time out without clicking +anything). Afterward, the auto tint mode should no longer be in the +channel mode rotation. To turn the mode back on later, do the same +thing, but enter a value of 1 (click 1 time at the prompt). + +A light can have many different channel modes, so don't be shy about +turning off any modes you don't use. It makes all the others easier to +reach. + +If you turn off channel modes until only 1 remains, the "Ramp -> 3C" +action reverts to its single-channel behavior -- switching between a +smooth or stepped brightness ramp. Additionally, when a channel mode +has nothing to adjust with 3H, the 3H action also reverts to its +single-channel behavior -- momentary turbo. + +The Misc Config Menu (Off -> 9H) may also have a setting to choose a +tint ramp style. There are a few styles available, by entering +different numbers into that config menu: + + 0: smooth ramp + 1: middle tint only + 2: extreme tints only + 3+: stepped ramp with 3+ steps + +This setting only applies to modes with channel ramping (i.e. tint +ramping), and only when that mode uses the default 3H event handler. +Custom channel modes may work differently. -The misc config menu also has a setting to choose a tint ramp style. -This can be smooth, allowing the user to smoothly blend both channels in -whatever ratio they desire... or it can be "tint toggle" style, where -only one channel is active at a time. UI Reference Table @@ -758,9 +843,12 @@ Off Any 3C Battcheck mode Off Full 3H Strobe mode (whichever was used last) Off Any 4C Lockout mode Off Full 5C Momentary mode +Off Full 6C Tactical mode Off Full 7C Aux LEDs: Next pattern Off Full 7H Aux LEDs: Next color -Off Full 9H Misc config menu (varies per light) +Off Full 9H Misc Config menu (varies per light): + ?1: tint ramp style + ?2: jump start level Off Full 10C Enable Simple UI Off Simple 10H Disable Simple UI Off Full 10H Simple UI ramp config menu: @@ -776,19 +864,29 @@ Ramp Any 1H Ramp (up, with reversing) Ramp Any 2H Ramp (down) Ramp Any 2C Go to/from ceiling or turbo (configurable) Ramp Full 3C Change ramp style (smooth / stepped) -Ramp Any 3H Tint ramping (on some lights) -Ramp Full 3H Momentary turbo (on lights without tint ramping) +Ramp Full 6C (same as above, but on multi-channel lights) +Ramp Full 3H Momentary turbo (when no tint ramping) +Ramp Full 4H Momentary turbo (on multi channel lights) Ramp Any 4C Lockout mode Ramp Full 5C Momentary mode Ramp Full 5H Sunset timer on, and add 5 minutes -Ramp Full 7H Ramp config menu (1: floor, 2: ceiling, 3: speed/steps) +Ramp Full 7H Ramp config menu: (for current ramp) + 1: floor + 2: ceiling + 3: speed / steps Ramp Full 10C Turn on manual memory and save current brightness Ramp Full 10H Ramp Extras config menu: - 1: enable automatic mem + 1: switch to automatic mem, not manual mem 2: set manual mem timeout 3: ramp after moon or not 4: advanced UI turbo style +Multi-channel lights only: +Any Any 3C Next channel mode (i.e. next color mode) +Any Any 3H Tint ramp (if this mode can) +Any Full 9H Channel mode enable/disable menu: + N: click (or not) to enable (disable) mode N + Lockout Any 1C/1H Momentary moon (lowest floor) Lockout Any 2C/2H Momentary moon (highest floor, or manual mem level) Lockout Any 3C Unlock (go to "Off" mode) @@ -797,27 +895,39 @@ Lockout Any 4H On (ramp mode, floor level) Lockout Any 5C On (ramp mode, ceiling level) Lockout Full 7C Aux LEDs: Next pattern Lockout Full 7H Aux LEDs: Next color -Lockout Full 10H Auto-lock config menu (1: set timeout) +Lockout Full 10H Auto-lock config menu: + 1: set timeout in minutes (0 = no auto-lock) Strobe (any) Full 1C Off Strobe (any) Full 2C Next strobe mode -Strobe (any) Full 3H Tint ramping (on some lights) +Strobe (any) Full 4C Prev strobe mode Strobe (any) Full 5C Momentary mode (using current strobe) -Candle Full 1H/2H Brighter / dimmer -Candle Full 5H Sunset timer on, add 5 minutes Party strobe Full 1H/2H Faster / slower Tactical strobe Full 1H/2H Faster / slower -Biking Full 1H/2H Brighter / dimmer +Police strobe - - None (brightness is Ramp Mode's last-used level) Lightning Full 1H Interrupt current flash or start new one +Candle Full 1H/2H Brighter / dimmer +Candle Full 5H Sunset timer on, add 5 minutes +Biking Full 1H/2H Brighter / dimmer Batt check Any 1C Off Batt check Full 2C Next blinky mode (Temp check, Beacon, SOS) Batt check Full 7H Voltage config menu + 1: voltage correction factor + ... + 5: -0.10V + 6: -0.05V + 7: no correction + 8: +0.05V + 9: +0.10V + ... Temp check Full 1C Off Temp check Full 2C Next blinky mode (Beacon, SOS, Batt check) Temp check Full 7H Thermal config menu + 1: set current temperature + 2: set temperature limit Beacon Full 1C Off Beacon Full 1H Configure beacon timing @@ -829,8 +939,19 @@ SOS Full 2C Next blinky mode (Batt check, Temp check, Beacon) Momentary Full Any On (until button is released) Momentary Full Disconnect power Exit Momentary mode +Tactical Full 1H High (tactical slot 1) +Tactical Full 2H Low (tactical slot 2) +Tactical Full 3H Strobe (tactical slot 3) +Tactical Full 6C Exit (go back to Off Mode) +Tactical Full 7H Tactical Mode config menu: + 1: tactical slot 1 + 2: tactical slot 2 + 3: tactical slot 3 + Config menus Full Hold Skip current item with no changes Config menus Full Release Configure current item + (goes to Number Entry menu) Number entry Full Click Add 1 to value for current item Number entry Full Hold Add 10 to value for current item + diff --git a/spaghetti-monster/anduril/channel-modes.c b/spaghetti-monster/anduril/channel-modes.c index 51f294c..b2985a1 100644 --- a/spaghetti-monster/anduril/channel-modes.c +++ b/spaghetti-monster/anduril/channel-modes.c @@ -70,13 +70,25 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { // ignore event if we weren't the ones who handled the first frame if (! active) return EVENT_NOT_HANDLED; - // change normal tints - if ((tint_ramp_direction > 0) && (tint < 255)) { - tint += 1; - } - else if ((tint_ramp_direction < 0) && (tint > 0)) { - tint -= 1; - } + #ifdef USE_STEPPED_TINT_RAMPING + if ((tint_ramp_direction > 0 && tint < 255) || + (tint_ramp_direction < 0 && tint > 0)) { + // ramp slower in stepped mode + if (cfg.tint_ramp_style && (arg % HOLD_TIMEOUT != 0)) + return EVENT_HANDLED; + + const uint8_t step_size = (cfg.tint_ramp_style < 2) + ? 1 : 254 / (cfg.tint_ramp_style-1); + tint = nearest_tint_value( + tint + ((int16_t)step_size * tint_ramp_direction) + ); + } + #else // smooth tint ramping only + if ((tint_ramp_direction > 0) && (tint < 255)) { tint ++; } + else + if ((tint_ramp_direction < 0) && (tint > 0)) { tint --; } + #endif // ifdef USE_STEPPED_TINT_RAMPING + // if tint change stalled, let user know we hit the edge else if (prev_tint == tint) { if (past_edge_counter == 0) blip(); @@ -124,6 +136,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { return EVENT_NOT_HANDLED; } + #if NUM_CHANNEL_MODES > 1 void channel_mode_config_save(uint8_t step, uint8_t value) { // 1 menu item per channel mode, to enable or disable that mode @@ -142,3 +155,31 @@ uint8_t channel_mode_config_state(Event event, uint16_t arg) { } #endif + +#if defined(USE_CHANNEL_MODE_ARGS) && defined(USE_STEPPED_TINT_RAMPING) +uint8_t nearest_tint_value(const int16_t target) { + // const symbols for more readable code, will be removed by the compiler + const uint8_t tint_min = 0; + const uint8_t tint_max = 255; + const uint8_t tint_range = tint_max - tint_min; + + // only equal mix of both channels + if (1 == cfg.tint_ramp_style) return (tint_min + tint_max) >> 1; + + if (target < tint_min) return tint_min; + if (target > tint_max) return tint_max; + if (0 == cfg.tint_ramp_style) return target; // smooth ramping + + const uint8_t step_size = tint_range / (cfg.tint_ramp_style-1); + + uint8_t tint_result = tint_min; + for (uint8_t i=0; i>1)) return tint_result; + } + return tint_result; +} +#endif + diff --git a/spaghetti-monster/anduril/channel-modes.h b/spaghetti-monster/anduril/channel-modes.h index 67d6bbb..4c16281 100644 --- a/spaghetti-monster/anduril/channel-modes.h +++ b/spaghetti-monster/anduril/channel-modes.h @@ -10,3 +10,9 @@ uint8_t channel_mode_state(Event event, uint16_t arg); #if NUM_CHANNEL_MODES > 1 uint8_t channel_mode_config_state(Event event, uint16_t arg); #endif + +#if defined(USE_CHANNEL_MODE_ARGS) && defined(USE_STEPPED_TINT_RAMPING) +// calculate the nearest tint value which would be valid at the moment +uint8_t nearest_tint_value(const int16_t target); +#endif + diff --git a/spaghetti-monster/anduril/config-default.h b/spaghetti-monster/anduril/config-default.h index 514b9a8..5023c3b 100644 --- a/spaghetti-monster/anduril/config-default.h +++ b/spaghetti-monster/anduril/config-default.h @@ -181,3 +181,7 @@ // those oscillations //#define USE_LOWPASS_WHILE_ASLEEP +// if there's tint ramping, allow user to set it smooth or stepped +#define USE_STEPPED_TINT_RAMPING +#define DEFAULT_TINT_RAMP_STYLE 0 // smooth + diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h index ef079db..ceb9d76 100644 --- a/spaghetti-monster/anduril/load-save-config-fsm.h +++ b/spaghetti-monster/anduril/load-save-config-fsm.h @@ -59,6 +59,9 @@ typedef struct Config { #ifdef USE_MANUAL_MEMORY uint8_t manual_memory_channel_args[NUM_CHANNEL_MODES]; #endif + #ifdef USE_STEPPED_TINT_RAMPING + uint8_t tint_ramp_style; + #endif #endif ///// strobe / blinky mode settings diff --git a/spaghetti-monster/anduril/load-save-config.h b/spaghetti-monster/anduril/load-save-config.h index 9fe24c7..60612d3 100644 --- a/spaghetti-monster/anduril/load-save-config.h +++ b/spaghetti-monster/anduril/load-save-config.h @@ -85,6 +85,9 @@ Config cfg = { // remember and reset 1 extra parameter per channel mode (like tint) .manual_memory_channel_args = { CHANNEL_MODE_ARGS }, #endif + #ifdef USE_STEPPED_TINT_RAMPING + .tint_ramp_style = DEFAULT_TINT_RAMP_STYLE, + #endif #endif ///// strobe / blinky mode settings diff --git a/spaghetti-monster/anduril/ramp-mode-fsm.h b/spaghetti-monster/anduril/ramp-mode-fsm.h index 8fb80d1..edfd6db 100644 --- a/spaghetti-monster/anduril/ramp-mode-fsm.h +++ b/spaghetti-monster/anduril/ramp-mode-fsm.h @@ -31,7 +31,8 @@ #endif // include an extra config mode for random stuff which doesn't fit elsewhere -#if defined(USE_TINT_RAMPING) || defined(USE_JUMP_START) +#if defined(USE_JUMP_START) || \ + (defined(USE_CHANNEL_MODE_ARGS) && defined(USE_STEPPED_TINT_RAMPING)) #define USE_GLOBALS_CONFIG #endif diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index 5a960c9..1799e97 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -587,12 +587,8 @@ uint8_t ramp_extras_config_state(Event event, uint16_t arg) { #ifdef USE_GLOBALS_CONFIG void globals_config_save(uint8_t step, uint8_t value) { if (0) {} - #ifdef USE_TINT_RAMPING - else if (step == 1+tint_style_config_step) { - tint_style = !(!(value)); - // set tint to middle or edge depending on style being smooth or toggle - tint = tint_style ? 1 : 127; - } + #if defined(USE_CHANNEL_MODE_ARGS) && defined(USE_STEPPED_TINT_RAMPING) + else if (step == 1+tint_style_config_step) { cfg.tint_ramp_style = value; } #endif #ifdef USE_JUMP_START else if (step == 1+jump_start_config_step) { cfg.jump_start_level = value; } diff --git a/spaghetti-monster/anduril/ramp-mode.h b/spaghetti-monster/anduril/ramp-mode.h index e4ded1e..20986cc 100644 --- a/spaghetti-monster/anduril/ramp-mode.h +++ b/spaghetti-monster/anduril/ramp-mode.h @@ -188,7 +188,7 @@ void reset_sunset_timer(); #ifdef USE_GLOBALS_CONFIG typedef enum { - #ifdef USE_TINT_RAMPING + #if defined(USE_CHANNEL_MODE_ARGS) && defined(USE_STEPPED_TINT_RAMPING) tint_style_config_step, #endif #ifdef USE_JUMP_START -- cgit v1.2.3 From 5f6bb2bda2dd4eccbdfba94e5d35cedc8c0c42dc Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 25 Apr 2023 01:07:15 -0600 Subject: updated D4Sv2-tintramp -> Emisar 2-channel build target ... ... and reworked how gradual_tick() works ... and updated LT1S Pro to use new method --- hwdef-Sofirn_LT1S-Pro.c | 99 +++++-------- hwdef-Sofirn_LT1S-Pro.h | 10 +- hwdef-emisar-2ch.c | 161 +++++++++++++++++++++ hwdef-emisar-2ch.h | 222 +++++++++++++++++++++++++++++ spaghetti-monster/anduril/cfg-emisar-2ch.h | 114 +++++++++++++++ spaghetti-monster/fsm-ramping.c | 13 +- spaghetti-monster/fsm-ramping.h | 13 +- tk.h | 8 ++ 8 files changed, 555 insertions(+), 85 deletions(-) create mode 100644 hwdef-emisar-2ch.c create mode 100644 hwdef-emisar-2ch.h create mode 100644 spaghetti-monster/anduril/cfg-emisar-2ch.h diff --git a/hwdef-Sofirn_LT1S-Pro.c b/hwdef-Sofirn_LT1S-Pro.c index dd93f93..f5af65a 100644 --- a/hwdef-Sofirn_LT1S-Pro.c +++ b/hwdef-Sofirn_LT1S-Pro.c @@ -155,24 +155,28 @@ void set_level_red_white_blend(uint8_t level) { ///// "gradual tick" functions for smooth thermal regulation ///// -void gradual_tick_red() { - GRADUAL_TICK_SETUP(); - - GRADUAL_ADJUST_1CH(pwm1_levels, RED_PWM_LVL); +///// bump each channel toward a target value ///// +bool gradual_adjust(uint16_t red, uint16_t warm, uint16_t cool) { + GRADUAL_ADJUST_SIMPLE(red, RED_PWM_LVL ); + GRADUAL_ADJUST_SIMPLE(warm, WARM_PWM_LVL); + GRADUAL_ADJUST_SIMPLE(cool, COOL_PWM_LVL); - if ((RED_PWM_LVL == PWM_GET(pwm1_levels, gt))) - { - GRADUAL_IS_ACTUAL(); + // check for completion + if ((red == RED_PWM_LVL ) + && (warm == WARM_PWM_LVL) + && (cool == COOL_PWM_LVL)) { + return true; // done } + return false; // not done yet } +bool gradual_tick_red(uint8_t gt) { + uint16_t red = PWM_GET(pwm1_levels, gt); + return gradual_adjust(red, 0, 0); +} -void gradual_tick_white_blend() { - uint8_t gt = gradual_target; - if (gt < actual_level) gt = actual_level - 1; - else if (gt > actual_level) gt = actual_level + 1; - gt --; +bool gradual_tick_white_blend(uint8_t gt) { // figure out what exact PWM levels we're aiming for PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); @@ -181,27 +185,12 @@ void gradual_tick_white_blend() { calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); - // move up/down if necessary - GRADUAL_ADJUST_SIMPLE(warm_PWM, WARM_PWM_LVL); - GRADUAL_ADJUST_SIMPLE(cool_PWM, COOL_PWM_LVL); - - // check for completion - if ( (WARM_PWM_LVL == warm_PWM) - && (COOL_PWM_LVL == cool_PWM) - ) - { - GRADUAL_IS_ACTUAL(); - } + return gradual_adjust(0, warm_PWM, cool_PWM); } // same as white blend, but tint is calculated from the ramp level -void gradual_tick_auto_2ch_blend() { - uint8_t gt = gradual_target; - if (gt < actual_level) gt = actual_level - 1; - else if (gt > actual_level) gt = actual_level + 1; - gt --; - +bool gradual_tick_auto_2ch_blend(uint8_t gt) { // figure out what exact PWM levels we're aiming for PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); @@ -210,53 +199,29 @@ void gradual_tick_auto_2ch_blend() { calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); - // move up/down if necessary - GRADUAL_ADJUST_SIMPLE(warm_PWM, WARM_PWM_LVL); - GRADUAL_ADJUST_SIMPLE(cool_PWM, COOL_PWM_LVL); - - // check for completion - if ( (WARM_PWM_LVL == warm_PWM) - && (COOL_PWM_LVL == cool_PWM) - ) - { - GRADUAL_IS_ACTUAL(); - } + return gradual_adjust(0, warm_PWM, cool_PWM); } -void gradual_tick_auto_3ch_blend() { - uint8_t gt = gradual_target; - if (gt < actual_level) gt = actual_level - 1; - else if (gt > actual_level) gt = actual_level + 1; - gt --; - +bool gradual_tick_auto_3ch_blend(uint8_t gt) { // figure out what exact PWM levels we're aiming for PWM_DATATYPE red, warm, cool; calc_auto_3ch_blend(&red, &warm, &cool, gt); + return gradual_adjust(red, warm, cool); +} - // move up/down if necessary - GRADUAL_ADJUST_SIMPLE(red, RED_PWM_LVL); - GRADUAL_ADJUST_SIMPLE(warm, WARM_PWM_LVL); - GRADUAL_ADJUST_SIMPLE(cool, COOL_PWM_LVL); - // check for completion - if ( (RED_PWM_LVL == red) - && (WARM_PWM_LVL == warm) - && (COOL_PWM_LVL == cool) - ) - { - GRADUAL_IS_ACTUAL(); - } -} +bool gradual_tick_red_white_blend(uint8_t gt) { + // figure out what exact PWM levels we're aiming for + PWM_DATATYPE red, warm, cool; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE top = PWM_GET(pwm_tops, gt); + uint8_t blend = cfg.channel_mode_args[CM_WHITE]; + uint8_t ratio = cfg.channel_mode_args[cfg.channel_mode]; + red = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)brightness) + 127) / 255; + calc_2ch_blend(&warm, &cool, brightness, top, blend); -void gradual_tick_red_white_blend() { - // do the white blend thing... - cfg.channel_mode = CM_WHITE; - gradual_tick_white_blend(); - cfg.channel_mode = CM_WHITE_RED; - // ... and then update red to the closest ramp level - // (coarse red adjustments aren't visible here anyway) - set_level_red(actual_level); + return gradual_adjust(red, warm, cool); } diff --git a/hwdef-Sofirn_LT1S-Pro.h b/hwdef-Sofirn_LT1S-Pro.h index af0e6f0..a63f906 100644 --- a/hwdef-Sofirn_LT1S-Pro.h +++ b/hwdef-Sofirn_LT1S-Pro.h @@ -115,11 +115,11 @@ void set_level_auto_2ch_blend(uint8_t level); void set_level_auto_3ch_blend(uint8_t level); void set_level_red_white_blend(uint8_t level); -void gradual_tick_red(); -void gradual_tick_white_blend(); -void gradual_tick_auto_2ch_blend(); -void gradual_tick_auto_3ch_blend(); -void gradual_tick_red_white_blend(); +bool gradual_tick_red(uint8_t gt); +bool gradual_tick_white_blend(uint8_t gt); +bool gradual_tick_auto_2ch_blend(uint8_t gt); +bool gradual_tick_auto_3ch_blend(uint8_t gt); +bool gradual_tick_red_white_blend(uint8_t gt); inline void hwdef_setup() { diff --git a/hwdef-emisar-2ch.c b/hwdef-emisar-2ch.c new file mode 100644 index 0000000..53117e0 --- /dev/null +++ b/hwdef-emisar-2ch.c @@ -0,0 +1,161 @@ +// Emisar 2-channel generic w/ tint ramping +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// set new values for both channels, +// handling any possible combination +// and any before/after state +void set_pwms(uint16_t ch1_pwm, uint16_t ch2_pwm, uint16_t top) { + bool was_on = (CH1_PWM>0) | (CH2_PWM>0); + bool now_on = (ch1_pwm>0) | (ch2_pwm>0); + + if (! now_on) { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_TOP = PWM_TOP_INIT; + PWM_CNT = 0; + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp + CH2_ENABLE_PORT &= ~(1 << CH2_ENABLE_PIN); // disable opamp + return; + } + + if (ch1_pwm) + CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable opamp + else + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp + + if (ch2_pwm) + CH2_ENABLE_PORT |= (1 << CH2_ENABLE_PIN); // enable opamp + else + CH2_ENABLE_PORT &= ~(1 << CH2_ENABLE_PIN); // disable opamp + + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; + + // manual phase sync when changing level while already on + if (was_on && now_on) while(PWM_CNT > (top - 32)) {} + + PWM_TOP = top; + + // reset phase when turning on or off + //if ((! was_on) | (! now_on)) PWM_CNT = 0; + if (! was_on) PWM_CNT = 0; +} + +void set_level_ch1(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, PWM_TOP_INIT); + + level --; + uint16_t pwm = PWM_GET(pwm1_levels, level); + uint16_t top = PWM_GET(pwm_tops, level); + set_pwms(pwm, 0, top); +} + +void set_level_ch2(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, PWM_TOP_INIT); + + level --; + uint16_t pwm = PWM_GET(pwm1_levels, level); + uint16_t top = PWM_GET(pwm_tops, level); + set_pwms(0, pwm, top); +} + +void set_level_both(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, PWM_TOP_INIT); + + level --; + uint16_t pwm = PWM_GET(pwm1_levels, level); + uint16_t top = PWM_GET(pwm_tops, level); + set_pwms(pwm, pwm, top); +} + +void set_level_blend(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, PWM_TOP_INIT); + + level --; + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + PWM_DATATYPE top = PWM_GET(pwm_tops, level); + uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); + + set_pwms(ch1_pwm, ch2_pwm, top); +} + +void set_level_auto(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, PWM_TOP_INIT); + + level --; + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + PWM_DATATYPE top = PWM_GET(pwm_tops, level); + uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; + if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + blend = 255 - blend; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); + + set_pwms(ch1_pwm, ch2_pwm, top); +} + + +///// bump each channel toward a target value ///// +bool gradual_adjust(uint16_t ch1_pwm, uint16_t ch2_pwm) { + GRADUAL_ADJUST_SIMPLE(ch1_pwm, CH1_PWM); + GRADUAL_ADJUST_SIMPLE(ch2_pwm, CH2_PWM); + + // check for completion + if ((ch1_pwm == CH1_PWM) + && (ch2_pwm == CH2_PWM)) { + return true; // done + } + return false; // not done yet +} + +bool gradual_tick_ch1(uint8_t gt) { + uint16_t pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(pwm, 0); +} + +bool gradual_tick_ch2(uint8_t gt) { + uint16_t pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(0, pwm); +} + +bool gradual_tick_both(uint8_t gt) { + uint16_t pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(pwm, pwm); +} + +bool gradual_tick_blend(uint8_t gt) { + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE top = PWM_GET(pwm_tops, gt); + uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); + + return gradual_adjust(ch1_pwm, ch2_pwm); +} + +bool gradual_tick_auto(uint8_t gt) { + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE top = PWM_GET(pwm_tops, gt); + uint8_t blend = 255 * (uint16_t)gt / RAMP_SIZE; + if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + blend = 255 - blend; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); + + return gradual_adjust(ch1_pwm, ch2_pwm); +} + + diff --git a/hwdef-emisar-2ch.h b/hwdef-emisar-2ch.h new file mode 100644 index 0000000..8b0ffc0 --- /dev/null +++ b/hwdef-emisar-2ch.h @@ -0,0 +1,222 @@ +// Emisar 2-channel generic w/ tint ramping +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * Pin / Name / Function + * 1 PA6 ch2 LED PWM (linear) (PWM1B) + * 2 PA5 R: red aux LED (PWM0B) + * 3 PA4 G: green aux LED + * 4 PA3 B: blue aux LED + * 5 PA2 button LED + * 6 PA1 Opamp 2 enable (channel 2 LEDs) + * 7 PA0 Opamp 1 enable (channel 1 LEDs) + * 8 GND GND + * 9 VCC VCC + * 10 PC5 (none) + * 11 PC4 (none) + * 12 PC3 RESET + * 13 PC2 (none) + * 14 PC1 SCK + * 15 PC0 [unused: ch1 LED PWM (FET) (PWM0A, 8-bit)] + * 16 PB3 ch1 LED PWM (linear) (PWM1A) + * 17 PB2 MISO + * 18 PB1 MOSI / battery voltage (ADC6) + * 19 PB0 (none) + * 20 PA7 e-switch (PCINT7) + * ADC12 thermal sensor + */ + +#define HWDEF_C_FILE hwdef-emisar-2ch.c + +#define ATTINY 1634 +#include + +// channel modes: +// * 0. channel 1 only +// * 1. channel 2 only +// * 2. both channels, tied together +// * 3. both channels, manual blend, max 200% power? +// * 4. both channels, auto blend, reversible +#define NUM_CHANNEL_MODES 5 +#define CM_CH1 0 +#define CM_CH2 1 +#define CM_BOTH 2 +#define CM_BLEND 3 +#define CM_AUTO 4 + +#define CHANNEL_MODES_ENABLED 0b00011111 +#define CHANNEL_HAS_ARGS 0b00011000 +// _, _, _, 128=middle CCT, 0=warm-to-cool +#define CHANNEL_MODE_ARGS 0,0,0,128,0 + +#define USE_CHANNEL_MODES +#define USE_CHANNEL_MODE_ARGS +#define SET_LEVEL_MODES set_level_ch1, \ + set_level_ch2, \ + set_level_both, \ + set_level_blend, \ + set_level_auto +// gradual ticking for thermal regulation +#define GRADUAL_TICK_MODES gradual_tick_ch1, \ + gradual_tick_ch2, \ + gradual_tick_both, \ + gradual_tick_blend, \ + gradual_tick_auto +// can use some of the common handlers +#define USE_CALC_2CH_BLEND + + +#define PWM_CHANNELS 1 // old, remove this + +#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // regular ramp table +#define PWM2_DATATYPE uint16_t // max "200% power" ramp table +//#define PWM3_DATATYPE uint8_t // DD FET ramp table (8-bit only) + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 511 +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +#define CH1_PIN PB3 // pin 16, Opamp reference +#define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 +#define CH1_ENABLE_PIN PA0 // pin 7, Opamp power +#define CH1_ENABLE_PORT PORTA // control port for PA0 + +#define CH2_PIN PA6 // pin 1, 2nd LED Opamp reference +#define CH2_PWM OCR1B // OCR1B is the output compare register for PA6 +#define CH2_ENABLE_PIN PA1 // pin 6, Opamp power +#define CH2_ENABLE_PORT PORTA // control port for PA1 + +//#define CH3_PIN PC0 // pin 15, DD FET PWM +//#define CH3_LVL OCR0A // OCR0A is the output compare register for PC0 + + +#ifndef SWITCH_PIN +#define SWITCH_PIN PA7 // pin 20 +#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt +#define SWITCH_PCIE PCIE0 // PCIE1 is for PCINT[7:0] +#define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] +#define SWITCH_PORT PINA // PINA or PINB or PINC +#define SWITCH_PUE PUEA // pullup group A +#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#endif + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 +// pin to ADC mappings are in DS table 19-4 +#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 +// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 +#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D +// DS tables 19-3, 19-4 +// Bit 7 6 5 4 3 2 1 0 +// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 +// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 +// divided by ... +// REFS[1:0] = 1, 0 for internal 1.1V reference +// other bits reserved +#define ADMUX_VOLTAGE_DIVIDER 0b10000110 +#define ADC_PRSCL 0x07 // clk/128 + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// D1, R1, R2 = 0, 330, 100 +#ifndef ADC_44 +//#define ADC_44 981 // raw value at 4.40V +#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 +#endif +#ifndef ADC_22 +//#define ADC_22 489 // raw value at 2.20V +#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 +#endif + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + +#define BUTTON_LED_PIN PA2 // pin 5 +#define BUTTON_LED_PORT PORTA // for all "PA" pins +#define BUTTON_LED_DDR DDRA // for all "PA" pins +#define BUTTON_LED_PUE PUEA // for all "PA" pins + + +void set_level_ch1(uint8_t level); +void set_level_ch2(uint8_t level); +void set_level_both(uint8_t level); +void set_level_blend(uint8_t level); +void set_level_auto(uint8_t level); + +bool gradual_tick_ch1(uint8_t gt); +bool gradual_tick_ch2(uint8_t gt); +bool gradual_tick_both(uint8_t gt); +bool gradual_tick_blend(uint8_t gt); +bool gradual_tick_auto(uint8_t gt); + + +// with so many pins, doing this all with #ifdefs gets awkward... +// ... so just hardcode it in each hwdef file instead +inline void hwdef_setup() { + // enable output ports + //DDRC = (1 << CH3_PIN); + DDRB = (1 << CH1_PIN); + DDRA = (1 << CH2_PIN) + | (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + | (1 << BUTTON_LED_PIN) + | (1 << CH1_ENABLE_PIN) + | (1 << CH2_ENABLE_PIN) + ; + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // Linear opamp PWM for both main and 2nd LEDs (10-bit) + // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) + TCCR1A = (1< actual_level) gt = actual_level + 1; + gt --; + // call the relevant hardware-specific function GradualTickFuncPtr gradual_tick_func = gradual_tick_modes[CH_MODE]; - gradual_tick_func(); + bool done = gradual_tick_func(gt); + + if (done) { + uint8_t orig = gradual_target; + set_level(gt + 1); + gradual_target = orig; + } } diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index a9e333e..7b3722d 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -32,7 +32,7 @@ SetLevelFuncPtr channel_modes[NUM_CHANNEL_MODES]; #ifdef USE_SET_LEVEL_GRADUALLY // the gradual tick mechanism may be different per channel -typedef void GradualTickFunc(); +typedef bool GradualTickFunc(uint8_t gt); typedef GradualTickFunc * GradualTickFuncPtr; // TODO: move to progmem GradualTickFuncPtr gradual_tick_modes[NUM_CHANNEL_MODES]; @@ -101,12 +101,7 @@ inline void set_level_gradually(uint8_t lvl); void gradual_tick(); // reduce repetition with macros -// common code at the beginning of every gradual tick handler #define GRADUAL_TICK_SETUP() \ - uint8_t gt = gradual_target; \ - if (gt < actual_level) gt = actual_level - 1; \ - else if (gt > actual_level) gt = actual_level + 1; \ - gt --; \ PWM_DATATYPE target; // tick to a specific value @@ -132,12 +127,6 @@ void gradual_tick(); if (PWM < target) PWM ++; \ else if (PWM > target) PWM --; -// do this when output exactly matches a ramp level -#define GRADUAL_IS_ACTUAL() \ - uint8_t orig = gradual_target; \ - set_level(gt + 1); \ - gradual_target = orig; - #endif // ifdef USE_SET_LEVEL_GRADUALLY // auto-detect the data type for PWM tables diff --git a/tk.h b/tk.h index d618134..785808d 100644 --- a/tk.h +++ b/tk.h @@ -9,6 +9,14 @@ // but which don't need to be repeated in every source file //// +// AVR GCC has no boolean type by default +// (this isn't native bool, but it's mostly okay) +#define bool uint8_t +#define false 0 +#define true 1 +#define FALSE 0 +#define TRUE 1 + // create a way to include files defined at the command line, // like with "gcc -DCONFIGFILE=foo.h" #define incfile2(s) #s -- cgit v1.2.3 From 847485ca96a6ef99abd19984ec025cf1d6841d3d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 25 Apr 2023 23:28:30 -0600 Subject: fixed bug behind K93_LOCKOUT_KLUDGE which could exit lockout in solid aux mode (also reduced avg standby power by about 15 uA) (also fixed oscillating voltage mode colors, I think) The bug happened because sometimes sleep LVP would get triggered, because the ADC would read zero under some conditions. This in turn happened because the ADC needs the MCU to be at least partially awake in order to finish a measurement. So in standby mode, with the MCU only waking up very briefly to send a sleep tick and go back to sleep, the ADC required several cycles (like 375ms to 625ms) to finish a single measurement. This varied depending on how many instructions the MCU executed while it was awake. In the single-color mode, so few instructions were being executed that the ADC seemed to time out and abort its measurement, returning a zero. Then a low voltage warning was sent, which knocked the light back into "Off" mode. Adding no-op instructions inside the single-color clause was sufficient to prevent the ADC from timing out, because it kept the MCU awake just barely long enough. But it was a kludge, and it still took like half a second to finish a measurement, and the measurements were noisy. It also used more power, because it required keeping the ADC powered on far too long. This fix puts the MCU into "ADC Noise Reduction" mode instead, when a voltage measurement is needed during sleep. It reduces noise to make measurements more stable... but more importantly, it lets the measurement finish in like 0.5ms instead of 500ms. So it uses less power and isn't dependent on the number of calculations the MCU does during each "sleep tick". As a bonus, this can also measure voltage much more often, while still using less total energy than before. It was once every 8 seconds, and now it's once per second. Avg power use in aux low mode, on a D4Sv2: (avg of 30k samples each) - before: 101 uA - after: 86 uA --- spaghetti-monster/anduril/aux-leds.c | 9 --------- spaghetti-monster/anduril/cfg-emisar-2ch.h | 3 --- spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h | 3 --- spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h | 3 --- spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h | 3 --- spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h | 3 --- spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h | 3 --- spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h | 3 --- spaghetti-monster/anduril/cfg-noctigon-dm11.h | 3 --- spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-nofet.h | 3 --- spaghetti-monster/anduril/cfg-noctigon-k9.3.h | 3 --- spaghetti-monster/fsm-adc.c | 2 ++ spaghetti-monster/fsm-adc.h | 3 +++ spaghetti-monster/fsm-standby.c | 9 +++++++++ spaghetti-monster/fsm-wdt.c | 3 ++- 15 files changed, 16 insertions(+), 40 deletions(-) diff --git a/spaghetti-monster/anduril/aux-leds.c b/spaghetti-monster/anduril/aux-leds.c index d9b23d0..c72eb70 100644 --- a/spaghetti-monster/anduril/aux-leds.c +++ b/spaghetti-monster/anduril/aux-leds.c @@ -108,15 +108,6 @@ void rgb_led_update(uint8_t mode, uint8_t arg) { const uint8_t *colors = rgb_led_colors; uint8_t actual_color = 0; if (color < 7) { // normal color - #ifdef USE_K93_LOCKOUT_KLUDGE - // FIXME: jank alert: this is dumb - // this clause does nothing; it just uses up clock cycles - // because without it, the K9.3's lockout mode fails and returns - // to "off" after ~5 to 15 seconds when configured for a blinking - // single color, even though there is no code path from lockout to - // "off", and it doesn't act like a reboot either (no boot-up blink) - rainbow = (rainbow + 1 + pseudo_rand() % 5) % 6; - #endif actual_color = pgm_read_byte(colors + color); } else if (color == 7) { // disco diff --git a/spaghetti-monster/anduril/cfg-emisar-2ch.h b/spaghetti-monster/anduril/cfg-emisar-2ch.h index 00ef117..69e1524 100644 --- a/spaghetti-monster/anduril/cfg-emisar-2ch.h +++ b/spaghetti-monster/anduril/cfg-emisar-2ch.h @@ -109,6 +109,3 @@ // for consistency with KR4 (not otherwise necessary though) #define USE_SOFT_FACTORY_RESET - -// work around bizarre bug: lockout mode fails when set to solid color blinking -//#define USE_K93_LOCKOUT_KLUDGE diff --git a/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h b/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h index 15464db..6df56cf 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h @@ -30,6 +30,3 @@ #endif #define THERM_FASTER_LEVEL (RAMP_SIZE*9/10) // throttle back faster when high - -// work around bizarre bug: lockout mode fails when set to solid color blinking -#define USE_K93_LOCKOUT_KLUDGE diff --git a/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h b/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h index c8864bf..c1f7238 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h @@ -28,6 +28,3 @@ #endif #define THERM_FASTER_LEVEL (RAMP_SIZE*9/10) // throttle back faster when high - -// work around bizarre bug: lockout mode fails when set to solid color blinking -#define USE_K93_LOCKOUT_KLUDGE diff --git a/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h b/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h index ede1b67..a68a333 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h @@ -22,6 +22,3 @@ #undef SIMPLE_UI_CEIL #define SIMPLE_UI_CEIL RAMP_SMOOTH_CEIL - -// work around bizarre bug: lockout mode fails when set to solid color blinking -#define USE_K93_LOCKOUT_KLUDGE diff --git a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h b/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h index bfbcba0..c9a0b4f 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h @@ -86,6 +86,3 @@ // for consistency with KR4 (not otherwise necessary though) #define USE_SOFT_FACTORY_RESET - -// work around bizarre bug: lockout mode fails when set to solid color blinking -#define USE_K93_LOCKOUT_KLUDGE diff --git a/spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h b/spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h index e0fc162..7798206 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h +++ b/spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h @@ -77,6 +77,3 @@ // added for convenience #define USE_SOFT_FACTORY_RESET - -// work around bizarre bug: lockout mode fails when set to solid color blinking -#define USE_K93_LOCKOUT_KLUDGE diff --git a/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h b/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h index 5a978b5..94c9a52 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h +++ b/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h @@ -76,6 +76,3 @@ // added for convenience #define USE_SOFT_FACTORY_RESET - -// work around bizarre bug: lockout mode fails when set to solid color blinking -#define USE_K93_LOCKOUT_KLUDGE diff --git a/spaghetti-monster/anduril/cfg-noctigon-dm11.h b/spaghetti-monster/anduril/cfg-noctigon-dm11.h index d9b0b8c..5f3cb80 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-dm11.h +++ b/spaghetti-monster/anduril/cfg-noctigon-dm11.h @@ -76,6 +76,3 @@ // added for convenience #define USE_SOFT_FACTORY_RESET - -// work around bizarre bug: lockout mode fails when set to solid color blinking -#define USE_K93_LOCKOUT_KLUDGE diff --git a/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-nofet.h index b505701..8eb55dc 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-nofet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-nofet.h @@ -83,6 +83,3 @@ // for consistency with KR4 (not otherwise necessary though) #define USE_SOFT_FACTORY_RESET - -// work around bizarre bug: lockout mode fails when set to solid color blinking -#define USE_K93_LOCKOUT_KLUDGE diff --git a/spaghetti-monster/anduril/cfg-noctigon-k9.3.h b/spaghetti-monster/anduril/cfg-noctigon-k9.3.h index dfe1d18..bf504d2 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-k9.3.h +++ b/spaghetti-monster/anduril/cfg-noctigon-k9.3.h @@ -84,6 +84,3 @@ inline void set_level_override(uint8_t level); // for consistency with KR4 (not otherwise necessary though) #define USE_SOFT_FACTORY_RESET - -// work around bizarre bug: lockout mode fails when set to solid color blinking -#define USE_K93_LOCKOUT_KLUDGE diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 5b238aa..0b79767 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -244,6 +244,8 @@ void adc_deferred() { // (and the usual standby level is only ~20 uA) if (go_to_standby) { ADC_off(); + // if any measurements were in progress, they're done now + adc_active_now = 0; // also, only check the battery while asleep, not the temperature adc_channel = 0; } diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index 16666f9..b25b650 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -32,6 +32,9 @@ volatile uint8_t adc_reset = 2; #endif #endif +#ifdef TICK_DURING_STANDBY +volatile uint8_t adc_active_now = 0; // sleep LVP needs a different sleep mode +#endif volatile uint8_t irq_adc = 0; // ADC interrupt happened? uint8_t adc_sample_count = 0; // skip the first sample; it's junk uint8_t adc_channel = 0; // 0=voltage, 1=temperature diff --git a/spaghetti-monster/fsm-standby.c b/spaghetti-monster/fsm-standby.c index 50e6e30..2ce3a24 100644 --- a/spaghetti-monster/fsm-standby.c +++ b/spaghetti-monster/fsm-standby.c @@ -40,6 +40,15 @@ void sleep_until_eswitch_pressed() #endif // configure sleep mode + #ifdef TICK_DURING_STANDBY + // needs a special sleep mode to get accurate measurements + // quickly ... full power-down ends up using more power + // overall, and causes some weird issues when the MCU + // doesn't stay awake enough cycles to complete a reading + if (adc_active_now) + set_sleep_mode(SLEEP_MODE_ADC); + else + #endif set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c index 847c7fd..7c25e9f 100644 --- a/spaghetti-monster/fsm-wdt.c +++ b/spaghetti-monster/fsm-wdt.c @@ -123,9 +123,10 @@ void WDT_inner() { return; // no sleep LVP needed if nothing drains power while off #else // stop here, usually... but proceed often enough for sleep LVP to work - if (0 != (ticks_since_last & 0x3f)) return; + if (0 != (ticks_since_last & 0x07)) return; adc_trigger = 0; // make sure a measurement will happen + adc_active_now = 1; // use ADC noise reduction sleep mode ADC_on(); // enable ADC voltage measurement functions temporarily #endif } -- cgit v1.2.3 From 5c3917517c8bebdb9326ec715ed3e52ea801d695 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 25 Apr 2023 23:57:33 -0600 Subject: put RGB aux LEDs in high mode for 3 seconds after light goes to sleep (much easier to see the voltage this way, including post-turbo sag) --- spaghetti-monster/anduril/aux-leds.c | 4 +++- spaghetti-monster/anduril/aux-leds.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/aux-leds.c b/spaghetti-monster/anduril/aux-leds.c index c72eb70..5ac92a3 100644 --- a/spaghetti-monster/anduril/aux-leds.c +++ b/spaghetti-monster/anduril/aux-leds.c @@ -79,7 +79,7 @@ uint8_t voltage_to_rgb() { // do fancy stuff with the RGB aux LEDs // mode: 0bPPPPCCCC where PPPP is the pattern and CCCC is the color // arg: time slice number -void rgb_led_update(uint8_t mode, uint8_t arg) { +void rgb_led_update(uint8_t mode, uint16_t arg) { static uint8_t rainbow = 0; // track state of rainbow mode static uint8_t frame = 0; // track state of animation mode @@ -104,6 +104,8 @@ void rgb_led_update(uint8_t mode, uint8_t arg) { // preview in blinking mode is awkward... use high instead if ((! go_to_standby) && (pattern > 2)) { pattern = 2; } + // use high mode for a few seconds after initial poweroff + if (arg < (SLEEP_TICKS_PER_SECOND*3)) pattern = 2; const uint8_t *colors = rgb_led_colors; uint8_t actual_color = 0; diff --git a/spaghetti-monster/anduril/aux-leds.h b/spaghetti-monster/anduril/aux-leds.h index 1938557..2e656dc 100644 --- a/spaghetti-monster/anduril/aux-leds.h +++ b/spaghetti-monster/anduril/aux-leds.h @@ -8,7 +8,7 @@ void indicator_led_update(uint8_t mode, uint8_t tick); #endif #if defined(USE_AUX_RGB_LEDS) && defined(TICK_DURING_STANDBY) uint8_t setting_rgb_mode_now = 0; -void rgb_led_update(uint8_t mode, uint8_t arg); +void rgb_led_update(uint8_t mode, uint16_t arg); void rgb_led_voltage_readout(uint8_t bright); /* * 0: R -- cgit v1.2.3 From aa4c627377b07cc07cd1e904f9f7d2f24c1155a4 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 26 Apr 2023 01:34:53 -0600 Subject: made sleep voltage work on attiny1616 again (oops, it has no "ADC Noise Reduction" mode... needs different setup code) --- spaghetti-monster/fsm-adc.c | 25 +++++++++++++++++++++++++ spaghetti-monster/fsm-adc.h | 4 ++++ spaghetti-monster/fsm-standby.c | 8 ++------ 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/spaghetti-monster/fsm-adc.c b/spaghetti-monster/fsm-adc.c index 0b79767..a196b7b 100644 --- a/spaghetti-monster/fsm-adc.c +++ b/spaghetti-monster/fsm-adc.c @@ -12,6 +12,8 @@ #define ADMUX_THERM ADMUX_THERM_EXTERNAL_SENSOR #endif +#include + static inline void set_admux_therm() { #if (ATTINY == 1634) @@ -70,6 +72,29 @@ inline void set_admux_voltage() { ADC_start_measurement(); } + +#ifdef TICK_DURING_STANDBY +inline void adc_sleep_mode() { + // needs a special sleep mode to get accurate measurements quickly + // ... full power-down ends up using more power overall, and causes + // some weird issues when the MCU doesn't stay awake enough cycles + // to complete a reading + #ifdef SLEEP_MODE_ADC + // attiny1634 + set_sleep_mode(SLEEP_MODE_ADC); + #elif defined(AVRXMEGA3) // ATTINY816, 817, etc + // set the RUNSTDBY bit so ADC will run in standby mode + ADC0.CTRLA |= 1; + // set a INITDLY value because the AVR manual says so + // (section 30.3.5) + ADC0.CTRLD |= (1 << 5); + set_sleep_mode(SLEEP_MODE_STANDBY); + #else + #error No ADC sleep mode defined for this hardware. + #endif +} +#endif + inline void ADC_start_measurement() { #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) || (ATTINY == 841) || (ATTINY == 1634) ADCSRA |= (1 << ADSC) | (1 << ADIE); diff --git a/spaghetti-monster/fsm-adc.h b/spaghetti-monster/fsm-adc.h index b25b650..1bb67ed 100644 --- a/spaghetti-monster/fsm-adc.h +++ b/spaghetti-monster/fsm-adc.h @@ -106,3 +106,7 @@ inline void ADC_on(); inline void ADC_off(); inline void ADC_start_measurement(); +#ifdef TICK_DURING_STANDBY +inline void adc_sleep_mode(); +#endif + diff --git a/spaghetti-monster/fsm-standby.c b/spaghetti-monster/fsm-standby.c index 2ce3a24..5def07c 100644 --- a/spaghetti-monster/fsm-standby.c +++ b/spaghetti-monster/fsm-standby.c @@ -41,12 +41,8 @@ void sleep_until_eswitch_pressed() // configure sleep mode #ifdef TICK_DURING_STANDBY - // needs a special sleep mode to get accurate measurements - // quickly ... full power-down ends up using more power - // overall, and causes some weird issues when the MCU - // doesn't stay awake enough cycles to complete a reading - if (adc_active_now) - set_sleep_mode(SLEEP_MODE_ADC); + // needs a special sleep mode during measurements + if (adc_active_now) adc_sleep_mode(); else #endif set_sleep_mode(SLEEP_MODE_PWR_DOWN); -- cgit v1.2.3 From 3e09391f597b64a7ef6e023111499f5ad73e10bf Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 26 Apr 2023 01:39:28 -0600 Subject: change channel mode per config step in channel mode menu (to show which channel mode is being edited) also, avoid setting channel mode again if it's not going to change (this prevents unnecessary flickering) --- spaghetti-monster/anduril/cfg-emisar-2ch.h | 1 + spaghetti-monster/anduril/channel-modes.c | 8 +++++++- spaghetti-monster/anduril/config-mode.c | 26 +++++++++++++++++++++----- spaghetti-monster/anduril/config-mode.h | 5 +++++ 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-emisar-2ch.h b/spaghetti-monster/anduril/cfg-emisar-2ch.h index 69e1524..4704072 100644 --- a/spaghetti-monster/anduril/cfg-emisar-2ch.h +++ b/spaghetti-monster/anduril/cfg-emisar-2ch.h @@ -27,6 +27,7 @@ //#define FACTORY_RESET_WARN_CHANNEL CM_CH2 //#define FACTORY_RESET_SUCCESS_CHANNEL CM_BOTH +#define USE_CONFIG_COLORS //#define CONFIG_WAITING_CHANNEL CM_CH2 //#define CONFIG_BLINK_CHANNEL CM_BOTH diff --git a/spaghetti-monster/anduril/channel-modes.c b/spaghetti-monster/anduril/channel-modes.c index b2985a1..76cbf7e 100644 --- a/spaghetti-monster/anduril/channel-modes.c +++ b/spaghetti-monster/anduril/channel-modes.c @@ -146,12 +146,18 @@ void channel_mode_config_save(uint8_t step, uint8_t value) { } uint8_t channel_mode_config_state(Event event, uint16_t arg) { + uint8_t ret; + // make config steps match channel modes + config_color_per_step = true; // 1 menu item per channel mode, to enable or disable that mode - return config_state_base( + ret = config_state_base( event, arg, NUM_CHANNEL_MODES, channel_mode_config_save ); + // no other menu needs this + config_color_per_step = false; + return ret; } #endif diff --git a/spaghetti-monster/anduril/config-mode.c b/spaghetti-monster/anduril/config-mode.c index 394998a..b8b3398 100644 --- a/spaghetti-monster/anduril/config-mode.c +++ b/spaghetti-monster/anduril/config-mode.c @@ -12,6 +12,13 @@ uint8_t number_entry_state(Event event, uint16_t arg); volatile uint8_t number_entry_value; +#if defined(USE_CONFIG_COLORS) && (NUM_CHANNEL_MODES > 1) +void set_chan_if(bool cond, uint8_t chan) { + if ((cond) && (chan != cfg.channel_mode)) + set_channel_mode(chan); +} +#endif + // allow the user to set a new value for a config option // can be called two ways: // - with a "click" action: Configures first menu item only. @@ -33,7 +40,7 @@ uint8_t config_state_base( static uint8_t orig_channel; #endif if (event == EV_enter_state) { - #ifdef USE_CONFIG_COLORS + #if defined(USE_CONFIG_COLORS) && (NUM_CHANNEL_MODES > 1) orig_channel = cfg.channel_mode; #endif config_step = 0; @@ -52,12 +59,17 @@ uint8_t config_state_base( #define B_ANY_HOLD_RELEASE (B_CLICK|B_HOLD|B_RELEASE|B_TIMEOUT) else if ((event & B_CLICK_FLAGS) == B_ANY_HOLD) { if (config_step <= num_config_steps) { + #if defined(USE_CONFIG_COLORS) && (NUM_CHANNEL_MODES > 1) + uint8_t chan = config_step - 1; + if (chan < NUM_CHANNEL_MODES) + set_chan_if(config_color_per_step, chan); + #endif if ((TICKS_PER_SECOND/10) == (arg % (TICKS_PER_SECOND*3/2))) { config_step ++; // blink when config step advances if (config_step <= num_config_steps) { #ifdef CONFIG_BLINK_CHANNEL - set_channel_mode(CONFIG_BLINK_CHANNEL); + set_chan_if(!config_color_per_step, CONFIG_BLINK_CHANNEL); #endif set_level(RAMP_SIZE * 3 / 8); } @@ -65,7 +77,7 @@ uint8_t config_state_base( else { // stay on at a low level to indicate menu is active #ifdef CONFIG_WAITING_CHANNEL - set_channel_mode(CONFIG_WAITING_CHANNEL); + set_chan_if(!config_color_per_step, CONFIG_WAITING_CHANNEL); #endif set_level(RAMP_SIZE * 1 / 8); } @@ -79,6 +91,10 @@ uint8_t config_state_base( else if ((event & B_CLICK_FLAGS) == B_ANY_HOLD_RELEASE) { // ask the user for a number, if they selected a menu item if (config_step && config_step <= num_config_steps) { + #if defined(USE_CONFIG_COLORS) && (NUM_CHANNEL_MODES > 1) + // put the colors back how they were + set_channel_mode(orig_channel); + #endif push_state(number_entry_state, 0); } // exit after falling out of end of menu @@ -96,7 +112,7 @@ uint8_t config_state_base( pop_state(); } - #ifdef USE_CONFIG_COLORS + #if defined(USE_CONFIG_COLORS) && (NUM_CHANNEL_MODES > 1) else if (event == EV_leave_state) { // put the colors back how they were set_channel_mode(orig_channel); @@ -140,7 +156,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { // except first frame (so we can see flashes after each click)) else if (arg) { #ifdef CONFIG_WAITING_CHANNEL - set_channel_mode(CONFIG_WAITING_CHANNEL); + set_chan_if(1, CONFIG_WAITING_CHANNEL); #endif set_level( (RAMP_SIZE/8) + ((arg&2)<<2) ); diff --git a/spaghetti-monster/anduril/config-mode.h b/spaghetti-monster/anduril/config-mode.h index 388c0a2..d4a7652 100644 --- a/spaghetti-monster/anduril/config-mode.h +++ b/spaghetti-monster/anduril/config-mode.h @@ -9,6 +9,11 @@ #define USE_CONFIG_COLORS #endif +#if NUM_CHANNEL_MODES > 1 +// when true, changes the channel mode for each config step +bool config_color_per_step = false; +#endif + // config menu uint8_t config_state_base( Event event, -- cgit v1.2.3 From e84d6a51cc3c52e95af1267f6013f3410de09484 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 26 Apr 2023 01:41:39 -0600 Subject: whitespace cleanup --- spaghetti-monster/fsm-misc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spaghetti-monster/fsm-misc.c b/spaghetti-monster/fsm-misc.c index 626ad43..5a8a9fc 100644 --- a/spaghetti-monster/fsm-misc.c +++ b/spaghetti-monster/fsm-misc.c @@ -184,7 +184,7 @@ void button_led_set(uint8_t lvl) { break; #else - + case 0: // LED off BUTTON_LED_DDR &= 0xff ^ (1 << BUTTON_LED_PIN); BUTTON_LED_PUE &= 0xff ^ (1 << BUTTON_LED_PIN); @@ -214,7 +214,7 @@ void rgb_led_set(uint8_t value) { uint8_t lvl = (value >> (i<<1)) & 0x03; uint8_t pin = pins[i]; switch (lvl) { - + #ifdef AVRXMEGA3 // ATTINY816, 817, etc case 0: // LED off @@ -232,7 +232,7 @@ void rgb_led_set(uint8_t value) { break; #else - + case 0: // LED off AUXLED_RGB_DDR &= 0xff ^ (1 << pin); AUXLED_RGB_PUE &= 0xff ^ (1 << pin); @@ -248,8 +248,8 @@ void rgb_led_set(uint8_t value) { AUXLED_RGB_PUE |= (1 << pin); AUXLED_RGB_PORT |= (1 << pin); break; - - #endif // MCU type + + #endif // MCU type } } } -- cgit v1.2.3 From 688387a75413fe8213ac1bf1458176ddaa7df0ae Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 27 Apr 2023 04:26:03 -0600 Subject: Noctigon KR4-tintramp updated to use new channel system (was easy since it just uses the generic Emisar-2ch build with a couple small overrides) --- hwdef-Noctigon_KR4-tintramp.h | 47 ---------------------- hwdef-noctigon-kr4-2ch.h | 47 ++++++++++++++++++++++ spaghetti-monster/anduril/cfg-noctigon-kr4-2ch.h | 16 ++++++++ .../anduril/cfg-noctigon-kr4-tintramp.h | 16 -------- 4 files changed, 63 insertions(+), 63 deletions(-) delete mode 100644 hwdef-Noctigon_KR4-tintramp.h create mode 100644 hwdef-noctigon-kr4-2ch.h create mode 100644 spaghetti-monster/anduril/cfg-noctigon-kr4-2ch.h delete mode 100644 spaghetti-monster/anduril/cfg-noctigon-kr4-tintramp.h diff --git a/hwdef-Noctigon_KR4-tintramp.h b/hwdef-Noctigon_KR4-tintramp.h deleted file mode 100644 index 78a4d6b..0000000 --- a/hwdef-Noctigon_KR4-tintramp.h +++ /dev/null @@ -1,47 +0,0 @@ -// Noctigon KR4 w/ tint ramping -// Copyright (C) 2021-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * (same driver as D4Sv2-tintramp, but with the switch on a different pin) - * - * Pin / Name / Function - * 1 PA6 2nd LED PWM (linear) (PWM1B) - * 2 PA5 R: red aux LED (PWM0B) - * 3 PA4 G: green aux LED - * 4 PA3 B: blue aux LED - * 5 PA2 button LED - * 6 PA1 Opamp 2 enable (2nd LEDs) - * 7 PA0 Opamp 1 enable (main LEDs) - * 8 GND GND - * 9 VCC VCC - * 10 PC5 (none) - * 11 PC4 (none) - * 12 PC3 RESET - * 13 PC2 (none) - * 14 PC1 SCK - * 15 PC0 main LED PWM (FET) (PWM0A) (unused on some models because tint ramping) - * 16 PB3 main LED PWM (linear) (PWM1A) - * 17 PB2 MISO / e-switch (PCINT10) - * 18 PB1 MOSI / battery voltage (ADC6) - * 19 PB0 (none) - * 20 PA7 (none) - * ADC12 thermal sensor - */ - -#define ATTINY 1634 -#include - -// move the switch to a different pin -#define SWITCH_PIN PB2 // pin 17 -#define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt -#define SWITCH_PCIE PCIE1 // PCIE1 is for PCINT[11:8] -#define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] -#define SWITCH_PORT PINB // PINA or PINB or PINC -#define SWITCH_PUE PUEB // pullup group B -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] - -// the rest of the config is the same as D4Sv2-tintramp -#include "hwdef-Emisar_D4Sv2-tintramp.h" - diff --git a/hwdef-noctigon-kr4-2ch.h b/hwdef-noctigon-kr4-2ch.h new file mode 100644 index 0000000..a450693 --- /dev/null +++ b/hwdef-noctigon-kr4-2ch.h @@ -0,0 +1,47 @@ +// Noctigon KR4 w/ tint ramping +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * (same driver as emisar-2ch, but with the switch on a different pin) + * + * Pin / Name / Function + * 1 PA6 2nd LED PWM (linear) (PWM1B) + * 2 PA5 R: red aux LED (PWM0B) + * 3 PA4 G: green aux LED + * 4 PA3 B: blue aux LED + * 5 PA2 button LED + * 6 PA1 Opamp 2 enable (2nd LEDs) + * 7 PA0 Opamp 1 enable (main LEDs) + * 8 GND GND + * 9 VCC VCC + * 10 PC5 (none) + * 11 PC4 (none) + * 12 PC3 RESET + * 13 PC2 (none) + * 14 PC1 SCK + * 15 PC0 main LED PWM (FET) (PWM0A) (unused on some models because tint ramping) + * 16 PB3 main LED PWM (linear) (PWM1A) + * 17 PB2 MISO / e-switch (PCINT10) + * 18 PB1 MOSI / battery voltage (ADC6) + * 19 PB0 (none) + * 20 PA7 (none) + * ADC12 thermal sensor + */ + +#define ATTINY 1634 +#include + +// move the switch to a different pin +#define SWITCH_PIN PB2 // pin 17 +#define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt +#define SWITCH_PCIE PCIE1 // PCIE1 is for PCINT[11:8] +#define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] +#define SWITCH_PORT PINB // PINA or PINB or PINC +#define SWITCH_PUE PUEB // pullup group B +#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] + +// the rest of the config is the same as the generic Emisar 2ch build +#include "hwdef-emisar-2ch.h" + diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-2ch.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-2ch.h new file mode 100644 index 0000000..09dd604 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-2ch.h @@ -0,0 +1,16 @@ +// Noctigon KR4 2-channel config options for Anduril +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// (basically the same as Emisar generic 2-channel build, +// but switch on a different pin, and no lighted button) +// ATTINY: 1634 +#include "hwdef-noctigon-kr4-2ch.h" +#include "cfg-emisar-2ch.h" +#undef MODEL_NUMBER +#define MODEL_NUMBER "0215" + +// the button doesn't light up +#undef USE_BUTTON_LED + diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-tintramp.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-tintramp.h deleted file mode 100644 index c36df47..0000000 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4-tintramp.h +++ /dev/null @@ -1,16 +0,0 @@ -// Noctigon KR4 tint-ramping config options for Anduril -// Copyright (C) 2021-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -// (basically the same as Emisar D4S V2 tint-ramping, -// but switch on a different pin, and no lighted button) -// ATTINY: 1634 -#include "hwdef-Noctigon_KR4-tintramp.h" -#include "cfg-emisar-d4sv2-tintramp.h" -#undef MODEL_NUMBER -#define MODEL_NUMBER "0215" - -// the button doesn't light up -#undef USE_BUTTON_LED - -- cgit v1.2.3 From 723437e28500d728b0779a75e67eaaaa2740c6f6 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 27 Apr 2023 04:27:09 -0600 Subject: tactical mode: use police strobe by default, if it exists --- spaghetti-monster/anduril/tactical-mode.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/tactical-mode.h b/spaghetti-monster/anduril/tactical-mode.h index 8972202..4e14658 100644 --- a/spaghetti-monster/anduril/tactical-mode.h +++ b/spaghetti-monster/anduril/tactical-mode.h @@ -5,8 +5,12 @@ #pragma once #ifndef TACTICAL_LEVELS -// high, low, tactical strobe -#define TACTICAL_LEVELS 120,30,(RAMP_SIZE+2) + // high, low, tactical strobe + #ifdef USE_POLICE_COLOR_STROBE_MODE + #define TACTICAL_LEVELS 120,30,(RAMP_SIZE+3) + #else + #define TACTICAL_LEVELS 120,30,(RAMP_SIZE+2) + #endif #endif // tactical(ish) mode -- cgit v1.2.3 From 8b77e295c448d7f5ecc2cb34829f84dac648ce2b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 28 Apr 2023 02:47:45 -0600 Subject: only use 2-color strobe in tactical mode if it's on main LEDs, not aux --- spaghetti-monster/anduril/tactical-mode.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/tactical-mode.h b/spaghetti-monster/anduril/tactical-mode.h index 4e14658..528a796 100644 --- a/spaghetti-monster/anduril/tactical-mode.h +++ b/spaghetti-monster/anduril/tactical-mode.h @@ -6,9 +6,12 @@ #ifndef TACTICAL_LEVELS // high, low, tactical strobe - #ifdef USE_POLICE_COLOR_STROBE_MODE + // only do color strobe here if it's main LEDs, not aux LEDs + #if defined(USE_POLICE_COLOR_STROBE_MODE) && !defined(POLICE_STROBE_USES_AUX) + // 2-color police style strobe #define TACTICAL_LEVELS 120,30,(RAMP_SIZE+3) #else + // regular tactical strobe (1 color) #define TACTICAL_LEVELS 120,30,(RAMP_SIZE+2) #endif #endif -- cgit v1.2.3 From 76bcb0bd6c75d729f0a0eb169399ffab93ea50d6 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 28 Apr 2023 02:52:42 -0600 Subject: changed lockout RGB aux default to blinking voltage, instead of blinking disco --- spaghetti-monster/anduril/aux-leds.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/aux-leds.h b/spaghetti-monster/anduril/aux-leds.h index 2e656dc..8a79cfb 100644 --- a/spaghetti-monster/anduril/aux-leds.h +++ b/spaghetti-monster/anduril/aux-leds.h @@ -39,7 +39,8 @@ const PROGMEM uint8_t rgb_led_colors[] = { //#define RGB_LED_OFF_DEFAULT 0x18 // low, rainbow #endif #ifndef RGB_LED_LOCKOUT_DEFAULT -#define RGB_LED_LOCKOUT_DEFAULT 0x37 // blinking, disco +#define RGB_LED_LOCKOUT_DEFAULT 0x39 // blinking, voltage +//#define RGB_LED_LOCKOUT_DEFAULT 0x37 // blinking, disco #endif #ifndef RGB_RAINBOW_SPEED #define RGB_RAINBOW_SPEED 0x0f // change color every 16 frames -- cgit v1.2.3 From f34fe6dad847f4a8f1e10739d55adb35ba3e185b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 28 Apr 2023 03:03:42 -0600 Subject: RGB aux: always preview in high mode, and show voltage during 3-second post-off period --- spaghetti-monster/anduril/aux-leds.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/spaghetti-monster/anduril/aux-leds.c b/spaghetti-monster/anduril/aux-leds.c index 5ac92a3..237390c 100644 --- a/spaghetti-monster/anduril/aux-leds.c +++ b/spaghetti-monster/anduril/aux-leds.c @@ -101,11 +101,14 @@ void rgb_led_update(uint8_t mode, uint16_t arg) { uint8_t pattern = (mode>>4); // off, low, high, blinking, ... more? uint8_t color = mode & 0x0f; - // preview in blinking mode is awkward... use high instead - if ((! go_to_standby) && (pattern > 2)) { pattern = 2; } + // always preview in high mode + if (! go_to_standby) { pattern = 2; } - // use high mode for a few seconds after initial poweroff - if (arg < (SLEEP_TICKS_PER_SECOND*3)) pattern = 2; + // use voltage high mode for a few seconds after initial poweroff + else if (arg < (SLEEP_TICKS_PER_SECOND*3)) { + pattern = 2; + color = RGB_LED_NUM_COLORS - 1; + } const uint8_t *colors = rgb_led_colors; uint8_t actual_color = 0; -- cgit v1.2.3 From becb1525aadc1039a99ecdc6f7ae5cf3a1beb2fb Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 28 Apr 2023 03:06:22 -0600 Subject: D4v2 FET+1 model: works again, and now uses dynamic PWM (lower lows) (also added generic channel modes for RGB aux LEDs) --- hwdef-Emisar_D4v2.h | 129 ------------------- hwdef-emisar-d4v2.c | 45 +++++++ hwdef-emisar-d4v2.h | 185 ++++++++++++++++++++++++++++ spaghetti-monster/anduril/cfg-emisar-d4v2.h | 60 ++++++--- spaghetti-monster/chan-rgbaux.c | 19 +++ spaghetti-monster/chan-rgbaux.h | 11 ++ 6 files changed, 302 insertions(+), 147 deletions(-) delete mode 100644 hwdef-Emisar_D4v2.h create mode 100644 hwdef-emisar-d4v2.c create mode 100644 hwdef-emisar-d4v2.h create mode 100644 spaghetti-monster/chan-rgbaux.c create mode 100644 spaghetti-monster/chan-rgbaux.h diff --git a/hwdef-Emisar_D4v2.h b/hwdef-Emisar_D4v2.h deleted file mode 100644 index 2864cd4..0000000 --- a/hwdef-Emisar_D4v2.h +++ /dev/null @@ -1,129 +0,0 @@ -// hwdef for Emisar D4v2 (attiny1634) -// Copyright (C) 2018 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * Pin / Name / Function - * 1 PA6 FET PWM (PWM1B) - * 2 PA5 red aux LED (PWM0B) - * 3 PA4 green aux LED - * 4 PA3 blue aux LED - * 5 PA2 e-switch - * 6 PA1 button LED - * 7 PA0 (none) - * 8 GND GND - * 9 VCC VCC - * 10 PC5 (none) - * 11 PC4 (none) - * 12 PC3 RESET - * 13 PC2 (none) - * 14 PC1 SCK - * 15 PC0 (none) PWM0A - * 16 PB3 7135 PWM (PWM1A) - * 17 PB2 MISO - * 18 PB1 MOSI - * 19 PB0 (none) - * 20 PA7 (none) - * ADC12 thermal sensor - */ - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1634 -#include - -// TODO: add aux red and aux blue as disabled channel modes, -// so they can be used for the police strobe? -#define NUM_CHANNEL_MODES 1 -#define DEFAULT_CHANNEL_MODE 0 -#define SET_LEVEL_MODES set_level_2ch_stacked -#define GRADUAL_TICK_MODES gradual_tick_2ch_stacked -// no special handlers needed, can use common handlers -#define USE_SET_LEVEL_2CH_STACKED -#define USE_GRADUAL_TICK_2CH_STACKED - -#define PWM_CHANNELS 2 - -#define SWITCH_PIN PA2 // pin 5 -#define SWITCH_PCINT PCINT2 // pin 5 pin change interrupt -#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] -#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] -#define SWITCH_PORT PINA // PINA or PINB or PINC - -#define LOW_PWM_PIN PB3 // pin 16, 1x7135 PWM -#define LOW_PWM_LVL OCR1A // OCR1A is the output compare register for PB3 -#define PWM1_BITS 8 - -#define HIGH_PWM_PIN PA6 // pin 1, FET PWM -#define HIGH_PWM_LVL OCR1B // OCR1B is the output compare register for PB1 -#define PWM2_BITS 8 - -// only using 8-bit on this light -#define PWM_GET PWM_GET8 -#define PWM_DATATYPE uint8_t - -#define ADC_PRSCL 0x07 // clk/128 - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 4 // add 0.20V (measured 0.22V) -#endif - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -#define BUTTON_LED_PIN PA1 // pin 6 -#define BUTTON_LED_PORT PORTA // for all "PA" pins -#define BUTTON_LED_DDR DDRA // for all "PA" pins -#define BUTTON_LED_PUE PUEA // for all "PA" pins - -// this light has three aux LED channels: R, G, B -#define USE_AUX_RGB_LEDS -// it also has an independent LED in the button -#define USE_BUTTON_LED -// the aux LEDs are front-facing, so turn them off while main LEDs are on -// TODO: the whole "indicator LED" thing needs to be refactored into -// "aux LED(s)" and "button LED(s)" since they work a bit differently -#ifdef USE_INDICATOR_LED_WHILE_RAMPING -#undef USE_INDICATOR_LED_WHILE_RAMPING -#endif - -inline void hwdef_setup() { - // enable output ports - // 7135 - DDRB = (1 << LOW_PWM_PIN); - // FET, aux R/G/B, button LED - DDRA = (1 << HIGH_PWM_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - | (1 << BUTTON_LED_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - TCCR1A = (0< (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; + } +} + +bool gradual_tick_stacked(uint8_t gt) { + GRADUAL_TICK_SETUP(); + + GRADUAL_ADJUST(pwm1_levels, LOW_PWM_LVL, PWM_TOP_INIT); + GRADUAL_ADJUST_1CH(pwm2_levels, HIGH_PWM_LVL); + + // did we go far enough to hit the next defined ramp level? + // if so, update the main ramp level tracking var + if ( (LOW_PWM_LVL == PWM_GET(pwm1_levels, gt)) + && (HIGH_PWM_LVL == PWM_GET(pwm2_levels, gt)) + ) { + return true; + } + return false; +} + diff --git a/hwdef-emisar-d4v2.h b/hwdef-emisar-d4v2.h new file mode 100644 index 0000000..96d4052 --- /dev/null +++ b/hwdef-emisar-d4v2.h @@ -0,0 +1,185 @@ +// hwdef for Emisar D4v2 (attiny1634) +// Copyright (C) 2018 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * Pin / Name / Function + * 1 PA6 FET PWM (PWM1B) + * 2 PA5 red aux LED (PWM0B) + * 3 PA4 green aux LED + * 4 PA3 blue aux LED + * 5 PA2 e-switch + * 6 PA1 button LED + * 7 PA0 (none) + * 8 GND GND + * 9 VCC VCC + * 10 PC5 (none) + * 11 PC4 (none) + * 12 PC3 RESET + * 13 PC2 (none) + * 14 PC1 SCK + * 15 PC0 (none) PWM0A + * 16 PB3 7135 PWM (PWM1A) + * 17 PB2 MISO + * 18 PB1 MOSI + * 19 PB0 (none) + * 20 PA7 (none) + * ADC12 thermal sensor + */ + +#define ATTINY 1634 +#include + +#define HWDEF_C_FILE hwdef-emisar-d4v2.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +// channel modes: +// * 0. FET+7135 stacked +// * 1. aux red +// * 2. aux green +// * 3. aux blue +#define NUM_CHANNEL_MODES 4 +#define CM_MAIN 0 +#define CM_AUXRED 1 +#define CM_AUXGRN 2 +#define CM_AUXBLU 3 + +#define DEFAULT_CHANNEL_MODE 0 + +#define CHANNEL_MODES_ENABLED 0b00000001 +#define CHANNEL_HAS_ARGS 0b00000000 +// _, _, _, 128=middle CCT, 0=warm-to-cool +//#define CHANNEL_MODE_ARGS 0,0,0,0 + +#define USE_CHANNEL_MODES +//#define USE_CHANNEL_MODE_ARGS +#define SET_LEVEL_MODES set_level_stacked, \ + set_level_auxred, \ + set_level_auxgrn, \ + set_level_auxblu +// gradual ticking for thermal regulation +#define GRADUAL_TICK_MODES gradual_tick_stacked, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null + +// TODO: remove this when possible +#define PWM_CHANNELS 2 + +#define SWITCH_PIN PA2 // pin 5 +#define SWITCH_PCINT PCINT2 // pin 5 pin change interrupt +#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] +#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] +#define SWITCH_PORT PINA // PINA or PINB or PINC + +#define PWM_GET PWM_GET16 +#define PWM_BITS 16 +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t +#define PWM2_DATATYPE uint16_t + +// dynamic PWM +#define PWM_TOP_INIT 255 +#define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +#define LOW_PWM_PIN PB3 // pin 16, 1x7135 PWM +#define LOW_PWM_LVL OCR1A // OCR1A is the output compare register for PB3 + +#define HIGH_PWM_PIN PA6 // pin 1, FET PWM +#define HIGH_PWM_LVL OCR1B // OCR1B is the output compare register for PB1 + +#define ADC_PRSCL 0x07 // clk/128 + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 4 // add 0.20V (measured 0.22V) +#endif + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + +#define BUTTON_LED_PIN PA1 // pin 6 +#define BUTTON_LED_PORT PORTA // for all "PA" pins +#define BUTTON_LED_DDR DDRA // for all "PA" pins +#define BUTTON_LED_PUE PUEA // for all "PA" pins + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS +// it also has an independent LED in the button +#define USE_BUTTON_LED +// the aux LEDs are front-facing, so turn them off while main LEDs are on +// TODO: the whole "indicator LED" thing needs to be refactored into +// "aux LED(s)" and "button LED(s)" since they work a bit differently +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif + +// custom channel modes +void set_level_stacked(uint8_t level); + +bool gradual_tick_stacked(uint8_t gt); + + +inline void hwdef_setup() { + // enable output ports + // 7135 + DDRB = (1 << LOW_PWM_PIN); + // FET, aux R/G/B, button LED + DDRA = (1 << HIGH_PWM_PIN) + | (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + | (1 << BUTTON_LED_PIN) + ; + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // Linear opamp PWM for both main and 2nd LEDs (10-bit) + // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) + TCCR1A = (1< lvl) lvl = cfg.ramp_floors[1]; #ifdef USE_MANUAL_MEMORY if (cfg.manual_memory) lvl = cfg.manual_memory; #endif - } else { // anything except second click - if (cfg.ramp_floors[1] < lvl) lvl = cfg.ramp_floors[1]; } set_level(lvl); } @@ -65,6 +65,13 @@ uint8_t lockout_state(Event event, uint16_t arg) { #if defined(TICK_DURING_STANDBY) && (defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS)) else if (event == EV_sleep_tick) { + #ifdef USE_MANUAL_MEMORY_TIMER + // reset to manual memory level when timer expires + if (cfg.manual_memory && + (arg >= (cfg.manual_memory_timer * SLEEP_TICKS_PER_MINUTE))) { + manual_memory_restore(); + } + #endif #if defined(USE_INDICATOR_LED) indicator_led_update(cfg.indicator_led_mode >> 2, arg); #elif defined(USE_AUX_RGB_LEDS) @@ -83,8 +90,9 @@ uint8_t lockout_state(Event event, uint16_t arg) { // 4 clicks: exit and turn on else if (event == EV_4clicks) { - #ifdef USE_MANUAL_MEMORY - // FIXME: memory timer is totally ignored + #if defined(USE_MANUAL_MEMORY) && !defined(USE_MANUAL_MEMORY_TIMER) + // this clause probably isn't used by any configs any more + // but is included just in case someone configures it this way if (cfg.manual_memory) set_state(steady_state, cfg.manual_memory); else @@ -110,6 +118,16 @@ uint8_t lockout_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } + #if NUM_CHANNEL_MODES > 1 + // 3H: next channel mode + else if (event == EV_click3_hold) { + if (0 == (arg % TICKS_PER_SECOND)) { + // pretend the user clicked 3 times to change channels + return channel_mode_state(EV_3clicks, 0); + } + } + #endif + ////////// Every action below here is blocked in the (non-Extended) Simple UI ////////// #if defined(USE_SIMPLE_UI) && !defined(USE_EXTENDED_SIMPLE_UI) -- cgit v1.2.3 From eee06ae626a90a2d05aca3a2255c313f3900ed98 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 29 Apr 2023 00:44:17 -0600 Subject: just a todo note for later --- spaghetti-monster/fsm-misc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/spaghetti-monster/fsm-misc.c b/spaghetti-monster/fsm-misc.c index 5a8a9fc..80652b3 100644 --- a/spaghetti-monster/fsm-misc.c +++ b/spaghetti-monster/fsm-misc.c @@ -33,6 +33,7 @@ uint8_t blink_digit(uint8_t num) { if (!num) { ontime = 8; num ++; } for (; num>0; num--) { + // TODO: allow setting a blink channel mode per build target set_level(BLINK_BRIGHTNESS); nice_delay_ms(ontime); set_level(0); -- cgit v1.2.3 From 9765caab66ab628d763a5148efde80b3c3930b31 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 29 Apr 2023 01:19:42 -0600 Subject: Noctigon KR4: updated to use new channel system (also tweaked D4v2 build to match KR4 as much as possible) (also added Extended Simple UI to Hank's config) --- hwdef-Noctigon_KR4.h | 161 -------------------- hwdef-emisar-2ch.h | 115 +++++++-------- hwdef-emisar-d4v2.h | 79 +++++----- hwdef-noctigon-kr4.c | 51 +++++++ hwdef-noctigon-kr4.h | 212 +++++++++++++++++++++++++++ spaghetti-monster/anduril/cfg-emisar-2ch.h | 12 -- spaghetti-monster/anduril/cfg-emisar-d4v2.h | 7 +- spaghetti-monster/anduril/cfg-noctigon-kr4.h | 32 ++-- spaghetti-monster/anduril/hank-cfg.h | 8 + spaghetti-monster/fsm-ramping.h | 7 + 10 files changed, 402 insertions(+), 282 deletions(-) delete mode 100644 hwdef-Noctigon_KR4.h create mode 100644 hwdef-noctigon-kr4.c create mode 100644 hwdef-noctigon-kr4.h diff --git a/hwdef-Noctigon_KR4.h b/hwdef-Noctigon_KR4.h deleted file mode 100644 index 1c863cb..0000000 --- a/hwdef-Noctigon_KR4.h +++ /dev/null @@ -1,161 +0,0 @@ -// Noctigon KR4 / D4V2.5 driver layout (attiny1634) -// Copyright (C) 2020-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * Pin / Name / Function - * 1 PA6 FET PWM (direct drive) (PWM1B) - * 2 PA5 R: red aux LED (PWM0B) - * 3 PA4 G: green aux LED - * 4 PA3 B: blue aux LED - * 5 PA2 button LED (D4V2.5 only) - * 6 PA1 (none) - * 7 PA0 (none) - * 8 GND GND - * 9 VCC VCC - * 10 PC5 (none) - * 11 PC4 (none) - * 12 PC3 RESET - * 13 PC2 (none) - * 14 PC1 SCK - * 15 PC0 (none) PWM0A - * 16 PB3 main LED PWM (linear) (PWM1A) - * 17 PB2 MISO / e-switch (PCINT10) - * 18 PB1 MOSI / battery voltage (ADC6) - * 19 PB0 Opamp power - * 20 PA7 (none) - * ADC12 thermal sensor - * - * Main LED power uses one pin to turn the Opamp on/off, - * and one pin to control Opamp power level. - * Main brightness control uses the power level pin, with 4 kHz 10-bit PWM. - * The on/off pin is only used to turn the main LED on and off, - * not to change brightness. - * Some models also have a direct-drive FET for turbo. - */ - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1634 -#include - -#define PWM_CHANNELS 2 -#define PWM_BITS 16 // data type needs 16 bits, not 8 -#define PWM_TOP 255 // highest value used in top half of ramp -#define USE_DYN_PWM // dynamic frequency and speed - -#define SWITCH_PIN PB2 // pin 17 -#define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt -#define SWITCH_PCIE PCIE1 // PCIE1 is for PCINT[11:8] -#define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] -#define SWITCH_PORT PINB // PINA or PINB or PINC -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] - -// the button tends to short out the voltage divider, -// so ignore voltage while the button is being held -//#define NO_LVP_WHILE_BUTTON_PRESSED - - -#define PWM1_PIN PB3 // pin 16, Opamp reference -#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 -#define PWM1_CNT TCNT1 // for dynamic PWM, reset phase -#define PWM1_PHASE_RESET_OFF // force reset while shutting off -#define PWM1_PHASE_RESET_ON // force reset while turning on -#define PWM1_PHASE_SYNC // manual sync while changing level - -#define PWM2_PIN PA6 // pin 1, DD FET PWM -#define PWM2_LVL OCR1B // OCR1B is the output compare register for PA6 - -// PWM parameters of both channels are tied together because they share a counter -#define PWM1_TOP ICR1 // holds the TOP value for for variable-resolution PWM - -#define LED_ENABLE_PIN PB0 // pin 19, Opamp power -#define LED_ENABLE_PORT PORTB // control port for PB0 - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -#define BUTTON_LED_PIN PA2 // pin 5 -#define BUTTON_LED_PORT PORTA // for all "PA" pins -#define BUTTON_LED_DDR DDRA // for all "PA" pins -#define BUTTON_LED_PUE PUEA // for all "PA" pins - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - // enable output ports - // Opamp level and Opamp on/off - DDRB = (1 << PWM1_PIN) - | (1 << LED_ENABLE_PIN); - // DD FET PWM, aux R/G/B, button LED - DDRA = (1 << PWM2_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - | (1 << BUTTON_LED_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) - TCCR1A = (1< +#define HWDEF_C_FILE hwdef-emisar-2ch.c + +#define USE_CHANNEL_MODES // channel modes: // * 0. channel 1 only // * 1. channel 2 only @@ -48,11 +49,10 @@ #define CHANNEL_MODES_ENABLED 0b00011111 #define CHANNEL_HAS_ARGS 0b00011000 +#define USE_CHANNEL_MODE_ARGS // _, _, _, 128=middle CCT, 0=warm-to-cool #define CHANNEL_MODE_ARGS 0,0,0,128,0 -#define USE_CHANNEL_MODES -#define USE_CHANNEL_MODE_ARGS #define SET_LEVEL_MODES set_level_ch1, \ set_level_ch2, \ set_level_both, \ @@ -70,7 +70,7 @@ #define PWM_CHANNELS 1 // old, remove this -#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz +#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz #define PWM_GET PWM_GET16 #define PWM_DATATYPE uint16_t #define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 @@ -80,7 +80,7 @@ // PWM parameters of both channels are tied together because they share a counter #define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM -#define PWM_TOP_INIT 511 +#define PWM_TOP_INIT 511 // highest value used in top half of ramp #define PWM_CNT TCNT1 // for dynamic PWM, reset phase #define CH1_PIN PB3 // pin 16, Opamp reference @@ -96,7 +96,7 @@ //#define CH3_PIN PC0 // pin 15, DD FET PWM //#define CH3_LVL OCR0A // OCR0A is the output compare register for PC0 - +// e-switch #ifndef SWITCH_PIN #define SWITCH_PIN PA7 // pin 20 #define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt @@ -164,59 +164,58 @@ bool gradual_tick_blend(uint8_t gt); bool gradual_tick_auto(uint8_t gt); -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead inline void hwdef_setup() { - // enable output ports - //DDRC = (1 << CH3_PIN); - DDRB = (1 << CH1_PIN); - DDRA = (1 << CH2_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - | (1 << BUTTON_LED_PIN) - | (1 << CH1_ENABLE_PIN) - | (1 << CH2_ENABLE_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // Linear opamp PWM for both main and 2nd LEDs (10-bit) - // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) - TCCR1A = (1< (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE pwm2 = PWM_GET(pwm2_levels, gt); + + GRADUAL_ADJUST_STACKED(pwm1, CH1_PWM, PWM_TOP_INIT); + GRADUAL_ADJUST_SIMPLE (pwm2, CH2_PWM); + + if ( (pwm1 == CH1_PWM) + && (pwm2 == CH2_PWM) + ) { + return true; // done + } + return false; // not done yet +} + diff --git a/hwdef-noctigon-kr4.h b/hwdef-noctigon-kr4.h new file mode 100644 index 0000000..8caf262 --- /dev/null +++ b/hwdef-noctigon-kr4.h @@ -0,0 +1,212 @@ +// Noctigon KR4 / D4V2.5 driver layout (attiny1634) +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * Pin / Name / Function + * 1 PA6 FET PWM (direct drive) (PWM1B) + * 2 PA5 R: red aux LED (PWM0B) + * 3 PA4 G: green aux LED + * 4 PA3 B: blue aux LED + * 5 PA2 button LED (D4V2.5 only) + * 6 PA1 (none) + * 7 PA0 (none) + * 8 GND GND + * 9 VCC VCC + * 10 PC5 (none) + * 11 PC4 (none) + * 12 PC3 RESET + * 13 PC2 (none) + * 14 PC1 SCK + * 15 PC0 (none) PWM0A + * 16 PB3 main LED PWM (linear) (PWM1A) + * 17 PB2 MISO / e-switch (PCINT10) + * 18 PB1 MOSI / battery voltage (ADC6) + * 19 PB0 Opamp power + * 20 PA7 (none) + * ADC12 thermal sensor + * + * Main LED power uses one pin to turn the Opamp on/off, + * and one pin to control Opamp power level. + * The on/off pin is only used to turn the main LED on and off, + * not to change brightness. + * Some models also have a direct-drive FET for turbo. + */ + +#define ATTINY 1634 +#include + +#define HWDEF_C_FILE hwdef-noctigon-kr4.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +#define USE_CHANNEL_MODES +// channel modes: +// * 0. linear + DD FET stacked +// * 1. aux red +// * 2. aux green +// * 3. aux blue +#define NUM_CHANNEL_MODES 4 +#define CM_MAIN 0 +#define CM_AUXRED 1 +#define CM_AUXGRN 2 +#define CM_AUXBLU 3 + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +#define CHANNEL_MODES_ENABLED 0b00000001 +#define CHANNEL_HAS_ARGS 0b00000000 +// no args +//#define USE_CHANNEL_MODE_ARGS +//#define CHANNEL_MODE_ARGS 0,0,0,0 + +#define SET_LEVEL_MODES set_level_main, \ + set_level_auxred, \ + set_level_auxgrn, \ + set_level_auxblu +// gradual ticking for thermal regulation +#define GRADUAL_TICK_MODES gradual_tick_main, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // linear ramp +#define PWM2_DATATYPE uint16_t // DD FET ramp + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 255 // highest value used in top half of ramp +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +// linear channel +#define CH1_PIN PB3 // pin 16, Opamp reference +#define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 +#define CH1_ENABLE_PIN PB0 // pin 19, Opamp power +#define CH1_ENABLE_PORT PORTB // control port for PB0 +// TODO: remove these +#define PWM1_PHASE_RESET_OFF // force reset while shutting off +#define PWM1_PHASE_RESET_ON // force reset while turning on +#define PWM1_PHASE_SYNC // manual sync while changing level + +// DD FET channel +#define CH2_PIN PA6 // pin 1, DD FET PWM +#define CH2_PWM OCR1B // OCR1B is the output compare register for PA6 + +// e-switch +#define SWITCH_PIN PB2 // pin 17 +#define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt +#define SWITCH_PCIE PCIE1 // PCIE1 is for PCINT[11:8] +#define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] +#define SWITCH_PORT PINB // PINA or PINB or PINC +#define SWITCH_PUE PUEB // pullup group B +#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] + +// the button tends to short out the voltage divider, +// so ignore voltage while the button is being held +//#define NO_LVP_WHILE_BUTTON_PRESSED + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 +// pin to ADC mappings are in DS table 19-4 +#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 +// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 +#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D +// DS tables 19-3, 19-4 +// Bit 7 6 5 4 3 2 1 0 +// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 +// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 +// divided by ... +// REFS[1:0] = 1, 0 for internal 1.1V reference +// other bits reserved +#define ADMUX_VOLTAGE_DIVIDER 0b10000110 +#define ADC_PRSCL 0x07 // clk/128 + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// D1, R1, R2 = 0, 330, 100 +#ifndef ADC_44 +//#define ADC_44 981 // raw value at 4.40V +#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 +#endif +#ifndef ADC_22 +//#define ADC_22 489 // raw value at 2.20V +#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 +#endif + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + +#define BUTTON_LED_PIN PA2 // pin 5 +#define BUTTON_LED_PORT PORTA // for all "PA" pins +#define BUTTON_LED_DDR DDRA // for all "PA" pins +#define BUTTON_LED_PUE PUEA // for all "PA" pins + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS +// some variants also have an independent LED in the button +#define USE_BUTTON_LED +// the aux LEDs are front-facing, so turn them off while main LEDs are on +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif + +void set_level_main(uint8_t level); + +bool gradual_tick_main(uint8_t gt); + + +inline void hwdef_setup() { + // enable output ports + // Opamp level and Opamp on/off + DDRB = (1 << CH1_PIN) + | (1 << CH1_ENABLE_PIN); + // DD FET PWM, aux R/G/B, button LED + DDRA = (1 << CH2_PIN) + | (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + | (1 << BUTTON_LED_PIN) + ; + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) + TCCR1A = (1< TARGET) PWM --; +// tick to a specific value, except when immediate 0 to 255 is needed +#define GRADUAL_ADJUST_STACKED(TARGET,PWM,TOP) \ + if ( ((PWM == 0) && (TARGET == TOP)) \ + || ((PWM == TOP) && (TARGET == 0))) \ + PWM = TOP; \ + else GRADUAL_ADJUST_SIMPLE(TARGET,PWM) + // tick the top layer of the stack #define GRADUAL_ADJUST_1CH(TABLE,PWM) \ target = PWM_GET(TABLE, gt); \ -- cgit v1.2.3 From 71929d68d210a26ac12bd53299cc0a52fcfafdbf Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 29 Apr 2023 01:21:51 -0600 Subject: missed this file on previous commit --- hwdef-emisar-d4v2.c | 55 ++++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/hwdef-emisar-d4v2.c b/hwdef-emisar-d4v2.c index dce6c92..9b647a3 100644 --- a/hwdef-emisar-d4v2.c +++ b/hwdef-emisar-d4v2.c @@ -7,39 +7,42 @@ #include "chan-rgbaux.c" // single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear -void set_level_stacked(uint8_t level) { +void set_level_main(uint8_t level) { if (level == 0) { - LOW_PWM_LVL = 0; - HIGH_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - } else { - level --; // PWM array index = level - 1 - LOW_PWM_LVL = PWM_GET(pwm1_levels, level); - HIGH_PWM_LVL = PWM_GET(pwm2_levels, level); - // pulse frequency modulation, a.k.a. dynamic PWM - uint16_t top = PWM_GET(pwm_tops, level); - // wait to sync the counter and avoid flashes - while(actual_level && (PWM_CNT > (top - 32))) {} - PWM_TOP = top; - // force reset phase when turning on from zero - // (because otherwise the initial response is inconsistent) - if (! actual_level) PWM_CNT = 0; + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; // reset phase + return; } + + level --; // PWM array index = level - 1 + PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); + PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET(pwm_tops, level); + + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; + // wait to sync the counter and avoid flashes + while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; } -bool gradual_tick_stacked(uint8_t gt) { - GRADUAL_TICK_SETUP(); +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE pwm2 = PWM_GET(pwm2_levels, gt); - GRADUAL_ADJUST(pwm1_levels, LOW_PWM_LVL, PWM_TOP_INIT); - GRADUAL_ADJUST_1CH(pwm2_levels, HIGH_PWM_LVL); + GRADUAL_ADJUST_STACKED(pwm1, CH1_PWM, PWM_TOP_INIT); + GRADUAL_ADJUST_SIMPLE (pwm2, CH2_PWM); - // did we go far enough to hit the next defined ramp level? - // if so, update the main ramp level tracking var - if ( (LOW_PWM_LVL == PWM_GET(pwm1_levels, gt)) - && (HIGH_PWM_LVL == PWM_GET(pwm2_levels, gt)) + if ( (pwm1 == CH1_PWM) + && (pwm2 == CH2_PWM) ) { - return true; + return true; // done } - return false; + return false; // not done yet } -- cgit v1.2.3 From 0c88040fa1c2f3ffd5f6b6f6f5b12f5bd2193b06 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 29 Apr 2023 01:45:00 -0600 Subject: KR4: ramp can use 8 bits, since values never go over 255 also, don't blink at top of linear range --- hwdef-noctigon-kr4.c | 2 +- hwdef-noctigon-kr4.h | 12 ++++++------ spaghetti-monster/anduril/cfg-noctigon-kr4.h | 5 +++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/hwdef-noctigon-kr4.c b/hwdef-noctigon-kr4.c index bcb98fc..5813a9b 100644 --- a/hwdef-noctigon-kr4.c +++ b/hwdef-noctigon-kr4.c @@ -22,7 +22,7 @@ void set_level_main(uint8_t level) { PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); // pulse frequency modulation, a.k.a. dynamic PWM - uint16_t top = PWM_GET(pwm_tops, level); + uint16_t top = PWM_GET16(pwm_tops, level); CH1_PWM = ch1_pwm; CH2_PWM = ch2_pwm; diff --git a/hwdef-noctigon-kr4.h b/hwdef-noctigon-kr4.h index 8caf262..2e19ba4 100644 --- a/hwdef-noctigon-kr4.h +++ b/hwdef-noctigon-kr4.h @@ -75,12 +75,12 @@ #define PWM_CHANNELS 2 // old, remove this -#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz -#define PWM_GET PWM_GET16 -#define PWM_DATATYPE uint16_t -#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 -#define PWM1_DATATYPE uint16_t // linear ramp -#define PWM2_DATATYPE uint16_t // DD FET ramp +#define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // linear ramp +#define PWM2_DATATYPE uint8_t // DD FET ramp // PWM parameters of both channels are tied together because they share a counter #define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index bfecbea..78c76de 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -90,6 +90,11 @@ // the default of 26 looks a bit rough, so increase it to make it smoother #define CANDLE_AMPLITUDE 33 +// don't blink while ramping +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + // can't reset the normal way because power is connected before the button #define USE_SOFT_FACTORY_RESET -- cgit v1.2.3 From 278d58e747f5692ef614eb6605774688f85656e3 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 29 Apr 2023 01:54:19 -0600 Subject: D4v2 can use 8-bit ramp tables too --- hwdef-emisar-d4v2.c | 2 +- hwdef-emisar-d4v2.h | 12 ++++++------ hwdef-noctigon-kr4.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hwdef-emisar-d4v2.c b/hwdef-emisar-d4v2.c index 9b647a3..db32f19 100644 --- a/hwdef-emisar-d4v2.c +++ b/hwdef-emisar-d4v2.c @@ -19,7 +19,7 @@ void set_level_main(uint8_t level) { PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); // pulse frequency modulation, a.k.a. dynamic PWM - uint16_t top = PWM_GET(pwm_tops, level); + uint16_t top = PWM_GET16(pwm_tops, level); CH1_PWM = ch1_pwm; CH2_PWM = ch2_pwm; diff --git a/hwdef-emisar-d4v2.h b/hwdef-emisar-d4v2.h index aeb5b0d..e9ffe11 100644 --- a/hwdef-emisar-d4v2.h +++ b/hwdef-emisar-d4v2.h @@ -69,12 +69,12 @@ #define PWM_CHANNELS 2 // old, remove this -#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz -#define PWM_GET PWM_GET16 -#define PWM_DATATYPE uint16_t -#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 -#define PWM1_DATATYPE uint16_t // linear ramp -#define PWM2_DATATYPE uint16_t // DD FET ramp +#define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // linear ramp +#define PWM2_DATATYPE uint8_t // DD FET ramp // PWM parameters of both channels are tied together because they share a counter #define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM diff --git a/hwdef-noctigon-kr4.h b/hwdef-noctigon-kr4.h index 2e19ba4..b20effc 100644 --- a/hwdef-noctigon-kr4.h +++ b/hwdef-noctigon-kr4.h @@ -77,7 +77,7 @@ #define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 #define PWM_GET PWM_GET8 -#define PWM_DATATYPE uint16_t // is used for PWM_TOPS +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) #define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 #define PWM1_DATATYPE uint8_t // linear ramp #define PWM2_DATATYPE uint8_t // DD FET ramp -- cgit v1.2.3 From 882567cd08e15d73aee0802fd1b1c31076801a02 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 29 Apr 2023 02:50:03 -0600 Subject: converted KR4-nofet build --- hwdef-noctigon-kr4-nofet.c | 47 ++++++++++++++++++++++ hwdef-noctigon-kr4.h | 6 +-- spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h | 8 ++-- 3 files changed, 52 insertions(+), 9 deletions(-) create mode 100644 hwdef-noctigon-kr4-nofet.c diff --git a/hwdef-noctigon-kr4-nofet.c b/hwdef-noctigon-kr4-nofet.c new file mode 100644 index 0000000..ec984df --- /dev/null +++ b/hwdef-noctigon-kr4-nofet.c @@ -0,0 +1,47 @@ +// Noctigon KR4 (no DD FET) PWM helper functions +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "chan-rgbaux.c" + +// single set of LEDs with linear power channel +void set_level_main(uint8_t level) { + if (level == 0) { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; // reset phase + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp + return; + } + + CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable opamp + + level --; // PWM array index = level - 1 + PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET16(pwm_tops, level); + + CH1_PWM = ch1_pwm; + CH2_PWM = 0; + // wait to sync the counter and avoid flashes + while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + + GRADUAL_ADJUST_SIMPLE(pwm1, CH1_PWM); + + if ( (pwm1 == CH1_PWM) + ) { + return true; // done + } + return false; // not done yet +} + diff --git a/hwdef-noctigon-kr4.h b/hwdef-noctigon-kr4.h index b20effc..d6c33ff 100644 --- a/hwdef-noctigon-kr4.h +++ b/hwdef-noctigon-kr4.h @@ -37,7 +37,9 @@ #define ATTINY 1634 #include +#ifndef HWDEF_C_FILE #define HWDEF_C_FILE hwdef-noctigon-kr4.c +#endif // allow using aux LEDs as extra channel modes #include "chan-rgbaux.h" @@ -92,10 +94,6 @@ #define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 #define CH1_ENABLE_PIN PB0 // pin 19, Opamp power #define CH1_ENABLE_PORT PORTB // control port for PB0 -// TODO: remove these -#define PWM1_PHASE_RESET_OFF // force reset while shutting off -#define PWM1_PHASE_RESET_ON // force reset while turning on -#define PWM1_PHASE_SYNC // manual sync while changing level // DD FET channel #define CH2_PIN PA6 // pin 1, DD FET PWM diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h index 701d93f..6d49a8b 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-nofet.h @@ -1,10 +1,11 @@ -// Noctigon KR4 (fetless) config options for Anduril +// Noctigon KR4 (no DD FET) config options for Anduril // Copyright (C) 2020-2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once // (and Noctigon KR1) // (and Emisar D4v2 E21A, a.k.a. "D4v2.5") +#define HWDEF_C_FILE hwdef-noctigon-kr4-nofet.c #include "cfg-noctigon-kr4.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0212" @@ -16,7 +17,7 @@ // max regulated: 1740 lm #undef PWM_CHANNELS #define PWM_CHANNELS 1 -#define RAMP_LENGTH 150 +#define RAMP_SIZE 150 // prioritize low lows, at risk of visible ripple // level_calc.py 5.01 1 149 7135 1 0.3 1740 --pwm dyn:78:16384:255 #undef PWM1_LEVELS @@ -49,9 +50,6 @@ #define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL -// make candle mode wobble more -#define CANDLE_AMPLITUDE 32 - // slow down party strobe; this driver can't pulse for 1ms or less // (only needed on no-FET build) #define PARTY_STROBE_ONTIME 2 -- cgit v1.2.3 From 6b8386a4959bd0f718a47bada2cda331b9be4481 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 29 Apr 2023 07:46:19 -0600 Subject: converted Emisar D4Sv2 build, and updated it to use dynamic PWM --- hwdef-Emisar_D4Sv2.h | 123 ----------------- hwdef-emisar-d4sv2.c | 54 ++++++++ hwdef-emisar-d4sv2.h | 196 +++++++++++++++++++++++++++ hwdef-emisar-d4v2.h | 4 +- spaghetti-monster/anduril/cfg-emisar-d4sv2.h | 74 ++++++---- 5 files changed, 300 insertions(+), 151 deletions(-) delete mode 100644 hwdef-Emisar_D4Sv2.h create mode 100644 hwdef-emisar-d4sv2.c create mode 100644 hwdef-emisar-d4sv2.h diff --git a/hwdef-Emisar_D4Sv2.h b/hwdef-Emisar_D4Sv2.h deleted file mode 100644 index bd63649..0000000 --- a/hwdef-Emisar_D4Sv2.h +++ /dev/null @@ -1,123 +0,0 @@ -// Emisar D4Sv2 driver layout (attiny1634) -// Copyright (C) 2019-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * (same layout as D4v2, except it's a FET+3+1 instead of FET+1) - * - * Pin / Name / Function - * 1 PA6 FET PWM (PWM1B) - * 2 PA5 red aux LED (PWM0B) - * 3 PA4 green aux LED - * 4 PA3 blue aux LED - * 5 PA2 e-switch - * 6 PA1 (none) - * 7 PA0 (none) - * 8 GND GND - * 9 VCC VCC - * 10 PC5 (none) - * 11 PC4 (none) - * 12 PC3 RESET - * 13 PC2 (none) - * 14 PC1 SCK - * 15 PC0 3x7135 PWM (PWM0A) - * 16 PB3 1x7135 PWM (PWM1A) - * 17 PB2 MISO - * 18 PB1 MOSI - * 19 PB0 (none) - * 20 PA7 (none) - * ADC12 thermal sensor - */ - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1634 -#include - -#define SWITCH_PIN PA2 // pin 5 -#define SWITCH_PCINT PCINT2 // pin 5 pin change interrupt -#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] -#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] -#define SWITCH_PORT PINA // PINA or PINB or PINC - -#define PWM_CHANNELS 3 - -#define PWM1_PIN PB3 // pin 16, 1x7135 PWM -#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 - -#define PWM2_PIN PC0 // pin 15, 3x7135 PWM -#define PWM2_LVL OCR0A // OCR0A is the output compare register for PC0 - -#define PWM3_PIN PA6 // pin 1, FET PWM -#define PWM3_LVL OCR1B // OCR1B is the output compare register for PB1 - - -#define ADC_PRSCL 0x07 // clk/128 - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 4 // add 0.20V (measured 0.22V) -#endif - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - // enable output ports - // FET, aux R/G/B - DDRA = (1 << PWM3_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - ; - // 1x7135 - DDRB = (1 << PWM1_PIN); - // 3x7135 - DDRC = (1 << PWM2_PIN); - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // WGM1[3:0]: 0,0,0,1: PWM, Phase Correct, 8-bit (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) - TCCR1A = (0< (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE pwm2 = PWM_GET(pwm2_levels, gt); + PWM_DATATYPE pwm3 = PWM_GET(pwm3_levels, gt); + + GRADUAL_ADJUST_STACKED(pwm1, CH1_PWM, PWM_TOP_INIT); + GRADUAL_ADJUST_STACKED(pwm2, CH2_PWM, PWM_TOP_INIT); + GRADUAL_ADJUST_SIMPLE (pwm3, CH3_PWM); + + if ( (pwm1 == CH1_PWM) + && (pwm2 == CH2_PWM) + && (pwm3 == CH3_PWM) + ) { + return true; // done + } + return false; // not done yet +} + diff --git a/hwdef-emisar-d4sv2.h b/hwdef-emisar-d4sv2.h new file mode 100644 index 0000000..0607c24 --- /dev/null +++ b/hwdef-emisar-d4sv2.h @@ -0,0 +1,196 @@ +// Emisar D4Sv2 driver layout (attiny1634) +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * (same layout as D4v2, except it's a FET+3+1 instead of FET+1) + * + * Pin / Name / Function + * 1 PA6 FET PWM (PWM1B) + * 2 PA5 red aux LED (PWM0B) + * 3 PA4 green aux LED + * 4 PA3 blue aux LED + * 5 PA2 e-switch + * 6 PA1 button LED? + * 7 PA0 (none) + * 8 GND GND + * 9 VCC VCC + * 10 PC5 (none) + * 11 PC4 (none) + * 12 PC3 RESET + * 13 PC2 (none) + * 14 PC1 SCK + * 15 PC0 3x7135 PWM (PWM0A) (8-bit) + * 16 PB3 1x7135 PWM (PWM1A) + * 17 PB2 MISO + * 18 PB1 MOSI + * 19 PB0 (none) + * 20 PA7 (none) + * ADC12 thermal sensor + */ + +#define ATTINY 1634 +#include + +#define HWDEF_C_FILE hwdef-emisar-d4sv2.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +#define USE_CHANNEL_MODES +// channel modes: +// * 0. FET+3+1 stacked +// * 1. aux red +// * 2. aux green +// * 3. aux blue +#define NUM_CHANNEL_MODES 4 +#define CM_MAIN 0 +#define CM_AUXRED 1 +#define CM_AUXGRN 2 +#define CM_AUXBLU 3 + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +#define CHANNEL_MODES_ENABLED 0b00000001 +#define CHANNEL_HAS_ARGS 0b00000000 +// no args +//#define USE_CHANNEL_MODE_ARGS +//#define CHANNEL_MODE_ARGS 0,0,0,0 + +#define SET_LEVEL_MODES set_level_main, \ + set_level_auxred, \ + set_level_auxgrn, \ + set_level_auxblu +// gradual ticking for thermal regulation +#define GRADUAL_TICK_MODES gradual_tick_main, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null + + +#define PWM_CHANNELS 3 // old, remove this + +#define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // 1x7135 ramp (16-bit) +#define PWM2_DATATYPE uint8_t // 3x7135 ramp (8-bit) +#define PWM3_DATATYPE uint8_t // DD FET ramp (16-bit) + +// PWM parameters of FET and 1x7135 channels are tied together because they share a counter +#define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 255 // highest value used in top half of ramp +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +// 1x7135 channel +#define CH1_PIN PB3 // pin 16, 1x7135 PWM +#define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 + +// 3x7135 channel +#define CH2_PIN PC0 // pin 15, 3x7135 PWM +#define CH2_PWM OCR0A // OCR0A is the output compare register for PC0 + +// DD FET channel +#define CH3_PIN PA6 // pin 1, DD FET PWM +#define CH3_PWM OCR1B // OCR1B is the output compare register for PB1 + +// e-switch +#define SWITCH_PIN PA2 // pin 5 +#define SWITCH_PCINT PCINT2 // pin 5 pin change interrupt +#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] +#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] +#define SWITCH_PORT PINA // PINA or PINB or PINC +#define SWITCH_PUE PUEA // pullup group A +#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] + + +#define ADC_PRSCL 0x07 // clk/128 + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 4 // add 0.20V (measured 0.22V) +#endif + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + +#define BUTTON_LED_PIN PA1 // pin 6 +#define BUTTON_LED_PORT PORTA // for all "PA" pins +#define BUTTON_LED_DDR DDRA // for all "PA" pins +#define BUTTON_LED_PUE PUEA // for all "PA" pins + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS +// it also has an independent LED in the button +#define USE_BUTTON_LED +// the aux LEDs are front-facing, so turn them off while main LEDs are on +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif + +void set_level_main(uint8_t level); + +bool gradual_tick_main(uint8_t gt); + + +inline void hwdef_setup() { + // enable output ports + // 3x7135 + DDRC = (1 << CH2_PIN); + // 1x7135 + DDRB = (1 << CH1_PIN); + // FET, aux R/G/B + DDRA = (1 << CH3_PIN) + | (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + | (1 << BUTTON_LED_PIN) + ; + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) + TCCR1A = (1< - -#define PWM_CHANNELS 2 -#define PWM_BITS 16 -#define PWM_TOP 255 -#define USE_DYN_PWM - -#ifndef SWITCH_PIN -#define SWITCH_PIN PIN5_bp -#define SWITCH_PORT VPORTA.IN -#define SWITCH_ISC_REG PORTA.PIN2CTRL -#define SWITCH_VECT PORTA_PORT_vect -#define SWITCH_INTFLG VPORTA.INTFLAGS -#endif - - -// 7135 channel -#ifndef PWM1_PIN -#define PWM1_PIN PB1 // -#define PWM1_LVL TCA0.SINGLE.CMP1BUF // CMP1 is the output compare register for PB1 -#endif - -// FET channel -#ifndef PWM2_PIN -#define PWM2_PIN PB0 // -#define PWM2_LVL TCA0.SINGLE.CMP0BUF // CMP0 is the output compare register for PB0 -#endif - -// PWM parameters of both channels are tied together because they share a counter -#define PWM1_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM -// not necessary when double-buffered "BUF" registers are used -#define PWM1_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment -#define PWM1_PHASE_RESET_OFF // force reset while shutting off -#define PWM1_PHASE_RESET_ON // force reset while turning on - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V -#endif - - -// lighted button -#ifndef AUXLED_PIN -#define AUXLED_PIN PIN5_bp -#define AUXLED_PORT PORTB -#endif - - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - - // set up the system clock to run at 10 MHz instead of the default 3.33 MHz - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); - - //VPORTA.DIR = ...; - VPORTB.DIR = PIN0_bm | PIN1_bm | PIN5_bm; // Outputs: Aux LED and PWMs - //VPORTC.DIR = ...; - - // enable pullups on the unused pins to reduce power - PORTA.PIN0CTRL = PORT_PULLUPEN_bm; - PORTA.PIN1CTRL = PORT_PULLUPEN_bm; - PORTA.PIN2CTRL = PORT_PULLUPEN_bm; - PORTA.PIN3CTRL = PORT_PULLUPEN_bm; - PORTA.PIN4CTRL = PORT_PULLUPEN_bm; - PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch - PORTA.PIN6CTRL = PORT_PULLUPEN_bm; - PORTA.PIN7CTRL = PORT_PULLUPEN_bm; - - //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // FET channel - //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // 7135 channel - PORTB.PIN2CTRL = PORT_PULLUPEN_bm; - PORTB.PIN3CTRL = PORT_PULLUPEN_bm; - PORTB.PIN4CTRL = PORT_PULLUPEN_bm; - //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED - - PORTC.PIN0CTRL = PORT_PULLUPEN_bm; - PORTC.PIN1CTRL = PORT_PULLUPEN_bm; - PORTC.PIN2CTRL = PORT_PULLUPEN_bm; - PORTC.PIN3CTRL = PORT_PULLUPEN_bm; - - // set up the PWM - // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf - // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm - // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm - // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm - // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc - // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc - // See the manual for other pins, clocks, configs, portmux, etc - TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_WGMODE_DSBOTTOM_gc; - PWM1_TOP = PWM_TOP; - TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; -} - diff --git a/hwdef-wurkkos-ts10.c b/hwdef-wurkkos-ts10.c new file mode 100644 index 0000000..14f6794 --- /dev/null +++ b/hwdef-wurkkos-ts10.c @@ -0,0 +1,49 @@ +// Wurkkos TS10 PWM helper functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "chan-aux.c" + +// single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear +void set_level_main(uint8_t level) { + if (level == 0) { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; // reset phase + return; + } + + level --; // PWM array index = level - 1 + PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); + PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET16(pwm_tops, level); + + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; + // wait to sync the counter and avoid flashes + // (unnecessary w/ buffered registers) + //while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE pwm2 = PWM_GET(pwm2_levels, gt); + + GRADUAL_ADJUST_STACKED(pwm1, CH1_PWM, PWM_TOP_INIT); + GRADUAL_ADJUST_SIMPLE (pwm2, CH2_PWM); + + if ( (pwm1 == CH1_PWM) + && (pwm2 == CH2_PWM) + ) { + return true; // done + } + return false; // not done yet +} + diff --git a/hwdef-wurkkos-ts10.h b/hwdef-wurkkos-ts10.h new file mode 100644 index 0000000..c150add --- /dev/null +++ b/hwdef-wurkkos-ts10.h @@ -0,0 +1,146 @@ +// Wurkkos TS10 driver layout +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * (based on BLF Q8-t1616 driver layout) + * Driver pinout: + * eSwitch: PA5 + * Aux LED: PB5 + * PWM FET: PB0 (TCA0 WO0) + * PWM 1x7135: PB1 (TCA0 WO1) + * Voltage: VCC + */ + +#define ATTINY 1616 +#include + +#define HWDEF_C_FILE hwdef-wurkkos-ts10.c + +// allow using aux LEDs as extra channel modes +#include "chan-aux.h" + +#define USE_CHANNEL_MODES +// channel modes: +// * 0. FET+7135 stacked +// * 1. aux LEDs +#define NUM_CHANNEL_MODES 2 +#define CM_MAIN 0 +#define CM_AUX 1 + + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +#define CHANNEL_MODES_ENABLED 0b00000001 +#define CHANNEL_HAS_ARGS 0b00000000 + +#define SET_LEVEL_MODES set_level_main, \ + set_level_aux +// gradual ticking for thermal regulation +#define GRADUAL_TICK_MODES gradual_tick_main, \ + gradual_tick_null + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // 1x7135 ramp +#define PWM2_DATATYPE uint8_t // DD FET ramp + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 255 // highest value used in top half of ramp +// not necessary when double-buffered "BUF" registers are used +#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment + +// 1x7135 channel +#define CH1_PIN PB1 +#define CH1_PWM TCA0.SINGLE.CMP1BUF // CMP1 is the output compare register for PB1 + +// DD FET channel +#define CH2_PIN PB0 +#define CH2_PWM TCA0.SINGLE.CMP0BUF // CMP0 is the output compare register for PB0 + +// e-switch +#define SWITCH_PIN PIN5_bp +//#define SWITCH_PCINT PCINT0 +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN2CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS +//#define PCINT_vect PCINT0_vect + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + +// front-facing aux LEDs +#define AUXLED_PIN PIN5_bp +#define AUXLED_PORT PORTB + +void set_level_main(uint8_t level); + +bool gradual_tick_main(uint8_t gt); + + +inline void hwdef_setup() { + + // set up the system clock to run at 10 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, + CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + + //VPORTA.DIR = ...; + // Outputs: Aux LED and PWMs + VPORTB.DIR = PIN0_bm + | PIN1_bm + | PIN5_bm; + //VPORTC.DIR = ...; + + // enable pullups on the unused pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + PORTA.PIN1CTRL = PORT_PULLUPEN_bm; + PORTA.PIN2CTRL = PORT_PULLUPEN_bm; + PORTA.PIN3CTRL = PORT_PULLUPEN_bm; + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch + PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // FET channel + //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // 7135 channel + PORTB.PIN2CTRL = PORT_PULLUPEN_bm; + PORTB.PIN3CTRL = PORT_PULLUPEN_bm; + PORTB.PIN4CTRL = PORT_PULLUPEN_bm; + //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED + + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + + // set up the PWM + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf + // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm + // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm + // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm + // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc + // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc + // See the manual for other pins, clocks, configs, portmux, etc + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm + | TCA_SINGLE_CMP1EN_bm + | TCA_SINGLE_WGMODE_DSBOTTOM_gc; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc + | TCA_SINGLE_ENABLE_bm; + + PWM_TOP = PWM_TOP_INIT; + +} + + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts10.h b/spaghetti-monster/anduril/cfg-wurkkos-ts10.h index bef2ad8..4b82949 100644 --- a/spaghetti-monster/anduril/cfg-wurkkos-ts10.h +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts10.h @@ -5,7 +5,7 @@ // same as the BLF Q8 T1616, mostly (added Dynamic PWM) #define MODEL_NUMBER "0714" -#include "hwdef-Wurkkos_TS10.h" +#include "hwdef-wurkkos-ts10.h" // ATTINY: 1616 // uses forward-facing aux LEDs @@ -23,44 +23,57 @@ #undef VOLTAGE_FUDGE_FACTOR #define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V, not 0.35V -/* -// copied from Emisar D4 ramp -// ../../bin/level_calc.py 1 65 7135 1 0.8 150 -// ... mixed with this: -// ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 -#define RAMP_LENGTH 150 -#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 -#define MAX_1x7135 65 -#define HALFSPEED_LEVEL 14 -#define QUARTERSPEED_LEVEL 5 -*/ +#define RAMP_SIZE 150 + +#if 0 // 2022 version // level 1 by hand, for the rest // level_calc.py 7.01 2 149 7135 3 0.5 125 FET 1 10 1200 --pwm dyn:63:2048:255 -#define RAMP_LENGTH 150 -#define USE_DYN_PWM #define PWM1_LEVELS 1,3,3,4,5,6,7,8,9,10,12,13,14,16,17,19,20,22,24,25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,64,67,70,72,75,77,80,82,85,87,89,91,93,95,96,98,99,100,100,101,100,100,99,97,95,93,90,86,82,87,91,96,100,106,111,116,122,128,134,141,147,155,162,169,177,186,194,203,213,222,232,243,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,6,7,9,11,12,14,16,18,20,22,24,27,29,31,34,37,39,42,45,48,51,54,57,61,64,68,72,75,79,83,88,92,97,101,106,111,116,121,126,132,138,144,150,156,162,169,176,183,190,197,205,213,221,229,237,246,255 #define PWM_TOPS 2047,2047,1198,1322,1584,1676,1701,1691,1662,1622,1774,1703,1631,1692,1613,1639,1558,1564,1559,1478,1464,1444,1420,1392,1361,1329,1331,1293,1256,1246,1207,1192,1152,1133,1094,1074,1035,1013,991,954,932,897,875,842,820,790,760,731,704,678,646,622,593,566,534,510,478,452,423,393,364,338,310,280,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 #define MAX_1x7135 90 #define HALFSPEED_LEVEL 2 #define QUARTERSPEED_LEVEL 2 +#endif + +// 7135 at 75/150 +// level_calc.py 5.7895 2 150 7135 1 0.1 130 FET 1 10 3000 --pwm dyn:74:4096:255:3 +// (with some manual tweaks) +// non-zero part of FET channel calculated with: +// level_calc.py 3 1 75 7135 2 500 3000 +#define PWM1_LEVELS 1,1,2,3,3,4,5,6,7,8,9,11,12,13,15,16,18,19,21,23,26,27,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,71,74,76,78,80,82,85,87,90,93,96,100,103,107,112,116,122,127,133,140,147,154,163,171,182,192,203,215,228,241,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,5,7,9,11,13,15,17,19,21,23,25,27,29,32,34,36,39,41,43,46,49,51,54,57,59,62,65,68,71,74,77,80,83,86,90,93,96,100,103,107,110,114,117,121,125,129,133,137,141,145,149,153,157,162,166,170,175,179,184,189,193,198,203,208,213,218,223,228,233,239,244,249,255 +#define PWM_TOPS 4095,2701,3200,3586,2518,2778,2834,2795,2705,2587,2455,2582,2412,2247,2256,2091,2062,1907,1860,1802,1737,1605,1542,1477,1412,1347,1284,1222,1162,1105,1050,997,946,898,853,810,768,730,693,658,625,594,564,536,503,485,462,439,418,398,384,366,353,340,327,319,307,298,292,284,280,273,269,266,263,260,258,256,256,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 120 -// 10 28 46 [65] 83 101 120 -#define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 7 +#define MAX_1x7135 75 +#define DEFAULT_LEVEL 50 +#define MIN_THERM_STEPDOWN 60 +#define HALFSPEED_LEVEL 20 +#define QUARTERSPEED_LEVEL 5 + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 150 +// 20 38 56 [75] 93 111 130 +#define RAMP_DISCRETE_FLOOR 20 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 // at Wurkkos's request, reduce the Simple UI ceiling a little bit -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#define SIMPLE_UI_CEIL 144 -#define SIMPLE_UI_STEPS 5 +// (i.e. not 150; original config had it at 144/150, or DD FET 204/255) +// 20 47 [75] 102 130 +#define SIMPLE_UI_FLOOR 20 +#define SIMPLE_UI_CEIL 130 +#define SIMPLE_UI_STEPS 5 // enable 2 click turbo (Anduril 1 style) #define DEFAULT_2C_STYLE 1 +// stop panicking at ~50% power +#define THERM_FASTER_LEVEL 120 // throttle back faster when high + +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + // enable SOS in the blinkies group #define USE_SOS_MODE #define USE_SOS_MODE_IN_BLINKY_GROUP @@ -71,16 +84,14 @@ // allow Aux Config and Strobe Modes in Simple UI #define USE_EXTENDED_SIMPLE_UI -// enable factory reset on 13H without loosening tailcap -#define USE_SOFT_FACTORY_RESET +// the default of 26 looks a bit rough, so increase it to make it smoother +#define CANDLE_AMPLITUDE 33 -// stop panicking at ~55% power -#define THERM_FASTER_LEVEL 130 // throttle back faster when high - -// don't blink during the ramp or at the ceiling +// don't blink mid-ramp #ifdef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_MIDDLE #endif -#ifdef BLINK_AT_RAMP_CEIL -#undef BLINK_AT_RAMP_CEIL -#endif + +// enable factory reset on 13H without loosening tailcap +#define USE_SOFT_FACTORY_RESET + diff --git a/spaghetti-monster/chan-aux.c b/spaghetti-monster/chan-aux.c new file mode 100644 index 0000000..e04e6a2 --- /dev/null +++ b/spaghetti-monster/chan-aux.c @@ -0,0 +1,11 @@ +// channel modes for single color aux LEDs +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +void set_level_aux(uint8_t level) { + indicator_led(!(!(level)) << 1); // high (or off) +} + +bool gradual_tick_null(uint8_t gt) { return true; } // do nothing + diff --git a/spaghetti-monster/chan-aux.h b/spaghetti-monster/chan-aux.h new file mode 100644 index 0000000..c8264bd --- /dev/null +++ b/spaghetti-monster/chan-aux.h @@ -0,0 +1,9 @@ +// channel modes for single color aux LEDs +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +void set_level_aux(uint8_t level); + +bool gradual_tick_null(uint8_t gt); + -- cgit v1.2.3 From e8d7e8ea11696bb2cad60c309527d02f130f7687 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 05:19:50 -0600 Subject: added ability to set channel mode for number readouts (batt check, temp check, version check) Press 3C in batt check mode to change the blink channel. Also fixed TS10 stepped ramp ceiling value. --- spaghetti-monster/anduril/battcheck-mode.c | 9 +++++++++ spaghetti-monster/anduril/cfg-wurkkos-ts10.h | 5 ++++- spaghetti-monster/anduril/load-save-config-fsm.h | 3 +++ spaghetti-monster/anduril/load-save-config.h | 4 ++++ spaghetti-monster/fsm-misc.c | 10 ++++++++++ spaghetti-monster/fsm-misc.h | 13 +++++++++---- 6 files changed, 39 insertions(+), 5 deletions(-) diff --git a/spaghetti-monster/anduril/battcheck-mode.c b/spaghetti-monster/anduril/battcheck-mode.c index 9eb82fe..7e25f79 100644 --- a/spaghetti-monster/anduril/battcheck-mode.c +++ b/spaghetti-monster/anduril/battcheck-mode.c @@ -31,6 +31,15 @@ uint8_t battcheck_state(Event event, uint16_t arg) { return MISCHIEF_MANAGED; } + #ifdef DEFAULT_BLINK_CHANNEL + // 3 clicks: next channel mode (specific to number blinky modes) + else if (event == EV_3clicks) { + cfg.blink_channel = (cfg.blink_channel + 1) % NUM_CHANNEL_MODES; + save_config(); + return EVENT_HANDLED; + } + #endif // ifdef DEFAULT_BLINK_CHANNEL + #ifdef USE_VOLTAGE_CORRECTION // 7H: voltage config mode else if (event == EV_click7_hold) { diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts10.h b/spaghetti-monster/anduril/cfg-wurkkos-ts10.h index 4b82949..8e3462e 100644 --- a/spaghetti-monster/anduril/cfg-wurkkos-ts10.h +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts10.h @@ -55,7 +55,7 @@ #define RAMP_SMOOTH_CEIL 150 // 20 38 56 [75] 93 111 130 #define RAMP_DISCRETE_FLOOR 20 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_CEIL 130 #define RAMP_DISCRETE_STEPS 7 // at Wurkkos's request, reduce the Simple UI ceiling a little bit @@ -74,6 +74,9 @@ // show each channel while it scroll by in the menu #define USE_CONFIG_COLORS +// blink numbers on the aux LEDs by default +#define DEFAULT_BLINK_CHANNEL CM_AUX + // enable SOS in the blinkies group #define USE_SOS_MODE #define USE_SOS_MODE_IN_BLINKY_GROUP diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h index ceb9d76..df46fc5 100644 --- a/spaghetti-monster/anduril/load-save-config-fsm.h +++ b/spaghetti-monster/anduril/load-save-config-fsm.h @@ -52,6 +52,9 @@ typedef struct Config { #ifdef USE_MANUAL_MEMORY uint8_t manual_memory_channel_mode; #endif + #ifdef DEFAULT_BLINK_CHANNEL + uint8_t blink_channel; + #endif #endif #ifdef USE_CHANNEL_MODE_ARGS // this is an array, needs a few bytes diff --git a/spaghetti-monster/anduril/load-save-config.h b/spaghetti-monster/anduril/load-save-config.h index 60612d3..278d286 100644 --- a/spaghetti-monster/anduril/load-save-config.h +++ b/spaghetti-monster/anduril/load-save-config.h @@ -77,6 +77,10 @@ Config cfg = { // reset w/ manual memory .manual_memory_channel_mode = DEFAULT_CHANNEL_MODE, #endif + #ifdef DEFAULT_BLINK_CHANNEL + // blink numbers in a specific channel (user configurable) + .blink_channel = DEFAULT_BLINK_CHANNEL, + #endif #endif #ifdef USE_CHANNEL_MODE_ARGS // one byte of extra data per channel mode, like for tint value diff --git a/spaghetti-monster/fsm-misc.c b/spaghetti-monster/fsm-misc.c index 80652b3..1c40b81 100644 --- a/spaghetti-monster/fsm-misc.c +++ b/spaghetti-monster/fsm-misc.c @@ -32,6 +32,11 @@ uint8_t blink_digit(uint8_t num) { uint8_t ontime = BLINK_SPEED * 2 / 12; if (!num) { ontime = 8; num ++; } + #ifdef BLINK_CHANNEL + uint8_t old_channel = CH_MODE; + set_channel_mode(BLINK_CHANNEL); + #endif + for (; num>0; num--) { // TODO: allow setting a blink channel mode per build target set_level(BLINK_BRIGHTNESS); @@ -39,6 +44,11 @@ uint8_t blink_digit(uint8_t num) { set_level(0); nice_delay_ms(BLINK_SPEED * 3 / 12); } + + #ifdef BLINK_CHANNEL + set_channel_mode(old_channel); + #endif + return nice_delay_ms(BLINK_SPEED * 8 / 12); } #endif diff --git a/spaghetti-monster/fsm-misc.h b/spaghetti-monster/fsm-misc.h index 68929c2..8988337 100644 --- a/spaghetti-monster/fsm-misc.h +++ b/spaghetti-monster/fsm-misc.h @@ -9,10 +9,15 @@ void auto_clock_speed(); #endif #if defined(USE_BLINK_NUM) || defined(USE_BLINK_DIGIT) -#ifndef BLINK_BRIGHTNESS -#define BLINK_BRIGHTNESS (MAX_LEVEL/6) -#endif -uint8_t blink_digit(uint8_t num); + #ifndef BLINK_BRIGHTNESS + #define BLINK_BRIGHTNESS (MAX_LEVEL/6) + #endif + #if defined(USE_CFG) && defined(DEFAULT_BLINK_CHANNEL) + #define BLINK_CHANNEL cfg.blink_channel + #elif defined(DEFAULT_BLINK_CHANNEL) + #define BLINK_CHANNEL DEFAULT_BLINK_CHANNEL + #endif + uint8_t blink_digit(uint8_t num); #endif #ifdef USE_BLINK_NUM -- cgit v1.2.3 From d3d29ea2c08595d8a42d36a986f24e5b5afebd41 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 05:23:22 -0600 Subject: bin/flash-1616.py: added shebang header and +x bit --- bin/flash-1616.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) mode change 100644 => 100755 bin/flash-1616.py diff --git a/bin/flash-1616.py b/bin/flash-1616.py old mode 100644 new mode 100755 index 6b3e2ee..f431b3a --- a/bin/flash-1616.py +++ b/bin/flash-1616.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 # Use with Python3, make sure to have the pymcuprog module installed (via pip) # Read out the pymcuprog version @@ -73,4 +74,5 @@ print("Writing complete.") print("Verifying the write... ") verify_status = backend.verify_hex(hexfile) if verify_status is True: - print("Verification successful!") \ No newline at end of file + print("Verification successful!") + -- cgit v1.2.3 From b6397ae99169a7e5ce3f8205513947ff8d64f4fa Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 05:24:55 -0600 Subject: documented ramp 6C, ramp 4H, lockout 3H, and battcheck 3C --- spaghetti-monster/anduril/anduril-manual.txt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/anduril-manual.txt b/spaghetti-monster/anduril/anduril-manual.txt index 29478f8..aeafed9 100644 --- a/spaghetti-monster/anduril/anduril-manual.txt +++ b/spaghetti-monster/anduril/anduril-manual.txt @@ -182,8 +182,13 @@ While the light is on, a few actions are available: - 2H: Change brightness (down). - 3C: Switch to the other ramp style. (smooth / stepped) - - 3H: Tint ramping (on lights which have it). - - 3H: Momentary turbo (on lights with no tint ramping). + (or activate the next channel mode, when more than one is enabled) + (then use 6C instead, for smooth / stepped toggle) + - 6C: Switch to the other ramp style. (when 3C is mapped to next channel) + + - 3H: Momentary turbo (when current channel has no tint to ramp). + - 3H: Tint ramping (only when current channel has adjustable tint). + - 4H: Momentary turbo, when 3H is mapped to tint. - 4C: Go to lockout mode. @@ -316,6 +321,8 @@ lockout mode has two levels: - 2H: Light up at the highest floor level. (or the manual mem level, if there is one) + - 3H: Next channel mode (if more than one is enabled). + It is also possible to make the light lock itself automatically after being turned off. To enable this, go to lockout mode and use a 10H action to activate the auto-lock config menu. Release the button after @@ -365,6 +372,10 @@ In more detail, this is what each blinky / utility mode does: A "zero" digit is represented by a very quick blink. + On lights with more than one set of LEDs, pressing 3C during batt + check mode can select which set of LEDs (which channel mode) it + uses to blink out numbers. + The voltage config menu has one setting: 1. Voltage correction factor. This adjusts the battery @@ -894,6 +905,7 @@ Any Full 9H Channel mode enable/disable menu: Lockout Any 1C/1H Momentary moon (lowest floor) Lockout Any 2C/2H Momentary moon (highest floor, or manual mem level) Lockout Any 3C Unlock (go to "Off" mode) +Lockout Any 3H Next channel mode (if more than one enabled) Lockout Any 4C On (ramp mode, memorized level) Lockout Any 4H On (ramp mode, floor level) Lockout Any 5C On (ramp mode, ceiling level) @@ -917,6 +929,7 @@ Biking Full 1H/2H Brighter / dimmer Batt check Any 1C Off Batt check Full 2C Next blinky mode (Temp check, Beacon, SOS) +Batt check Full 3C Next channel mode (for number blinks only) Batt check Full 7H Voltage config menu 1: voltage correction factor ... -- cgit v1.2.3 From d12e533a547d95a3ac340d59aa0dd6f6765de3f5 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 08:37:07 -0600 Subject: fixed bug: channel change could stick when activating a config menu from battcheck (the blink function changed the channel, then the config menu saved it, then the blink function restored it, then the config menu restored it to the value it saved, which was wrong) --- spaghetti-monster/fsm-misc.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/spaghetti-monster/fsm-misc.c b/spaghetti-monster/fsm-misc.c index 1c40b81..dacca85 100644 --- a/spaghetti-monster/fsm-misc.c +++ b/spaghetti-monster/fsm-misc.c @@ -33,15 +33,29 @@ uint8_t blink_digit(uint8_t num) { if (!num) { ontime = 8; num ++; } #ifdef BLINK_CHANNEL + // channel is set per blink, to prevent issues + // if another mode interrupts us (like a config menu) uint8_t old_channel = CH_MODE; - set_channel_mode(BLINK_CHANNEL); #endif for (; num>0; num--) { // TODO: allow setting a blink channel mode per build target + #ifdef BLINK_CHANNEL + set_channel_mode(BLINK_CHANNEL); + #endif set_level(BLINK_BRIGHTNESS); + #ifdef BLINK_CHANNEL + CH_MODE = old_channel; + #endif nice_delay_ms(ontime); + + #ifdef BLINK_CHANNEL + set_channel_mode(BLINK_CHANNEL); + #endif set_level(0); + #ifdef BLINK_CHANNEL + CH_MODE = old_channel; + #endif nice_delay_ms(BLINK_SPEED * 3 / 12); } -- cgit v1.2.3 From c132c50a98c984fb6daee0a96370f466b1ee8b6a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 08:39:28 -0600 Subject: made "post-off voltage display" user-configurable in battcheck 7H menu item 2 (1 click per second the display should last) --- spaghetti-monster/anduril/aux-leds.c | 4 +++- spaghetti-monster/anduril/battcheck-mode-fsm.h | 7 +++++++ spaghetti-monster/anduril/battcheck-mode.c | 13 ++++++++++++- spaghetti-monster/anduril/load-save-config-fsm.h | 3 +++ spaghetti-monster/anduril/load-save-config.h | 4 ++++ 5 files changed, 29 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/aux-leds.c b/spaghetti-monster/anduril/aux-leds.c index 237390c..d833d82 100644 --- a/spaghetti-monster/anduril/aux-leds.c +++ b/spaghetti-monster/anduril/aux-leds.c @@ -104,11 +104,13 @@ void rgb_led_update(uint8_t mode, uint16_t arg) { // always preview in high mode if (! go_to_standby) { pattern = 2; } + #ifdef USE_POST_OFF_VOLTAGE // use voltage high mode for a few seconds after initial poweroff - else if (arg < (SLEEP_TICKS_PER_SECOND*3)) { + else if (arg < (cfg.post_off_voltage * SLEEP_TICKS_PER_SECOND)) { pattern = 2; color = RGB_LED_NUM_COLORS - 1; } + #endif const uint8_t *colors = rgb_led_colors; uint8_t actual_color = 0; diff --git a/spaghetti-monster/anduril/battcheck-mode-fsm.h b/spaghetti-monster/anduril/battcheck-mode-fsm.h index 4ab8f06..580080c 100644 --- a/spaghetti-monster/anduril/battcheck-mode-fsm.h +++ b/spaghetti-monster/anduril/battcheck-mode-fsm.h @@ -5,3 +5,10 @@ #define USE_BATTCHECK +#ifdef USE_AUX_RGB_LEDS + // show voltage colors for a few seconds after going to standby + #define USE_POST_OFF_VOLTAGE + #ifndef DEFAULT_POST_OFF_VOLTAGE_SECONDS + #define DEFAULT_POST_OFF_VOLTAGE_SECONDS 5 + #endif +#endif diff --git a/spaghetti-monster/anduril/battcheck-mode.c b/spaghetti-monster/anduril/battcheck-mode.c index 7e25f79..0ef6b0a 100644 --- a/spaghetti-monster/anduril/battcheck-mode.c +++ b/spaghetti-monster/anduril/battcheck-mode.c @@ -61,11 +61,22 @@ uint8_t battcheck_state(Event event, uint16_t arg) { // ... // 13 = add 0.30V void voltage_config_save(uint8_t step, uint8_t value) { + #ifdef USE_POST_OFF_VOLTAGE + if (2 == step) cfg.post_off_voltage = value; + else + #endif if (value) cfg.voltage_correction = value; } uint8_t voltage_config_state(Event event, uint16_t arg) { - return config_state_base(event, arg, 1, voltage_config_save); + #ifdef USE_POST_OFF_VOLTAGE + #define VOLTAGE_CONFIG_STEPS 2 + #else + #define VOLTAGE_CONFIG_STEPS 1 + #endif + return config_state_base(event, arg, + VOLTAGE_CONFIG_STEPS, + voltage_config_save); } #endif // #ifdef USE_VOLTAGE_CORRECTION diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h index df46fc5..862cf26 100644 --- a/spaghetti-monster/anduril/load-save-config-fsm.h +++ b/spaghetti-monster/anduril/load-save-config-fsm.h @@ -97,6 +97,9 @@ typedef struct Config { #ifdef USE_AUX_RGB_LEDS uint8_t rgb_led_off_mode; uint8_t rgb_led_lockout_mode; + #ifdef USE_POST_OFF_VOLTAGE + uint8_t post_off_voltage; + #endif #endif ///// misc other mode settings diff --git a/spaghetti-monster/anduril/load-save-config.h b/spaghetti-monster/anduril/load-save-config.h index 278d286..8ae9d96 100644 --- a/spaghetti-monster/anduril/load-save-config.h +++ b/spaghetti-monster/anduril/load-save-config.h @@ -135,6 +135,10 @@ Config cfg = { #ifdef USE_AUX_RGB_LEDS .rgb_led_off_mode = RGB_LED_OFF_DEFAULT, .rgb_led_lockout_mode = RGB_LED_LOCKOUT_DEFAULT, + #ifdef USE_POST_OFF_VOLTAGE + // display voltage readout for a while after turning off? + .post_off_voltage = DEFAULT_POST_OFF_VOLTAGE_SECONDS, + #endif #endif ///// misc other mode settings -- cgit v1.2.3 From fbed17d3260d1fca312d655818cc2394654615aa Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 08:47:42 -0600 Subject: D4v2: added the rest of the aux RGB colors as channel modes, and set aux "white" as the mode it uses to blink out numbers --- hwdef-emisar-d4v2.h | 34 ++++++++++++++++++++++------- spaghetti-monster/anduril/cfg-emisar-d4v2.h | 3 +++ spaghetti-monster/chan-rgbaux.c | 22 ++++++++++++++++--- spaghetti-monster/chan-rgbaux.h | 4 ++++ 4 files changed, 52 insertions(+), 11 deletions(-) diff --git a/hwdef-emisar-d4v2.h b/hwdef-emisar-d4v2.h index 813dbf3..a502421 100644 --- a/hwdef-emisar-d4v2.h +++ b/hwdef-emisar-d4v2.h @@ -40,13 +40,23 @@ // channel modes: // * 0. FET+7135 stacked // * 1. aux red -// * 2. aux green -// * 3. aux blue -#define NUM_CHANNEL_MODES 4 -#define CM_MAIN 0 -#define CM_AUXRED 1 -#define CM_AUXGRN 2 -#define CM_AUXBLU 3 +// * 2. aux yellow +// * 3. aux green +// * 4. aux cyan +// * 5. aux blue +// * 6. aux purple +// * 7. aux white +#define NUM_CHANNEL_MODES 8 +enum CHANNEL_MODES { + CM_MAIN = 0, + CM_AUXRED, + CM_AUXYEL, + CM_AUXGRN, + CM_AUXCYN, + CM_AUXBLU, + CM_AUXPRP, + CM_AUXWHT, +}; #define DEFAULT_CHANNEL_MODE CM_MAIN @@ -58,10 +68,18 @@ #define SET_LEVEL_MODES set_level_main, \ set_level_auxred, \ + set_level_auxyel, \ set_level_auxgrn, \ - set_level_auxblu + set_level_auxcyn, \ + set_level_auxblu, \ + set_level_auxprp, \ + set_level_auxwht // gradual ticking for thermal regulation #define GRADUAL_TICK_MODES gradual_tick_main, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ gradual_tick_null, \ gradual_tick_null, \ gradual_tick_null diff --git a/spaghetti-monster/anduril/cfg-emisar-d4v2.h b/spaghetti-monster/anduril/cfg-emisar-d4v2.h index 69023d1..f68e50f 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4v2.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4v2.h @@ -45,6 +45,9 @@ // show each channel while it scroll by in the menu #define USE_CONFIG_COLORS +// blink numbers on the aux LEDs by default +#define DEFAULT_BLINK_CHANNEL CM_AUXWHT + // use aux red + aux blue for police strobe #define USE_POLICE_COLOR_STROBE_MODE #define POLICE_STROBE_USES_AUX diff --git a/spaghetti-monster/chan-rgbaux.c b/spaghetti-monster/chan-rgbaux.c index 355f246..19d18a6 100644 --- a/spaghetti-monster/chan-rgbaux.c +++ b/spaghetti-monster/chan-rgbaux.c @@ -4,15 +4,31 @@ #pragma once void set_level_auxred(uint8_t level) { - rgb_led_set(!(!(level)) << 1); // red, high (or off) + rgb_led_set(!(!(level)) * 0b000010); // red, high (or off) +} + +void set_level_auxyel(uint8_t level) { + rgb_led_set(!(!(level)) * 0b001010); // red+green, high (or off) } void set_level_auxgrn(uint8_t level) { - rgb_led_set(!(!(level)) << 3); // green, high (or off) + rgb_led_set(!(!(level)) * 0b001000); // green, high (or off) +} + +void set_level_auxcyn(uint8_t level) { + rgb_led_set(!(!(level)) * 0b101000); // green+blue, high (or off) } void set_level_auxblu(uint8_t level) { - rgb_led_set(!(!(level)) << 5); // blue, high (or off) + rgb_led_set(!(!(level)) * 0b100000); // blue, high (or off) +} + +void set_level_auxprp(uint8_t level) { + rgb_led_set(!(!(level)) * 0b100010); // red+blue, high (or off) +} + +void set_level_auxwht(uint8_t level) { + rgb_led_set(!(!(level)) * 0b101010); // red+green+blue, high (or off) } bool gradual_tick_null(uint8_t gt) { return true; } // do nothing diff --git a/spaghetti-monster/chan-rgbaux.h b/spaghetti-monster/chan-rgbaux.h index 5c1c5c3..d19f6ad 100644 --- a/spaghetti-monster/chan-rgbaux.h +++ b/spaghetti-monster/chan-rgbaux.h @@ -4,8 +4,12 @@ #pragma once void set_level_auxred(uint8_t level); +void set_level_auxyel(uint8_t level); void set_level_auxgrn(uint8_t level); +void set_level_auxcyn(uint8_t level); void set_level_auxblu(uint8_t level); +void set_level_auxprp(uint8_t level); +void set_level_auxwht(uint8_t level); bool gradual_tick_null(uint8_t gt); -- cgit v1.2.3 From 8e9106f6fb26eadbfffd56fa14390b9f41e74ed2 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 09:13:39 -0600 Subject: converted Wurkkos TS25 build... ... and gave it a smoother ramp ... and the other new functions added recently --- hwdef-Wurkkos_TS25.h | 116 ----------------- hwdef-wurkkos-ts25.c | 49 ++++++++ hwdef-wurkkos-ts25.h | 179 +++++++++++++++++++++++++++ spaghetti-monster/anduril/cfg-wurkkos-ts25.h | 79 +++++++----- 4 files changed, 273 insertions(+), 150 deletions(-) delete mode 100644 hwdef-Wurkkos_TS25.h create mode 100644 hwdef-wurkkos-ts25.c create mode 100644 hwdef-wurkkos-ts25.h diff --git a/hwdef-Wurkkos_TS25.h b/hwdef-Wurkkos_TS25.h deleted file mode 100644 index cf34754..0000000 --- a/hwdef-Wurkkos_TS25.h +++ /dev/null @@ -1,116 +0,0 @@ -// Wurkkos TS25 driver layout -// Copyright (C) 2022-2023 (FIXME) -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * Driver pinout: - * eSwitch: PA5 - * PWM FET: PB0 (TCA0 WO0) - * PWM 1x7135: PB1 (TCA0 WO1) - * Voltage: VCC - * Aux Blue: PC1 - * Aux Red: PC2 - * Aux Green: PC3 - */ - -#define LAYOUT_DEFINED - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1616 -#include - -#define PWM_CHANNELS 2 -#define PWM_BITS 16 -#define PWM_TOP 255 -#define USE_DYN_PWM - -#ifndef SWITCH_PIN -#define SWITCH_PIN PIN5_bp -#define SWITCH_PORT VPORTA.IN -#define SWITCH_ISC_REG PORTA.PIN2CTRL -#define SWITCH_VECT PORTA_PORT_vect -#define SWITCH_INTFLG VPORTA.INTFLAGS -#endif - - -// 7135 channel -#ifndef PWM1_PIN -#define PWM1_PIN PB1 // -#define PWM1_LVL TCA0.SINGLE.CMP1BUF // CMP1 is the output compare register for PB1 -#endif - -// FET channel -#ifndef PWM2_PIN -#define PWM2_PIN PB0 // -#define PWM2_LVL TCA0.SINGLE.CMP0BUF // CMP0 is the output compare register for PB0 -#endif - -// PWM parameters of both channels are tied together because they share a counter -#define PWM1_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM -// not necessary when double-buffered "BUF" registers are used -#define PWM1_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment -#define PWM1_PHASE_RESET_OFF // force reset while shutting off -#define PWM1_PHASE_RESET_ON // force reset while turning on - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V -#endif - - -// this driver allows for aux LEDs under the optic -#define AUXLED_B_PIN PIN1_bp // pin 1 -#define AUXLED_R_PIN PIN2_bp // pin 2 -#define AUXLED_G_PIN PIN3_bp // pin 3 -#define AUXLED_RGB_PORT PORTC // PORTA or PORTB or PORTC - - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - - // set up the system clock to run at 10 MHz instead of the default 3.33 MHz - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); - - //VPORTA.DIR = ...; - VPORTB.DIR = PIN0_bm | PIN1_bm; // Outputs: PWMs - VPORTC.DIR = PIN1_bm | PIN2_bm | PIN3_bm; - - // enable pullups on the unused pins to reduce power - PORTA.PIN0CTRL = PORT_PULLUPEN_bm; - PORTA.PIN1CTRL = PORT_PULLUPEN_bm; - PORTA.PIN2CTRL = PORT_PULLUPEN_bm; - PORTA.PIN3CTRL = PORT_PULLUPEN_bm; - PORTA.PIN4CTRL = PORT_PULLUPEN_bm; - PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch - PORTA.PIN6CTRL = PORT_PULLUPEN_bm; - PORTA.PIN7CTRL = PORT_PULLUPEN_bm; - - //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // FET channel - //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // 7135 channel - PORTB.PIN2CTRL = PORT_PULLUPEN_bm; - PORTB.PIN3CTRL = PORT_PULLUPEN_bm; - PORTB.PIN4CTRL = PORT_PULLUPEN_bm; - PORTB.PIN5CTRL = PORT_PULLUPEN_bm; - - PORTC.PIN0CTRL = PORT_PULLUPEN_bm; - //PORTC.PIN1CTRL = PORT_PULLUPEN_bm; // RGB Aux - //PORTC.PIN2CTRL = PORT_PULLUPEN_bm; // RGB Aux - //PORTC.PIN3CTRL = PORT_PULLUPEN_bm; // RGB Aux - - // set up the PWM - // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf - // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm - // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm - // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm - // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc - // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc - // See the manual for other pins, clocks, configs, portmux, etc - TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_WGMODE_DSBOTTOM_gc; - PWM1_TOP = PWM_TOP; - TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; -} - diff --git a/hwdef-wurkkos-ts25.c b/hwdef-wurkkos-ts25.c new file mode 100644 index 0000000..1d5b656 --- /dev/null +++ b/hwdef-wurkkos-ts25.c @@ -0,0 +1,49 @@ +// Wurkkos TS25 PWM helper functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "chan-rgbaux.c" + +// single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear +void set_level_main(uint8_t level) { + if (level == 0) { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; // reset phase + return; + } + + level --; // PWM array index = level - 1 + PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); + PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET16(pwm_tops, level); + + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; + // wait to sync the counter and avoid flashes + // (unnecessary w/ buffered registers) + //while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE pwm2 = PWM_GET(pwm2_levels, gt); + + GRADUAL_ADJUST_STACKED(pwm1, CH1_PWM, PWM_TOP_INIT); + GRADUAL_ADJUST_SIMPLE (pwm2, CH2_PWM); + + if ( (pwm1 == CH1_PWM) + && (pwm2 == CH2_PWM) + ) { + return true; // done + } + return false; // not done yet +} + diff --git a/hwdef-wurkkos-ts25.h b/hwdef-wurkkos-ts25.h new file mode 100644 index 0000000..b9fbdfb --- /dev/null +++ b/hwdef-wurkkos-ts25.h @@ -0,0 +1,179 @@ +// Wurkkos TS25 driver layout +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * Driver pinout: + * eSwitch: PA5 + * PWM FET: PB0 (TCA0 WO0) + * PWM 1x7135: PB1 (TCA0 WO1) + * Voltage: VCC + * Aux Red: PC2 + * Aux Green: PC3 + * Aux Blue: PC1 + */ + +#define ATTINY 1616 +#include + +#define HWDEF_C_FILE hwdef-wurkkos-ts25.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +#define USE_CHANNEL_MODES +// channel modes: +// * 0. FET+7135 stacked +// * 1. aux red +// * 2. aux yellow +// * 3. aux green +// * 4. aux cyan +// * 5. aux blue +// * 6. aux purple +// * 7. aux white +#define NUM_CHANNEL_MODES 8 +enum CHANNEL_MODES { + CM_MAIN = 0, + CM_AUXRED, + CM_AUXYEL, + CM_AUXGRN, + CM_AUXCYN, + CM_AUXBLU, + CM_AUXPRP, + CM_AUXWHT, +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +#define CHANNEL_MODES_ENABLED 0b00000001 +#define CHANNEL_HAS_ARGS 0b00000000 + +#define SET_LEVEL_MODES set_level_main, \ + set_level_auxred, \ + set_level_auxyel, \ + set_level_auxgrn, \ + set_level_auxcyn, \ + set_level_auxblu, \ + set_level_auxprp, \ + set_level_auxwht +// gradual ticking for thermal regulation +#define GRADUAL_TICK_MODES gradual_tick_main, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // 1x7135 ramp +#define PWM2_DATATYPE uint8_t // DD FET ramp + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 255 // highest value used in top half of ramp +// not necessary when double-buffered "BUF" registers are used +#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment + +// 1x7135 channel +#define CH1_PIN PB1 +#define CH1_PWM TCA0.SINGLE.CMP1BUF // CMP1 is the output compare register for PB1 + +// DD FET channel +#define CH2_PIN PB0 +#define CH2_PWM TCA0.SINGLE.CMP0BUF // CMP0 is the output compare register for PB0 + +// e-switch +#define SWITCH_PIN PIN5_bp +//#define SWITCH_PCINT PCINT0 +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN2CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS +//#define PCINT_vect PCINT0_vect + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + +// this driver allows for aux LEDs under the optic +#define AUXLED_R_PIN PIN2_bp // pin 2 +#define AUXLED_G_PIN PIN3_bp // pin 3 +#define AUXLED_B_PIN PIN1_bp // pin 1 +#define AUXLED_RGB_PORT PORTC // PORTA or PORTB or PORTC + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + +void set_level_main(uint8_t level); + +bool gradual_tick_main(uint8_t gt); + + +inline void hwdef_setup() { + + // set up the system clock to run at 10 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, + CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + + //VPORTA.DIR = ...; + // Outputs: PWMs + VPORTB.DIR = PIN0_bm + | PIN1_bm; + // RGB aux LEDs + VPORTC.DIR = PIN1_bm + | PIN2_bm + | PIN3_bm; + + // enable pullups on the unused pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + PORTA.PIN1CTRL = PORT_PULLUPEN_bm; + PORTA.PIN2CTRL = PORT_PULLUPEN_bm; + PORTA.PIN3CTRL = PORT_PULLUPEN_bm; + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch + PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // FET channel + //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // 7135 channel + PORTB.PIN2CTRL = PORT_PULLUPEN_bm; + PORTB.PIN3CTRL = PORT_PULLUPEN_bm; + PORTB.PIN4CTRL = PORT_PULLUPEN_bm; + PORTB.PIN5CTRL = PORT_PULLUPEN_bm; + + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; + //PORTC.PIN1CTRL = PORT_PULLUPEN_bm; // RGB Aux + //PORTC.PIN2CTRL = PORT_PULLUPEN_bm; // RGB Aux + //PORTC.PIN3CTRL = PORT_PULLUPEN_bm; // RGB Aux + + // set up the PWM + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf + // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm + // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm + // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm + // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc + // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc + // See the manual for other pins, clocks, configs, portmux, etc + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm + | TCA_SINGLE_CMP1EN_bm + | TCA_SINGLE_WGMODE_DSBOTTOM_gc; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc + | TCA_SINGLE_ENABLE_bm; + + PWM_TOP = PWM_TOP_INIT; + +} + + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts25.h b/spaghetti-monster/anduril/cfg-wurkkos-ts25.h index 3196a9a..446ee26 100644 --- a/spaghetti-monster/anduril/cfg-wurkkos-ts25.h +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts25.h @@ -4,7 +4,7 @@ #pragma once #define MODEL_NUMBER "0715" -#include "hwdef-Wurkkos_TS25.h" +#include "hwdef-wurkkos-ts25.h" // ATTINY: 1616 // this light has three aux LED channels: R, G, B @@ -19,44 +19,60 @@ #undef VOLTAGE_FUDGE_FACTOR #define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V, not 0.35V -/* -// copied from Emisar D4 ramp -// ../../bin/level_calc.py 1 65 7135 1 0.8 150 -// ... mixed with this: -// ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 -#define RAMP_LENGTH 150 -#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 -#define MAX_1x7135 65 -#define HALFSPEED_LEVEL 14 -#define QUARTERSPEED_LEVEL 5 -*/ +#define RAMP_SIZE 150 + +#if 0 // 2022 version // level 1 by hand, for the rest // level_calc.py 7.01 2 149 7135 3 0.5 125 FET 1 10 1200 --pwm dyn:63:2048:255 -#define RAMP_LENGTH 150 -#define USE_DYN_PWM #define PWM1_LEVELS 1,3,3,4,5,6,7,8,9,10,12,13,14,16,17,19,20,22,24,25,27,29,31,33,35,37,40,42,44,47,49,52,54,57,59,62,64,67,70,72,75,77,80,82,85,87,89,91,93,95,96,98,99,100,100,101,100,100,99,97,95,93,90,86,82,87,91,96,100,106,111,116,122,128,134,141,147,155,162,169,177,186,194,203,213,222,232,243,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,6,7,9,11,12,14,16,18,20,22,24,27,29,31,34,37,39,42,45,48,51,54,57,61,64,68,72,75,79,83,88,92,97,101,106,111,116,121,126,132,138,144,150,156,162,169,176,183,190,197,205,213,221,229,237,246,255 #define PWM_TOPS 2047,2047,1198,1322,1584,1676,1701,1691,1662,1622,1774,1703,1631,1692,1613,1639,1558,1564,1559,1478,1464,1444,1420,1392,1361,1329,1331,1293,1256,1246,1207,1192,1152,1133,1094,1074,1035,1013,991,954,932,897,875,842,820,790,760,731,704,678,646,622,593,566,534,510,478,452,423,393,364,338,310,280,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 #define MAX_1x7135 90 #define HALFSPEED_LEVEL 2 #define QUARTERSPEED_LEVEL 2 +#endif -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 120 -// 10 28 46 [65] 83 101 120 -#define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 7 +// 7135 at 75/150 +// level_calc.py 5.7895 2 150 7135 1 0.1 130 FET 1 10 3000 --pwm dyn:74:4096:255:3 +// (with some manual tweaks) +#define PWM1_LEVELS 1,1,2,3,3,4,5,6,7,8,9,11,12,13,15,16,18,19,21,23,26,27,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,71,74,76,78,80,82,85,87,90,93,96,100,103,107,112,116,122,127,133,140,147,154,163,171,182,192,203,215,228,241,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +// non-zero part of FET channel calculated with: +// level_calc.py 3 1 75 7135 1 200 3000 +// (FIXME? there's a visible bump when the FET kicks in, even with just 1/255) +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,7,8,10,11,13,14,16,17,19,21,22,24,26,28,30,32,34,37,39,41,44,46,48,51,54,56,59,62,65,68,71,74,77,81,84,87,91,94,98,102,106,110,114,118,122,126,130,135,139,144,148,153,158,163,168,173,178,184,189,195,200,206,212,218,224,230,236,242,248,255 +#define PWM_TOPS 4095,2701,3200,3586,2518,2778,2834,2795,2705,2587,2455,2582,2412,2247,2256,2091,2062,1907,1860,1802,1737,1605,1542,1477,1412,1347,1284,1222,1162,1105,1050,997,946,898,853,810,768,730,693,658,625,594,564,536,503,485,462,439,418,398,384,366,353,340,327,319,307,298,292,284,280,273,269,266,263,260,258,256,256,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 + +#define MAX_1x7135 75 +#define DEFAULT_LEVEL 50 +#define MIN_THERM_STEPDOWN 60 +#define HALFSPEED_LEVEL 20 +#define QUARTERSPEED_LEVEL 5 + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 150 +// 20 38 56 [75] 93 111 130 +#define RAMP_DISCRETE_FLOOR 20 +#define RAMP_DISCRETE_CEIL 130 +#define RAMP_DISCRETE_STEPS 7 // at Wurkkos's request, reduce the Simple UI ceiling a little bit -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#define SIMPLE_UI_CEIL 135 -#define SIMPLE_UI_STEPS 5 +// 25 50 [75] 100 125 +#define SIMPLE_UI_FLOOR 25 +#define SIMPLE_UI_CEIL 125 +#define SIMPLE_UI_STEPS 5 // enable 2 click turbo (Anduril 1 style) #define DEFAULT_2C_STYLE 1 +// stop panicking at ~50% power +#define THERM_FASTER_LEVEL 120 // throttle back faster when high + +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// blink numbers on the aux LEDs by default +#define DEFAULT_BLINK_CHANNEL CM_AUXWHT + // enable SOS in the blinkies group #define USE_SOS_MODE #define USE_SOS_MODE_IN_BLINKY_GROUP @@ -67,16 +83,11 @@ // allow Aux Config and Strobe Modes in Simple UI #define USE_EXTENDED_SIMPLE_UI -// enable factory reset on 13H without loosening tailcap -#define USE_SOFT_FACTORY_RESET - -// stop panicking at ~55% power -#define THERM_FASTER_LEVEL 130 // throttle back faster when high - -// don't blink during the ramp or at the ceiling +// don't blink mid-ramp #ifdef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_MIDDLE #endif -#ifdef BLINK_AT_RAMP_CEIL -#undef BLINK_AT_RAMP_CEIL -#endif + +// enable factory reset on 13H without loosening tailcap +#define USE_SOFT_FACTORY_RESET + -- cgit v1.2.3 From e089e2a25a87b64cc09eec931459a5a2bb7698d1 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 09:17:38 -0600 Subject: documented post-off voltage display config --- spaghetti-monster/anduril/anduril-manual.txt | 121 ++++++++++++++------------- 1 file changed, 64 insertions(+), 57 deletions(-) diff --git a/spaghetti-monster/anduril/anduril-manual.txt b/spaghetti-monster/anduril/anduril-manual.txt index aeafed9..a30dcb6 100644 --- a/spaghetti-monster/anduril/anduril-manual.txt +++ b/spaghetti-monster/anduril/anduril-manual.txt @@ -364,74 +364,80 @@ In more detail, this is what each blinky / utility mode does: Battery check: - Blinks out the battery voltage per cell. Full is 4.2V, empty is - about 3.0V. The light blinks the whole-number digit first, pauses, - then blinks out the "tenths" digit. Then a longer pause, and it - repeats. - So for 4.2V, it would be "blink-blink-blink-blink .. blink-blink". - - A "zero" digit is represented by a very quick blink. - - On lights with more than one set of LEDs, pressing 3C during batt - check mode can select which set of LEDs (which channel mode) it - uses to blink out numbers. - - The voltage config menu has one setting: - - 1. Voltage correction factor. This adjusts the battery - measurement sensor, allowing the user to add or subtract up to - 0.30V in 0.05V steps. Click N times to enter a value: - - 1C: -0.30V - 2C: -0.25V - 3C: -0.20V - 4C: -0.15V - 5C: -0.10V - 6C: -0.05V - 7C: default, 0V - 8C: +0.05V - 9C: +0.10V - 10C: +0.15V - 11C: +0.20V - 12C: +0.25V - 13C: +0.30V + Blinks out the battery voltage per cell. Full is 4.2V, empty is + about 3.0V. The light blinks the whole-number digit first, pauses, + then blinks out the "tenths" digit. Then a longer pause, and it + repeats. + So for 4.2V, it would be "blink-blink-blink-blink .. blink-blink". + + A "zero" digit is represented by a very quick blink. + + On lights with more than one set of LEDs, pressing 3C during batt + check mode can select which set of LEDs (which channel mode) it uses + to blink out numbers. + + The voltage config menu has these settings: + + 1. Voltage correction factor. This adjusts the battery + measurement sensor, allowing the user to add or subtract up to + 0.30V in 0.05V steps. Click N times to enter a value: + + 1C: -0.30V + 2C: -0.25V + 3C: -0.20V + 4C: -0.15V + 5C: -0.10V + 6C: -0.05V + 7C: default, 0V + 8C: +0.05V + 9C: +0.10V + 10C: +0.15V + 11C: +0.20V + 12C: +0.25V + 13C: +0.30V + + 2. Post-off voltage display timeout. (only on lights with RGB aux) + This setting determines how many seconds the RGB aux LEDs + display the voltage color after the torch goes to sleep. Click + once per desired second, or zero times to turn this function + off. Temperature check: - Blinks out the current temperature in degrees C. This number - should be pretty close to what a real thermometer says. If not, it - would be a good idea to enter the thermal config menu and calibrate - the sensor. Or let the light settle to room temperature, then use - factory reset to auto-calibrate the sensor. + Blinks out the current temperature in degrees C. This number should + be pretty close to what a real thermometer says. If not, it would + be a good idea to enter the thermal config menu and calibrate the + sensor. Or let the light settle to room temperature, then use + factory reset to auto-calibrate the sensor. - The thermal config menu has two settings: + The thermal config menu has two settings: - - Current temperature. Click once per degree C to calibrate the - sensor. For example, if the ambient temperature is 21 C, then - click 21 times. + - Current temperature. Click once per degree C to calibrate the + sensor. For example, if the ambient temperature is 21 C, then + click 21 times. - - Temperature limit. This sets the maximum temperature the light - can reach before it will start doing thermal regulation to keep - itself from overheating. Click once per degree C above 30. For - example, to set the limit to 50 C, click 20 times. The default - is 45 C, and the highest value it will allow is 70 C. + - Temperature limit. This sets the maximum temperature the light + can reach before it will start doing thermal regulation to keep + itself from overheating. Click once per degree C above 30. For + example, to set the limit to 50 C, click 20 times. The default is + 45 C, and the highest value it will allow is 70 C. Beacon mode: - Blinks at a slow speed. The light stays on for 100ms, and then - stays off until the next blink. The brightness and the number of - seconds between pulses are configurable: + Blinks at a slow speed. The light stays on for 100ms, and then + stays off until the next blink. The brightness and the number of + seconds between pulses are configurable: - - Brightness is the user's memorized ramp level, so set this in - ramping mode before activating beacon mode. Follows the same - memory rules as ramping -- automatic, manual, or hybrid. + - Brightness is the user's memorized ramp level, so set this in + ramping mode before activating beacon mode. Follows the same + memory rules as ramping -- automatic, manual, or hybrid. - - Speed is configured by holding the button. The light should - blink once per second while holding the button. Release it - after the desired amount of time has passed, to set a new - beacon speed. - For example, to do a 10-second alpine beacon, hold the button - for 10 seconds. + - Speed is configured by holding the button. The light should + blink once per second while holding the button. Release it + after the desired amount of time has passed, to set a new beacon + speed. + For example, to do a 10-second alpine beacon, hold the button + for 10 seconds. SOS mode: @@ -939,6 +945,7 @@ Batt check Full 7H Voltage config menu 8: +0.05V 9: +0.10V ... + 2: post-off voltage display seconds Temp check Full 1C Off Temp check Full 2C Next blinky mode (Beacon, SOS, Batt check) -- cgit v1.2.3 From b47dff4574740ad3fac4eb9b26ebb9d0ead6d644 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 10:25:05 -0600 Subject: RGB buttons: while torch is on, use low mode below a configured level for real-time voltage color display, instead of always using high mode --- spaghetti-monster/anduril/anduril.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index bd05ede..ab43df6 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -267,7 +267,8 @@ void loop() { #ifdef USE_AUX_RGB_LEDS_WHILE_ON // display battery charge on RGB button during use - if (! setting_rgb_mode_now) rgb_led_voltage_readout(1); + if (! setting_rgb_mode_now) + rgb_led_voltage_readout(actual_level > USE_AUX_RGB_LEDS_WHILE_ON); #endif if (0) {} // placeholder -- cgit v1.2.3 From c1f60279ca8124b589ac146f6292024f07e2d136 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 10:26:31 -0600 Subject: post-off voltage display was slightly too long, default to 4s, not 5s --- spaghetti-monster/anduril/battcheck-mode-fsm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/battcheck-mode-fsm.h b/spaghetti-monster/anduril/battcheck-mode-fsm.h index 580080c..35c657a 100644 --- a/spaghetti-monster/anduril/battcheck-mode-fsm.h +++ b/spaghetti-monster/anduril/battcheck-mode-fsm.h @@ -9,6 +9,6 @@ // show voltage colors for a few seconds after going to standby #define USE_POST_OFF_VOLTAGE #ifndef DEFAULT_POST_OFF_VOLTAGE_SECONDS - #define DEFAULT_POST_OFF_VOLTAGE_SECONDS 5 + #define DEFAULT_POST_OFF_VOLTAGE_SECONDS 4 #endif #endif -- cgit v1.2.3 From c9905b84356d4926b8ad5e9d104410b7798c4ce8 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 10:42:36 -0600 Subject: added Wurkkos FC13 and TS11 (and a placeholder for the upcoming Noctigon M44) --- spaghetti-monster/anduril/MODELS | 9 +++++++-- spaghetti-monster/anduril/cfg-wurkkos-fc13.h | 17 +++++++++++++++++ spaghetti-monster/anduril/cfg-wurkkos-ts11.h | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 spaghetti-monster/anduril/cfg-wurkkos-fc13.h create mode 100644 spaghetti-monster/anduril/cfg-wurkkos-ts11.h diff --git a/spaghetti-monster/anduril/MODELS b/spaghetti-monster/anduril/MODELS index dfe1190..3a321cd 100644 --- a/spaghetti-monster/anduril/MODELS +++ b/spaghetti-monster/anduril/MODELS @@ -14,15 +14,18 @@ Model Name MCU 0132 emisar-d4s-219c attiny85 0133 emisar-d4sv2 attiny1634 0134 emisar-d4sv2-219 attiny1634 -0135 emisar-d4sv2-tintramp attiny1634 +0135 emisar-2ch attiny1634 +0135 emisar-d4sv2-tintramp attiny1634 (old) 0136 emisar-d4sv2-tintramp-fet attiny1634 0141 emisar-d18 attiny85 0142 emisar-d18-219 attiny85 +0143 noctigon-m44 attiny1634 0211 noctigon-kr4 attiny1634 0212 noctigon-kr4-nofet attiny1634 0213 noctigon-kr4-219 attiny1634 0214 noctigon-kr4-219b attiny1634 -0215 noctigon-kr4-tintramp attiny1634 +0215 noctigon-kr4-2ch attiny1634 +0215 noctigon-kr4-tintramp attiny1634 (old) 0216 noctigon-kr4-12v attiny1634 0251 noctigon-k1 attiny1634 0252 noctigon-k1-sbt90 attiny1634 @@ -64,6 +67,8 @@ Model Name MCU 0632 sofirn-sc21-pro attiny1616 0714 wurkkos-ts10 attiny1616 0715 wurkkos-ts25 attiny1616 +0716 wurkkos-fc13 attiny1616 +0717 wurkkos-ts11 attiny1616 1618 gchart-fet1-t1616 attiny1616 Duplicates: diff --git a/spaghetti-monster/anduril/cfg-wurkkos-fc13.h b/spaghetti-monster/anduril/cfg-wurkkos-fc13.h new file mode 100644 index 0000000..56161b4 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-wurkkos-fc13.h @@ -0,0 +1,17 @@ +// Wurkkos FC13, like a TS25 but with a RGB button and no front aux +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// ATTINY: 1616 +#include "cfg-wurkkos-ts25.h" +#undef MODEL_NUMBER +#define MODEL_NUMBER "0716" + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + +// turn on the aux LEDs while main LEDs are on +#define USE_AUX_RGB_LEDS_WHILE_ON 20 +#define USE_INDICATOR_LED_WHILE_RAMPING + diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts11.h b/spaghetti-monster/anduril/cfg-wurkkos-ts11.h new file mode 100644 index 0000000..8955731 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts11.h @@ -0,0 +1,19 @@ +// Wurkkos TS11, like a TS25 but with a RGB button and RGB front aux +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// ATTINY: 1616 +#include "cfg-wurkkos-ts25.h" +#undef MODEL_NUMBER +#define MODEL_NUMBER "0717" + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + +// turn on the aux LEDs while main LEDs are on +// (but not until the main LEDs are bright enough to overpower the aux) +// (setting this lower makes an annoying effect on some levels) +#define USE_AUX_RGB_LEDS_WHILE_ON 50 +#define USE_INDICATOR_LED_WHILE_RAMPING + -- cgit v1.2.3 From 00dbf2b76cdbad2dbf2fd3b960bcb09d77f932d1 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 2 May 2023 23:44:22 -0600 Subject: post-off voltage display: use low brightness when torch was at moon level before, and skip the voltage display after UI actions which didn't change the mode (like "Off -> 7C" to change aux LED settings) --- spaghetti-monster/anduril/aux-leds.c | 9 +++++++-- spaghetti-monster/anduril/battcheck-mode-fsm.h | 4 ++++ spaghetti-monster/anduril/lockout-mode.c | 20 ++++++++++---------- spaghetti-monster/anduril/off-mode.c | 3 +++ spaghetti-monster/anduril/off-mode.h | 3 +++ spaghetti-monster/fsm-ramping.c | 1 + spaghetti-monster/fsm-ramping.h | 2 ++ 7 files changed, 30 insertions(+), 12 deletions(-) diff --git a/spaghetti-monster/anduril/aux-leds.c b/spaghetti-monster/anduril/aux-leds.c index d833d82..3ecbefd 100644 --- a/spaghetti-monster/anduril/aux-leds.c +++ b/spaghetti-monster/anduril/aux-leds.c @@ -106,8 +106,13 @@ void rgb_led_update(uint8_t mode, uint16_t arg) { #ifdef USE_POST_OFF_VOLTAGE // use voltage high mode for a few seconds after initial poweroff - else if (arg < (cfg.post_off_voltage * SLEEP_TICKS_PER_SECOND)) { - pattern = 2; + // (but not after changing aux LED settings and other similar actions) + else if ((arg < (cfg.post_off_voltage * SLEEP_TICKS_PER_SECOND)) + && (ticks_since_on < (cfg.post_off_voltage * SLEEP_TICKS_PER_SECOND)) + ) { + // use high mode unless prev_level was really low + pattern = 1 + (prev_level >= POST_OFF_VOLTAGE_BRIGHTNESS); + // voltage mode color = RGB_LED_NUM_COLORS - 1; } #endif diff --git a/spaghetti-monster/anduril/battcheck-mode-fsm.h b/spaghetti-monster/anduril/battcheck-mode-fsm.h index 35c657a..5f8e8ec 100644 --- a/spaghetti-monster/anduril/battcheck-mode-fsm.h +++ b/spaghetti-monster/anduril/battcheck-mode-fsm.h @@ -11,4 +11,8 @@ #ifndef DEFAULT_POST_OFF_VOLTAGE_SECONDS #define DEFAULT_POST_OFF_VOLTAGE_SECONDS 4 #endif + #ifndef POST_OFF_VOLTAGE_BRIGHTNESS + // level at which to switch from low to high aux brightness + #define POST_OFF_VOLTAGE_BRIGHTNESS (RAMP_SIZE/10) + #endif #endif diff --git a/spaghetti-monster/anduril/lockout-mode.c b/spaghetti-monster/anduril/lockout-mode.c index c755a61..ee78a19 100644 --- a/spaghetti-monster/anduril/lockout-mode.c +++ b/spaghetti-monster/anduril/lockout-mode.c @@ -39,18 +39,17 @@ uint8_t lockout_state(Event event, uint16_t arg) { // (allow staying awake long enough to exit, but otherwise // be persistent about going back to sleep every few seconds // even if the user keeps pressing the button) - #ifdef USE_INDICATOR_LED - // redundant, sleep tick does the same thing - //if (event == EV_enter_state) { - // indicator_led_update(cfg.indicator_led_mode >> 2, 0); - //} else - #elif defined(USE_AUX_RGB_LEDS) if (event == EV_enter_state) { - rgb_led_update(cfg.rgb_led_lockout_mode, 0); - } else - #endif + ticks_since_on = 0; + #ifdef USE_INDICATOR_LED + // redundant, sleep tick does the same thing + // indicator_led_update(cfg.indicator_led_mode >> 2, 0); + #elif defined(USE_AUX_RGB_LEDS) + rgb_led_update(cfg.rgb_led_lockout_mode, 0); + #endif + } - if (event == EV_tick) { + else if (event == EV_tick) { if (arg > HOLD_TIMEOUT) { go_to_standby = 1; #ifdef USE_INDICATOR_LED @@ -65,6 +64,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { #if defined(TICK_DURING_STANDBY) && (defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS)) else if (event == EV_sleep_tick) { + if (ticks_since_on < 255) ticks_since_on ++; #ifdef USE_MANUAL_MEMORY_TIMER // reset to manual memory level when timer expires if (cfg.manual_memory && diff --git a/spaghetti-monster/anduril/off-mode.c b/spaghetti-monster/anduril/off-mode.c index 103e29d..c1ae2e4 100644 --- a/spaghetti-monster/anduril/off-mode.c +++ b/spaghetti-monster/anduril/off-mode.c @@ -15,6 +15,7 @@ uint8_t off_state(Event event, uint16_t arg) { // turn emitter off when entering state if (event == EV_enter_state) { set_level(0); + ticks_since_on = 0; #ifdef USE_INDICATOR_LED // redundant, sleep tick does the same thing //indicator_led_update(cfg.indicator_led_mode & 0x03, 0); @@ -47,6 +48,7 @@ uint8_t off_state(Event event, uint16_t arg) { #if defined(TICK_DURING_STANDBY) // blink the indicator LED, maybe else if (event == EV_sleep_tick) { + if (ticks_since_on < 255) ticks_since_on ++; #ifdef USE_MANUAL_MEMORY_TIMER // reset to manual memory level when timer expires if (cfg.manual_memory && @@ -141,6 +143,7 @@ uint8_t off_state(Event event, uint16_t arg) { // click, hold: momentary at ceiling or turbo else if (event == EV_click2_hold) { + ticks_since_on = 0; // momentary turbo is definitely "on" uint8_t turbo_level; // how bright is "turbo"? #if defined(USE_2C_STYLE_CONFIG) // user can choose 2C behavior diff --git a/spaghetti-monster/anduril/off-mode.h b/spaghetti-monster/anduril/off-mode.h index 71d45eb..d07fff1 100644 --- a/spaghetti-monster/anduril/off-mode.h +++ b/spaghetti-monster/anduril/off-mode.h @@ -4,6 +4,9 @@ #pragma once +// was the light in an "on" mode within the past second or so? +uint8_t ticks_since_on = 0; + // when the light is "off" or in standby uint8_t off_state(Event event, uint16_t arg); diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c index 393c425..d4e2068 100644 --- a/spaghetti-monster/fsm-ramping.c +++ b/spaghetti-monster/fsm-ramping.c @@ -71,6 +71,7 @@ void set_level(uint8_t level) { SetLevelFuncPtr set_level_func = channel_modes[CH_MODE]; set_level_func(level); + if (actual_level != level) prev_level = actual_level; actual_level = level; #ifdef USE_SET_LEVEL_GRADUALLY diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 3003ecb..8d5ed27 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -8,6 +8,8 @@ // actual_level: last ramp level set by set_level() uint8_t actual_level = 0; +// the level used before actual +uint8_t prev_level = 0; // TODO: size-optimize the case with only 1 channel mode // (the arrays and stuff shouldn't be needed) -- cgit v1.2.3 From f9fdd5937c65df328f2c2bf810115291e219aabe Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 17 May 2023 15:41:37 -0600 Subject: converted Noctigon DM11-12V build, renamed to noctigon-dm11-boost --- hwdef-Noctigon_DM11-12V.h | 166 --------------- hwdef-noctigon-dm11-boost.c | 47 +++++ hwdef-noctigon-dm11-boost.h | 226 +++++++++++++++++++++ spaghetti-monster/anduril/MODELS | 3 +- spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h | 79 ------- .../anduril/cfg-noctigon-dm11-boost.h | 81 ++++++++ 6 files changed, 356 insertions(+), 246 deletions(-) delete mode 100644 hwdef-Noctigon_DM11-12V.h create mode 100644 hwdef-noctigon-dm11-boost.c create mode 100644 hwdef-noctigon-dm11-boost.h delete mode 100644 spaghetti-monster/anduril/cfg-noctigon-dm11-12v.h create mode 100644 spaghetti-monster/anduril/cfg-noctigon-dm11-boost.h diff --git a/hwdef-Noctigon_DM11-12V.h b/hwdef-Noctigon_DM11-12V.h deleted file mode 100644 index 104b6ae..0000000 --- a/hwdef-Noctigon_DM11-12V.h +++ /dev/null @@ -1,166 +0,0 @@ -// Noctigon DM11 (12V) driver layout (attiny1634) -// Copyright (C) 2021-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * (based on Noctigon K1) - * - * Pin / Name / Function - * 1 PA6 (none) (PWM1B) (reserved for DD drivers) - * 2 PA5 R: red aux LED (PWM0B) - * 3 PA4 G: green aux LED - * 4 PA3 B: blue aux LED - * 5 PA2 L: button LED - * 6 PA1 (none) - * 7 PA0 (none) - * 8 GND GND - * 9 VCC VCC - * 10 PC5 (none) - * 11 PC4 (none) - * 12 PC3 RESET - * 13 PC2 (none) - * 14 PC1 SCK - * 15 PC0 boost PMIC enable (PWM0A not used) - * 16 PB3 main LED PWM (PWM1A) - * 17 PB2 MISO / e-switch? (PCINT10) - * 18 PB1 MOSI / battery voltage (ADC6) - * 19 PB0 Opamp power - * 20 PA7 e-switch? (PCINT7) - * ADC12 thermal sensor - * - * Main LED power uses one pin to turn the Opamp on/off, - * and one pin to control Opamp power level. - * Linear brightness control uses the power level pin, with dynamic PWM. - * The on/off pin is only used to turn the main LED on and off, - * not to change brightness. - */ - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1634 -#include - -#define PWM_CHANNELS 1 // can't use DD FET on boost drivers -#define PWM_BITS 16 // data type needs 16 bits, not 8 -#define PWM_TOP 255 // highest value used in top half of ramp -#define USE_DYN_PWM // dynamic frequency and speed - -//#define SWITCH_PIN PB2 // pin 17 -//#define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt -//#define SWITCH_PCIE PCIE1 // PCIE1 is for PCINT[11:8] -//#define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] -//#define SWITCH_PORT PINB // PINA or PINB or PINC -//#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] - -#define SWITCH_PIN PA7 // pin 20 -#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt -#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] -#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] -#define SWITCH_PORT PINA // PINA or PINB or PINC - -#define PWM1_PIN PB3 // pin 16, Opamp reference -#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 -#define PWM1_CNT TCNT1 // for dynamic PWM, reset phase -#define PWM1_PHASE_RESET_OFF // force reset while shutting off -#define PWM1_PHASE_RESET_ON // force reset while turning on -#define PWM1_PHASE_SYNC // manual sync while changing level - -// PWM parameters of both channels are tied together because they share a counter -#define PWM1_TOP ICR1 // holds the TOP value for for variable-resolution PWM - -#define LED_ENABLE_PIN PB0 // pin 19, Opamp power -#define LED_ENABLE_PORT PORTB // control port for PB0 - -#define LED2_ENABLE_PIN PC0 // pin 15, boost PMIC enable -#define LED2_ENABLE_PORT PORTC // control port for PC0 - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -#define BUTTON_LED_PIN PA2 // pin 5 -#define BUTTON_LED_PORT PORTA // for all "PA" pins -#define BUTTON_LED_DDR DDRA // for all "PA" pins -#define BUTTON_LED_PUE PUEA // for all "PA" pins - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - // enable output ports - // boost PMIC on/off - DDRC = (1 << LED2_ENABLE_PIN); - // Opamp level and Opamp on/off - DDRB = (1 << PWM1_PIN) - | (1 << LED_ENABLE_PIN); - // aux R/G/B, button LED - DDRA = (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - | (1 << BUTTON_LED_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 0,0: PWM OC1B disabled (DS table 12-4) - TCCR1A = (1< (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + + GRADUAL_ADJUST_SIMPLE(pwm1, CH1_PWM); + + if ( (pwm1 == CH1_PWM) + ) { + return true; // done + } + return false; // not done yet +} + diff --git a/hwdef-noctigon-dm11-boost.h b/hwdef-noctigon-dm11-boost.h new file mode 100644 index 0000000..e4d009d --- /dev/null +++ b/hwdef-noctigon-dm11-boost.h @@ -0,0 +1,226 @@ +// Noctigon DM11 boost driver layout (attiny1634) +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * (based on Noctigon K1) + * + * Pin / Name / Function + * 1 PA6 (none) (PWM1B) (reserved for DD drivers) + * 2 PA5 R: red aux LED (PWM0B) + * 3 PA4 G: green aux LED + * 4 PA3 B: blue aux LED + * 5 PA2 L: button LED + * 6 PA1 (none) + * 7 PA0 (none) + * 8 GND GND + * 9 VCC VCC + * 10 PC5 (none) + * 11 PC4 (none) + * 12 PC3 RESET + * 13 PC2 (none) + * 14 PC1 SCK + * 15 PC0 boost PMIC enable (PWM0A not used) + * 16 PB3 main LED PWM (PWM1A) + * 17 PB2 MISO (PCINT10) + * 18 PB1 MOSI / battery voltage (ADC6) + * 19 PB0 Opamp power + * 20 PA7 e-switch (PCINT7) + * ADC12 thermal sensor + * + * Main LED power uses one pin to turn the Opamp on/off, + * and one pin to control Opamp power level. + * Linear brightness control uses the power level pin, with dynamic PWM. + * The on/off pin is only used to turn the main LED on and off, + * not to change brightness. + */ + +#define ATTINY 1634 +#include + +#define HWDEF_C_FILE hwdef-noctigon-dm11-boost.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +#define USE_CHANNEL_MODES +// channel modes: +// * 0. main LEDs +// * 1. aux red +// * 2. aux yellow +// * 3. aux green +// * 4. aux cyan +// * 5. aux blue +// * 6. aux purple +// * 7. aux white +#define NUM_CHANNEL_MODES 8 +enum CHANNEL_MODES { + CM_MAIN = 0, + CM_AUXRED, + CM_AUXYEL, + CM_AUXGRN, + CM_AUXCYN, + CM_AUXBLU, + CM_AUXPRP, + CM_AUXWHT, +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +#define CHANNEL_MODES_ENABLED 0b00000001 +#define CHANNEL_HAS_ARGS 0b00000000 +// no args +//#define USE_CHANNEL_MODE_ARGS +//#define CHANNEL_MODE_ARGS 0,0,0,0,0,0,0,0 + +#define SET_LEVEL_MODES set_level_main, \ + set_level_auxred, \ + set_level_auxyel, \ + set_level_auxgrn, \ + set_level_auxcyn, \ + set_level_auxblu, \ + set_level_auxprp, \ + set_level_auxwht +// gradual ticking for thermal regulation +#define GRADUAL_TICK_MODES gradual_tick_main, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null + + +#define PWM_CHANNELS 1 // old, remove this + +#define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // 1x7135 ramp + +#define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 255 // highest value used in top half of ramp +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +#define CH1_PIN PB3 // pin 16, Opamp reference +#define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 + +#define PWM1_PHASE_RESET_OFF // force reset while shutting off +#define PWM1_PHASE_RESET_ON // force reset while turning on +#define PWM1_PHASE_SYNC // manual sync while changing level + +#define LED_ENABLE_PIN PB0 // pin 19, Opamp power +#define LED_ENABLE_PORT PORTB // control port for PB0 + +#define LED_ENABLE_PIN2 PC0 // pin 15, boost PMIC enable +#define LED_ENABLE_PORT2 PORTC // control port for PC0 + +// e-switch +#define SWITCH_PIN PA7 // pin 20 +#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt +#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] +#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] +#define SWITCH_PORT PINA // PINA or PINB or PINC +#define SWITCH_PUE PUEA // pullup group A +#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 +// pin to ADC mappings are in DS table 19-4 +#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 +// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 +#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D +// DS tables 19-3, 19-4 +// Bit 7 6 5 4 3 2 1 0 +// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 +// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 +// divided by ... +// REFS[1:0] = 1, 0 for internal 1.1V reference +// other bits reserved +#define ADMUX_VOLTAGE_DIVIDER 0b10000110 +#define ADC_PRSCL 0x07 // clk/128 + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// D1, R1, R2 = 0, 330, 100 +#ifndef ADC_44 +//#define ADC_44 981 // raw value at 4.40V +#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 +#endif +#ifndef ADC_22 +//#define ADC_22 489 // raw value at 2.20V +#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 +#endif + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + +#define BUTTON_LED_PIN PA2 // pin 5 +#define BUTTON_LED_PORT PORTA // for all "PA" pins +#define BUTTON_LED_DDR DDRA // for all "PA" pins +#define BUTTON_LED_PUE PUEA // for all "PA" pins + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS +// it also has an independent LED in the button +#define USE_BUTTON_LED +// the aux LEDs are front-facing, so turn them off while main LEDs are on +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif + +void set_level_main(uint8_t level); + +bool gradual_tick_main(uint8_t gt); + + +inline void hwdef_setup() { + // enable output ports + // boost PMIC on/off + DDRC = (1 << LED_ENABLE_PIN2); + // Opamp level and Opamp on/off + DDRB = (1 << CH1_PIN) + | (1 << LED_ENABLE_PIN); + // aux R/G/B, button LED + DDRA = (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + | (1 << BUTTON_LED_PIN) + ; + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 0,0: PWM OC1B disabled (DS table 12-4) + TCCR1A = (1< end of dynamic PWM range - -//#define THERM_RESPONSE_MAGNITUDE 32 // smaller adjustments, this host changes temperature slowly -//#define THERM_NEXT_WARNING_THRESHOLD 32 // more error tolerance before adjusting - -// slow down party strobe; this driver can't pulse for 2ms or less -#define PARTY_STROBE_ONTIME 3 - -#define THERM_CAL_OFFSET 5 - -// the power regulator seems to "jump start" the LEDs all on its own, -// so the firmware doesn't have to -// (and unfortunately the power regulator jumps it a bit too hard) -#define DEFAULT_JUMP_START_LEVEL 1 -#define BLINK_BRIGHTNESS 50 -#define BLINK_ONCE_TIME 12 - -// added for convenience -#define USE_SOFT_FACTORY_RESET - diff --git a/spaghetti-monster/anduril/cfg-noctigon-dm11-boost.h b/spaghetti-monster/anduril/cfg-noctigon-dm11-boost.h new file mode 100644 index 0000000..231944c --- /dev/null +++ b/spaghetti-monster/anduril/cfg-noctigon-dm11-boost.h @@ -0,0 +1,81 @@ +// Noctigon DM11 (boost driver) config options for Anduril +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#define MODEL_NUMBER "0273" +#include "hwdef-noctigon-dm11-boost.h" +#include "hank-cfg.h" +// ATTINY: 1634 + +#define RAMP_SIZE 150 + +// power channels: +// - boost: 8A? +// - DD FET: none (can't do DD on a boost driver) + +// level_calc.py 5.01 1 149 7135 1 0.3 1740 --pwm dyn:78:16384:255 +// (plus a 0 at the beginning for moon) +#define PWM1_LEVELS 0,1,1,1,2,3,3,4,5,6,7,8,9,10,11,13,14,16,17,19,21,23,25,27,29,31,34,36,39,42,44,47,50,53,57,60,63,67,70,74,77,81,85,88,92,96,99,103,107,110,113,117,120,123,126,128,130,133,134,136,137,137,137,137,136,135,133,130,126,122,117,111,104,96,87,76,65,52,38,22,23,25,26,27,28,29,30,32,33,34,36,37,39,40,42,43,45,47,49,51,53,55,57,59,61,63,66,68,70,73,76,78,81,84,87,90,93,96,99,103,106,110,113,117,121,125,129,133,137,142,146,151,155,160,165,170,175,181,186,192,197,203,209,215,222,228,234,241,248,255 +#define PWM_TOPS 16383,16383,12404,8140,11462,14700,11041,12947,13795,14111,14124,13946,13641,13248,12791,13418,12808,13057,12385,12428,12358,12209,12000,11746,11459,11147,11158,10793,10708,10576,10173,9998,9800,9585,9527,9278,9023,8901,8634,8486,8216,8053,7881,7615,7440,7261,7009,6832,6656,6422,6196,6031,5819,5615,5419,5190,4973,4803,4571,4386,4179,3955,3745,3549,3340,3145,2940,2729,2513,2312,2109,1903,1697,1491,1286,1070,871,662,459,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 + +#define DEFAULT_LEVEL 70 +#define MAX_1x7135 150 +#define HALFSPEED_LEVEL 12 +#define QUARTERSPEED_LEVEL 4 + +#define RAMP_SMOOTH_FLOOR 10 // low levels may be unreliable +#define RAMP_SMOOTH_CEIL 130 +// 10, 30, 50, [70], 90, 110, 130 +// Nichia B35 model: (0.56), 1.4, 8.4, 34.5, [102], 250, 500, 860, (1300) lm +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 + +// safe limit ~75% power +#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR +#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL +#define SIMPLE_UI_STEPS 5 + +// stop panicking at ~70% power or ~600 lm +#define THERM_FASTER_LEVEL 130 +#define MIN_THERM_STEPDOWN 80 // must be > end of dynamic PWM range + +#define THERM_CAL_OFFSET 5 + +//#define THERM_RESPONSE_MAGNITUDE 32 // smaller adjustments, this host changes temperature slowly +//#define THERM_NEXT_WARNING_THRESHOLD 32 // more error tolerance before adjusting + +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// blink numbers on the aux LEDs by default +#define DEFAULT_BLINK_CHANNEL CM_AUXWHT + +// use aux red + aux blue for police strobe +#define USE_POLICE_COLOR_STROBE_MODE +#define POLICE_STROBE_USES_AUX +#define POLICE_COLOR_STROBE_CH1 CM_AUXRED +#define POLICE_COLOR_STROBE_CH2 CM_AUXBLU + +// the default of 26 looks a bit rough, so increase it to make it smoother +#define CANDLE_AMPLITUDE 33 + +// slow down party strobe; this driver can't pulse for 2ms or less +#define PARTY_STROBE_ONTIME 3 + +// the power regulator seems to "jump start" the LEDs all on its own, +// so the firmware doesn't have to +// (and unfortunately the power regulator jumps it a bit too hard) +#define DEFAULT_JUMP_START_LEVEL 1 +#define BLINK_BRIGHTNESS 50 +#define BLINK_ONCE_TIME 12 + +// added for convenience +#define USE_SOFT_FACTORY_RESET + +// don't blink halfway up +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + -- cgit v1.2.3 From 91ca88356ecd234a9eb6e7e5b3170103913f36f9 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 30 May 2023 06:10:39 -0600 Subject: fixed bug: regulated down on some lights when not hot (thermal calibration needs a signed integer, not unsigned) --- spaghetti-monster/anduril/load-save-config-fsm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h index 862cf26..64ff6fd 100644 --- a/spaghetti-monster/anduril/load-save-config-fsm.h +++ b/spaghetti-monster/anduril/load-save-config-fsm.h @@ -87,7 +87,7 @@ typedef struct Config { #endif #ifdef USE_THERMAL_REGULATION uint8_t therm_ceil; - uint8_t therm_cal_offset; + int8_t therm_cal_offset; #endif ///// aux LEDs -- cgit v1.2.3 From 6415a13625eadb2793b888c3fa2c92e115b9a335 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 30 May 2023 06:12:18 -0600 Subject: gradual adjustments: handle 0-to-255 in one step on the way up too, not just down --- spaghetti-monster/fsm-ramping.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 8d5ed27..36cf89c 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -115,7 +115,7 @@ void gradual_tick(); #define GRADUAL_ADJUST_STACKED(TARGET,PWM,TOP) \ if ( ((PWM == 0) && (TARGET == TOP)) \ || ((PWM == TOP) && (TARGET == 0))) \ - PWM = TOP; \ + PWM = TARGET; \ else GRADUAL_ADJUST_SIMPLE(TARGET,PWM) // tick the top layer of the stack -- cgit v1.2.3 From 83e7dc7cc45e789b819c1dec2f419252ebdf5eae Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 30 May 2023 06:17:01 -0600 Subject: synced configs between D4v2 and KR4 --- hwdef-emisar-d4v2.h | 4 +-- hwdef-noctigon-kr4.h | 40 ++++++++++++++++++++-------- spaghetti-monster/anduril/cfg-emisar-d4v2.h | 4 +-- spaghetti-monster/anduril/cfg-noctigon-kr4.h | 27 ++++++------------- 4 files changed, 41 insertions(+), 34 deletions(-) diff --git a/hwdef-emisar-d4v2.h b/hwdef-emisar-d4v2.h index a502421..728d9e4 100644 --- a/hwdef-emisar-d4v2.h +++ b/hwdef-emisar-d4v2.h @@ -64,7 +64,7 @@ enum CHANNEL_MODES { #define CHANNEL_HAS_ARGS 0b00000000 // no args //#define USE_CHANNEL_MODE_ARGS -//#define CHANNEL_MODE_ARGS 0,0,0,0 +//#define CHANNEL_MODE_ARGS 0,0,0,0,0,0,0,0 #define SET_LEVEL_MODES set_level_main, \ set_level_auxred, \ @@ -105,7 +105,7 @@ enum CHANNEL_MODES { // DD FET channel #define CH2_PIN PA6 // pin 1, DD FET PWM -#define CH2_PWM OCR1B // OCR1B is the output compare register for PB1 +#define CH2_PWM OCR1B // OCR1B is the output compare register for PA6 // e-switch #define SWITCH_PIN PA2 // pin 5 diff --git a/hwdef-noctigon-kr4.h b/hwdef-noctigon-kr4.h index d6c33ff..806aeab 100644 --- a/hwdef-noctigon-kr4.h +++ b/hwdef-noctigon-kr4.h @@ -48,28 +48,46 @@ // channel modes: // * 0. linear + DD FET stacked // * 1. aux red -// * 2. aux green -// * 3. aux blue -#define NUM_CHANNEL_MODES 4 -#define CM_MAIN 0 -#define CM_AUXRED 1 -#define CM_AUXGRN 2 -#define CM_AUXBLU 3 - -#define DEFAULT_CHANNEL_MODE CM_MAIN +// * 2. aux yellow +// * 3. aux green +// * 4. aux cyan +// * 5. aux blue +// * 6. aux purple +// * 7. aux white +#define NUM_CHANNEL_MODES 8 +enum CHANNEL_MODES { + CM_MAIN = 0, + CM_AUXRED, + CM_AUXYEL, + CM_AUXGRN, + CM_AUXCYN, + CM_AUXBLU, + CM_AUXPRP, + CM_AUXWHT, +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN #define CHANNEL_MODES_ENABLED 0b00000001 #define CHANNEL_HAS_ARGS 0b00000000 // no args //#define USE_CHANNEL_MODE_ARGS -//#define CHANNEL_MODE_ARGS 0,0,0,0 +//#define CHANNEL_MODE_ARGS 0,0,0,0,0,0,0,0 #define SET_LEVEL_MODES set_level_main, \ set_level_auxred, \ + set_level_auxyel, \ set_level_auxgrn, \ - set_level_auxblu + set_level_auxcyn, \ + set_level_auxblu, \ + set_level_auxprp, \ + set_level_auxwht // gradual ticking for thermal regulation #define GRADUAL_TICK_MODES gradual_tick_main, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ + gradual_tick_null, \ gradual_tick_null, \ gradual_tick_null, \ gradual_tick_null diff --git a/spaghetti-monster/anduril/cfg-emisar-d4v2.h b/spaghetti-monster/anduril/cfg-emisar-d4v2.h index f68e50f..0f0bb17 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4v2.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4v2.h @@ -45,8 +45,8 @@ // show each channel while it scroll by in the menu #define USE_CONFIG_COLORS -// blink numbers on the aux LEDs by default -#define DEFAULT_BLINK_CHANNEL CM_AUXWHT +// blink numbers on the main LEDs by default (but allow user to change it) +#define DEFAULT_BLINK_CHANNEL CM_MAIN // use aux red + aux blue for police strobe #define USE_POLICE_COLOR_STROBE_MODE diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index 78c76de..d2e8107 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -9,18 +9,6 @@ #include "hank-cfg.h" // ATTINY: 1634 -// this light has three aux LED channels: R, G, B -#define USE_AUX_RGB_LEDS -// the aux LEDs are front-facing, so turn them off while main LEDs are on -// it also has an independent LED in the button (D4v2.5 titanium/brass only) -#define USE_BUTTON_LED -// TODO: the whole "indicator LED" thing needs to be refactored into -// "aux LED(s)" and "button LED(s)" since they work a bit differently -// enabling this option breaks the button LED on D4v2.5 -#ifdef USE_INDICATOR_LED_WHILE_RAMPING -#undef USE_INDICATOR_LED_WHILE_RAMPING -#endif - // brightness w/ SST-20 4000K LEDs: // 0/1023: 0.35 lm // 1/1023: 2.56 lm @@ -31,9 +19,9 @@ // nice low lows, but might have visible ripple on some lights: // maxreg at 130, dynamic PWM: level_calc.py 5.01 2 149 7135 1 0.3 1740 FET 1 10 3190 --pwm dyn:64:16384:255 // (plus one extra level at the beginning for moon) -#define PWM1_LEVELS 0,1,1,2,2,3,4,5,6,7,8,9,11,12,14,16,17,19,22,24,26,29,31,34,37,40,43,46,49,53,56,60,63,67,71,74,78,82,86,89,93,96,99,103,105,108,110,112,114,115,116,116,115,114,112,109,106,101,95,89,81,71,60,48,34,19,20,21,22,23,24,26,27,28,30,31,32,34,36,37,39,41,43,45,47,49,51,53,56,58,61,63,66,69,72,75,78,81,84,88,91,95,99,103,107,111,115,119,124,129,133,138,143,149,154,159,165,171,177,183,189,196,203,210,217,224,231,239,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,20,30,41,52,63,75,87,99,112,125,138,151,165,179,194,208,224,239,255 -#define PWM_TOPS 16383,16383,11750,14690,9183,12439,13615,13955,13877,13560,13093,12529,13291,12513,12756,12769,11893,11747,12085,11725,11329,11316,10851,10713,10518,10282,10016,9729,9428,9298,8971,8794,8459,8257,8043,7715,7497,7275,7052,6753,6538,6260,5994,5798,5501,5271,5006,4758,4525,4268,4030,3775,3508,3263,3010,2752,2517,2256,1998,1763,1512,1249,994,749,497,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#define PWM1_LEVELS 0,1,1,2,2,3,4,5,6,7,8,9,11,12,14,16,17,19,22,24,26,29,31,34,37,40,43,46,49,53,56,60,63,67,71,74,78,82,86,89,93,96,99,103,105,108,110,112,114,115,116,116,115,114,112,109,106,101,95,89,81,71,60,48,34,19,20,21,22,23,24,26,27,28,30,31,32,34,36,37,39,41,43,45,47,49,51,53,56,58,61,63,66,69,72,75,78,81,84,88,91,95,99,103,107,111,115,119,124,129,133,138,143,149,154,159,165,171,177,183,189,196,203,210,217,224,231,239,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,20,30,41,52,63,75,87,99,112,125,138,151,165,179,194,208,224,239,255 +#define PWM_TOPS 16383,16383,11750,14690,9183,12439,13615,13955,13877,13560,13093,12529,13291,12513,12756,12769,11893,11747,12085,11725,11329,11316,10851,10713,10518,10282,10016,9729,9428,9298,8971,8794,8459,8257,8043,7715,7497,7275,7052,6753,6538,6260,5994,5798,5501,5271,5006,4758,4525,4268,4030,3775,3508,3263,3010,2752,2517,2256,1998,1763,1512,1249,994,749,497,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // less ripple, but lows are a bit higher than ideal: // maxreg at 130, dynamic PWM: level_calc.py 5.01 2 149 7135 1 0.3 1740 FET 1 10 3190 --pwm dyn:64:4096:255 @@ -44,6 +32,7 @@ #define MAX_1x7135 130 #define DEFAULT_LEVEL 50 +//#define MIN_THERM_STEPDOWN 66 // should be above highest dyn_pwm level #define HALFSPEED_LEVEL 12 #define QUARTERSPEED_LEVEL 4 @@ -61,10 +50,6 @@ // stop panicking at ~1300 lm #define THERM_FASTER_LEVEL 120 -#define MIN_THERM_STEPDOWN 66 // must be > end of dynamic PWM range -// no longer needed, after switching to dynamic PWM -//#define THERM_NEXT_WARNING_THRESHOLD 16 // accumulate less error before adjusting -//#define THERM_RESPONSE_MAGNITUDE 128 // bigger adjustments #define THERM_CAL_OFFSET 5 @@ -77,6 +62,10 @@ // show each channel while it scroll by in the menu #define USE_CONFIG_COLORS +// there is usually no lighted button, +// so blink numbers on the main LEDs by default (but allow user to change it) +#define DEFAULT_BLINK_CHANNEL CM_MAIN + // slow down party strobe; this driver can't pulse for 1ms or less // (only needed on no-FET build) //#define PARTY_STROBE_ONTIME 2 -- cgit v1.2.3 From 803191510e07ebc6567158c47cff8b9893a16465 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 30 May 2023 06:18:12 -0600 Subject: with each build, dump a .cpp file with the source after preprocessing (for easier whole-program debugging) --- bin/build.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/build.sh b/bin/build.sh index 4cb03b4..a6169d1 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -27,9 +27,11 @@ fi export MCU=attiny$ATTINY export CC=avr-gcc +export CPP=avr-cpp export OBJCOPY=avr-objcopy export DFPFLAGS="-B $ATTINY_DFP/gcc/dev/$MCU/ -I $ATTINY_DFP/include/" -export CFLAGS="-Wall -g -Os -mmcu=$MCU -c -std=gnu99 -fgnu89-inline -fwhole-program -DATTINY=$ATTINY -I.. -I../.. -I../../.. -fshort-enums $DFPFLAGS" +export CFLAGS=" -Wall -g -Os -mmcu=$MCU -c -std=gnu99 -fgnu89-inline -fwhole-program -DATTINY=$ATTINY -I.. -I../.. -I../../.. -fshort-enums $DFPFLAGS" +export CPPFLAGS="-Wall -g -Os -mmcu=$MCU -C -std=gnu99 -fgnu89-inline -fwhole-program -DATTINY=$ATTINY -I.. -I../.. -I../../.. -fshort-enums $DFPFLAGS" export OFLAGS="-Wall -g -Os -mmcu=$MCU -mrelax $DFPFLAGS" export LDFLAGS="-fgnu89-inline" export OBJCOPYFLAGS='--set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex --remove-section .fuse' @@ -45,6 +47,8 @@ function run () { if [ x"$?" != x0 ]; then exit 1 ; fi } +run $CPP $OTHERFLAGS $CPPFLAGS -o foo.cpp $PROGRAM.c +grep --text -E -v '^#|^$' foo.cpp > $PROGRAM.cpp ; rm foo.cpp run $CC $OTHERFLAGS $CFLAGS -o $PROGRAM.o -c $PROGRAM.c run $CC $OFLAGS $LDFLAGS -o $PROGRAM.elf $PROGRAM.o run $OBJCOPY $OBJCOPYFLAGS $PROGRAM.elf $PROGRAM.hex -- cgit v1.2.3 From 3b2186b30b8b097263ec49d7d440da398684ef8b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 30 May 2023 06:19:52 -0600 Subject: Wurkkos models: add red+blue police strobe --- spaghetti-monster/anduril/cfg-wurkkos-ts25.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts25.h b/spaghetti-monster/anduril/cfg-wurkkos-ts25.h index 446ee26..26dc493 100644 --- a/spaghetti-monster/anduril/cfg-wurkkos-ts25.h +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts25.h @@ -73,6 +73,12 @@ // blink numbers on the aux LEDs by default #define DEFAULT_BLINK_CHANNEL CM_AUXWHT +// use aux red + aux blue for police strobe +#define USE_POLICE_COLOR_STROBE_MODE +#define POLICE_STROBE_USES_AUX +#define POLICE_COLOR_STROBE_CH1 CM_AUXRED +#define POLICE_COLOR_STROBE_CH2 CM_AUXBLU + // enable SOS in the blinkies group #define USE_SOS_MODE #define USE_SOS_MODE_IN_BLINKY_GROUP -- cgit v1.2.3 From ff41bca13f218ffb14ad71c3efe258039488a937 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 30 May 2023 06:59:57 -0600 Subject: changed version check from YYYYMMDDXXXX to XXXX.YYYY-MM-DD, where the punctuation makes a "buzz" instead of number blinks --- spaghetti-monster/anduril/build-all.sh | 2 +- spaghetti-monster/anduril/version-check-mode.c | 15 +++++++++------ spaghetti-monster/anduril/version-check-mode.h | 2 +- spaghetti-monster/anduril/version.h | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/spaghetti-monster/anduril/build-all.sh b/spaghetti-monster/anduril/build-all.sh index 768559c..b3fc5d3 100755 --- a/spaghetti-monster/anduril/build-all.sh +++ b/spaghetti-monster/anduril/build-all.sh @@ -9,7 +9,7 @@ fi UI=anduril -date '+#define VERSION_NUMBER "%Y%m%d"' > version.h +date '+#define VERSION_NUMBER "%Y-%m-%d"' > version.h PASS=0 FAIL=0 diff --git a/spaghetti-monster/anduril/version-check-mode.c b/spaghetti-monster/anduril/version-check-mode.c index 2b7112e..a47706f 100644 --- a/spaghetti-monster/anduril/version-check-mode.c +++ b/spaghetti-monster/anduril/version-check-mode.c @@ -14,14 +14,17 @@ uint8_t version_check_state(Event event, uint16_t arg) { // this happens in FSM loop() inline void version_check_iter() { for (uint8_t i=0; i 0) // don't blink red on 1st frame ) { // use high mode unless prev_level was really low pattern = 1 + (prev_level >= POST_OFF_VOLTAGE_BRIGHTNESS); -- cgit v1.2.3 From 3bf052387709ab2fcffcacf91dec7302f7c0e50c Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 29 Jun 2023 02:44:53 -0600 Subject: Removed references to Harry Potter, because J.K. Rowling is the figurehead of a hate group and I don't want to condone that in any way. I liked a 2-word phrase she wrote once, "mischief managed", but that was decades ago... and now she is the face of a transphobic movement known as TERFs. She turned out to be a pretty terrible person who uses her massive wealth and influence to spread hate and oppress people. To be clear: Trans rights are human rights. ... and anyone who has a problem with that has no place in this project. Patch suggested by SiteRelEnby, and TBH it's embarrassing that I didn't remove the phrase sooner. It seemed fun and innocent in 2017 when this project started, but ... things changed. https://github.com/SiteRelEnby/anduril2/commit/a1cee423b4e0e16909a90d5c3e6a7b70df30d755 --- spaghetti-monster/anduril/battcheck-mode.c | 6 +- spaghetti-monster/anduril/beacon-mode.c | 8 +- spaghetti-monster/anduril/candle-mode.c | 14 +- spaghetti-monster/anduril/channel-modes.c | 2 +- spaghetti-monster/anduril/config-mode.c | 4 +- spaghetti-monster/anduril/ff-strobe-modes.c | 6 +- spaghetti-monster/anduril/lockout-mode.c | 22 ++-- spaghetti-monster/anduril/momentary-mode.c | 6 +- spaghetti-monster/anduril/off-mode.c | 56 ++++---- spaghetti-monster/anduril/ramp-mode.c | 44 +++---- spaghetti-monster/anduril/sos-mode.c | 4 +- spaghetti-monster/anduril/strobe-modes.c | 20 +-- spaghetti-monster/anduril/sunset-timer.c | 6 +- spaghetti-monster/anduril/tactical-mode.c | 2 +- spaghetti-monster/anduril/tempcheck-mode.c | 6 +- spaghetti-monster/baton/baton.c | 4 +- spaghetti-monster/darkhorse/darkhorse.c | 16 +-- spaghetti-monster/fireflies-ui/fireflies-ui.c | 180 +++++++++++++------------- spaghetti-monster/meteor/meteor.c | 16 +-- spaghetti-monster/ramping-ui/ramping-ui.c | 62 ++++----- spaghetti-monster/rampingios/rampingiosv3.c | 100 +++++++------- spaghetti-monster/werner/werner.c | 64 ++++----- 22 files changed, 324 insertions(+), 324 deletions(-) diff --git a/spaghetti-monster/anduril/battcheck-mode.c b/spaghetti-monster/anduril/battcheck-mode.c index 0ef6b0a..462540e 100644 --- a/spaghetti-monster/anduril/battcheck-mode.c +++ b/spaghetti-monster/anduril/battcheck-mode.c @@ -16,7 +16,7 @@ uint8_t battcheck_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: next blinky mode @@ -28,7 +28,7 @@ uint8_t battcheck_state(Event event, uint16_t arg) { #elif defined(USE_SOS_MODE) && defined(USE_SOS_MODE_IN_BLINKY_GROUP) set_state(sos_state, 0); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef DEFAULT_BLINK_CHANNEL @@ -44,7 +44,7 @@ uint8_t battcheck_state(Event event, uint16_t arg) { // 7H: voltage config mode else if (event == EV_click7_hold) { push_state(voltage_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif diff --git a/spaghetti-monster/anduril/beacon-mode.c b/spaghetti-monster/anduril/beacon-mode.c index 6359b74..5aff508 100644 --- a/spaghetti-monster/anduril/beacon-mode.c +++ b/spaghetti-monster/anduril/beacon-mode.c @@ -19,7 +19,7 @@ uint8_t beacon_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // TODO: use sleep ticks to measure time between pulses, // to save power @@ -33,20 +33,20 @@ uint8_t beacon_state(Event event, uint16_t arg) { #elif defined(USE_THERMAL_REGULATION) set_state(tempcheck_state, 0); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: configure beacon timing else if (event == EV_click1_hold) { if (0 == (arg % TICKS_PER_SECOND)) { blink_once(); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // release hold: save new timing else if (event == EV_click1_hold_release) { cfg.beacon_seconds = 1 + (arg / TICKS_PER_SECOND); save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/anduril/candle-mode.c b/spaghetti-monster/anduril/candle-mode.c index bfb0377..ab47c34 100644 --- a/spaghetti-monster/anduril/candle-mode.c +++ b/spaghetti-monster/anduril/candle-mode.c @@ -35,14 +35,14 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { // if the timer just expired, shut off if (sunset_active && (! sunset_timer)) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // ifdef USE_SUNSET_TIMER if (event == EV_enter_state) { ramp_direction = 1; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_SUNSET_TIMER // 2 clicks: cancel timer @@ -50,7 +50,7 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { // parent state just rotated through strobe/flasher modes, // so cancel timer... in case any time was left over from earlier sunset_timer = 0; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // ifdef USE_SUNSET_TIMER // hold: change brightness (brighter) @@ -64,19 +64,19 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { candle_mode_brightness += ramp_direction; if (candle_mode_brightness < 1) candle_mode_brightness = 1; else if (candle_mode_brightness > MAX_CANDLE_LEVEL) candle_mode_brightness = MAX_CANDLE_LEVEL; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // reverse ramp direction on hold release else if (event == EV_click1_hold_release) { ramp_direction = -ramp_direction; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold: change brightness (dimmer) else if (event == EV_click2_hold) { ramp_direction = 1; if (candle_mode_brightness > 1) candle_mode_brightness --; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // clock tick: animate candle brightness else if (event == EV_tick) { @@ -129,7 +129,7 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { // random amplitude //candle_wave3_depth = 2 + (pseudo_rand() % ((CANDLE_WAVE3_MAXDEPTH * CANDLE_AMPLITUDE / 100) - 2)); candle_wave3_depth = pseudo_rand() % (CANDLE_WAVE3_MAXDEPTH * CANDLE_AMPLITUDE / 100); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/anduril/channel-modes.c b/spaghetti-monster/anduril/channel-modes.c index 76cbf7e..cecf0bf 100644 --- a/spaghetti-monster/anduril/channel-modes.c +++ b/spaghetti-monster/anduril/channel-modes.c @@ -129,7 +129,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { // channel toggle menu on ... 9H? else if (event == EV_click9_hold) { push_state(channel_mode_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif diff --git a/spaghetti-monster/anduril/config-mode.c b/spaghetti-monster/anduril/config-mode.c index b8b3398..d379cd9 100644 --- a/spaghetti-monster/anduril/config-mode.c +++ b/spaghetti-monster/anduril/config-mode.c @@ -166,7 +166,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { else { pop_state(); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // count clicks: click = +1, hold = +10 @@ -186,7 +186,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { set_channel_mode(CONFIG_BLINK_CHANNEL); #endif set_level(RAMP_SIZE/2); // flash briefly - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // eat all other events; don't pass any through to parent diff --git a/spaghetti-monster/anduril/ff-strobe-modes.c b/spaghetti-monster/anduril/ff-strobe-modes.c index 9e7f2bb..b7a7303 100644 --- a/spaghetti-monster/anduril/ff-strobe-modes.c +++ b/spaghetti-monster/anduril/ff-strobe-modes.c @@ -12,19 +12,19 @@ uint8_t boring_strobe_state(Event event, uint16_t arg) { uint8_t st = boring_strobe_type; if (event == EV_enter_state) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: off else if (event == EV_1click) { // reset to police strobe for next time boring_strobe_type = 0; set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: rotate through strobe/flasher modes else if (event == EV_2clicks) { boring_strobe_type = (st + 1) % NUM_BORING_STROBES; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/anduril/lockout-mode.c b/spaghetti-monster/anduril/lockout-mode.c index ee78a19..422d081 100644 --- a/spaghetti-monster/anduril/lockout-mode.c +++ b/spaghetti-monster/anduril/lockout-mode.c @@ -59,7 +59,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { rgb_led_update(cfg.rgb_led_lockout_mode, arg); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(TICK_DURING_STANDBY) && (defined(USE_INDICATOR_LED) || defined(USE_AUX_RGB_LEDS)) @@ -77,7 +77,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { #elif defined(USE_AUX_RGB_LEDS) rgb_led_update(cfg.rgb_led_lockout_mode, arg); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -85,7 +85,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { else if (event == EV_3clicks) { blink_once(); set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 4 clicks: exit and turn on @@ -98,7 +98,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { else #endif set_state(steady_state, memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 4 clicks, but hold last: exit and start at floor @@ -109,13 +109,13 @@ uint8_t lockout_state(Event event, uint16_t arg) { current_event = 0; // ... and back to ramp mode set_state(steady_state, 1); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 5 clicks: exit and turn on at ceiling level else if (event == EV_5clicks) { set_state(steady_state, MAX_LEVEL); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if NUM_CHANNEL_MODES > 1 @@ -155,7 +155,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { #elif defined(USE_AUX_RGB_LEDS) #endif save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #elif defined(USE_AUX_RGB_LEDS) // 7 clicks: change RGB aux LED pattern @@ -166,7 +166,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { rgb_led_update(cfg.rgb_led_lockout_mode, 0); save_config(); blink_once(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 7H: change RGB aux LED color else if (event == EV_click7_hold) { @@ -178,13 +178,13 @@ uint8_t lockout_state(Event event, uint16_t arg) { //save_config(); } rgb_led_update(cfg.rgb_led_lockout_mode, arg); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 7H, release: save new color else if (event == EV_click7_hold_release) { setting_rgb_mode_now = 0; save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -199,7 +199,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { // 10H: configure the autolock option else if (event == EV_click10_hold) { push_state(autolock_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif diff --git a/spaghetti-monster/anduril/momentary-mode.c b/spaghetti-monster/anduril/momentary-mode.c index 2d8d57b..a765142 100644 --- a/spaghetti-monster/anduril/momentary-mode.c +++ b/spaghetti-monster/anduril/momentary-mode.c @@ -22,14 +22,14 @@ uint8_t momentary_state(Event event, uint16_t arg) { if (momentary_mode == 0) { set_level(memorized_level); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // button was released else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) { momentary_active = 0; set_level(0); //go_to_standby = 1; // sleep while light is off - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // Sleep, dammit! (but wait a few seconds first) @@ -59,7 +59,7 @@ uint8_t momentary_state(Event event, uint16_t arg) { #ifdef USE_STROBE_STATE } #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; diff --git a/spaghetti-monster/anduril/off-mode.c b/spaghetti-monster/anduril/off-mode.c index c1ae2e4..ab67d96 100644 --- a/spaghetti-monster/anduril/off-mode.c +++ b/spaghetti-monster/anduril/off-mode.c @@ -28,7 +28,7 @@ uint8_t off_state(Event event, uint16_t arg) { // sleep while off (lower power use) // (unless delay requested; give the ADC some time to catch up) if (! arg) { go_to_standby = 1; } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // go back to sleep eventually if we got bumped but didn't leave "off" state @@ -42,7 +42,7 @@ uint8_t off_state(Event event, uint16_t arg) { rgb_led_update(cfg.rgb_led_off_mode, arg); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(TICK_DURING_STANDBY) @@ -69,7 +69,7 @@ uint8_t off_state(Event event, uint16_t arg) { set_state(lockout_state, 0); } #endif // ifdef USE_AUTOLOCK - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -77,7 +77,7 @@ uint8_t off_state(Event event, uint16_t arg) { // hold (initially): go to lowest level (floor), but allow abort for regular click else if (event == EV_click1_press) { set_level(nearest_level(1)); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // B_TIMING_ON == B_PRESS_T @@ -95,7 +95,7 @@ uint8_t off_state(Event event, uint16_t arg) { #endif #ifdef USE_RAMP_AFTER_MOON_CONFIG if (cfg.dont_ramp_after_moon) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // don't start ramping immediately; @@ -104,13 +104,13 @@ uint8_t off_state(Event event, uint16_t arg) { if (arg >= (!cfg.ramp_style) * HOLD_TIMEOUT) { // more consistent set_state(steady_state, 1); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold, release quickly: go to lowest level (floor) else if (event == EV_click1_hold_release) { set_state(steady_state, 1); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if (B_TIMING_ON != B_TIMEOUT_T) @@ -124,7 +124,7 @@ uint8_t off_state(Event event, uint16_t arg) { } #endif set_level(nearest_level(memorized_level)); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // if (B_TIMING_ON != B_TIMEOUT_T) @@ -138,7 +138,7 @@ uint8_t off_state(Event event, uint16_t arg) { // (need to duplicate manual mem logic here, probably) set_state(steady_state, memorized_level); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold: momentary at ceiling or turbo @@ -167,30 +167,30 @@ uint8_t off_state(Event event, uint16_t arg) { #endif set_level(turbo_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } else if (event == EV_click2_hold_release) { set_level(0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: highest mode (ceiling) else if (event == EV_2clicks) { set_state(steady_state, MAX_LEVEL); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 3 clicks (initial press): off, to prep for later events else if (event == EV_click3_press) { set_level(0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_BATTCHECK // 3 clicks: battcheck mode / blinky mode group 1 else if (event == EV_3clicks) { set_state(battcheck_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -199,7 +199,7 @@ uint8_t off_state(Event event, uint16_t arg) { else if (event == EV_4clicks) { blink_once(); set_state(lockout_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -207,7 +207,7 @@ uint8_t off_state(Event event, uint16_t arg) { // 13 clicks and hold the last click: invoke factory reset (reboot) else if (event == EV_click13_hold) { reboot(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -215,7 +215,7 @@ uint8_t off_state(Event event, uint16_t arg) { // 15+ clicks: show the version number else if (event == EV_15clicks) { set_state(version_check_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -230,7 +230,7 @@ uint8_t off_state(Event event, uint16_t arg) { else { // configure simple UI ramp push_state(simple_ui_config_state, 0); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } ////////// Every action below here is blocked in the (non-Extended) Simple UI ////////// @@ -246,12 +246,12 @@ uint8_t off_state(Event event, uint16_t arg) { #ifdef USE_STROBE_STATE else if (event == EV_click3_hold) { set_state(strobe_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #elif defined(USE_BORING_STROBE_STATE) else if (event == EV_click3_hold) { set_state(boring_strobe_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -271,7 +271,7 @@ uint8_t off_state(Event event, uint16_t arg) { // redundant, sleep tick does the same thing //indicator_led_update(cfg.indicator_led_mode & 0x03, arg); save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #elif defined(USE_AUX_RGB_LEDS) // 7 clicks: change RGB aux LED pattern @@ -282,7 +282,7 @@ uint8_t off_state(Event event, uint16_t arg) { rgb_led_update(cfg.rgb_led_off_mode, 0); save_config(); blink_once(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 7 clicks (hold last): change RGB aux LED color else if (event == EV_click7_hold) { @@ -294,12 +294,12 @@ uint8_t off_state(Event event, uint16_t arg) { //save_config(); } rgb_led_update(cfg.rgb_led_off_mode, arg); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } else if (event == EV_click7_hold_release) { setting_rgb_mode_now = 0; save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // end 7 clicks @@ -317,7 +317,7 @@ uint8_t off_state(Event event, uint16_t arg) { blink_once(); cfg.simple_ui_active = 1; save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // ifdef USE_SIMPLE_UI @@ -326,7 +326,7 @@ uint8_t off_state(Event event, uint16_t arg) { else if (event == EV_5clicks) { blink_once(); set_state(momentary_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -335,7 +335,7 @@ uint8_t off_state(Event event, uint16_t arg) { else if (event == EV_6clicks) { blink_once(); set_state(tactical_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -343,7 +343,7 @@ uint8_t off_state(Event event, uint16_t arg) { // 9 clicks, but hold last click: configure misc global settings else if ((event == EV_click9_hold) && (!arg)) { push_state(globals_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index 1799e97..4fef2c2 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -79,7 +79,7 @@ uint8_t steady_state(Event event, uint16_t arg) { // if the timer just expired, shut off else if (sunset_active && (! sunset_timer)) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // ifdef USE_SUNSET_TIMER @@ -99,25 +99,25 @@ uint8_t steady_state(Event event, uint16_t arg) { arg = nearest_level(arg); set_level_and_therm_target(arg); ramp_direction = 1; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if (B_TIMING_OFF == B_RELEASE_T) // 1 click (early): off, if configured for early response else if (event == EV_click1_release) { level_before_off = actual_level; set_level_and_therm_target(0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks (early): abort turning off, if configured for early response else if (event == EV_click2_press) { set_level_and_therm_target(level_before_off); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // if (B_TIMING_OFF == B_RELEASE_T) // 1 click: off else if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: go to/from highest level else if (event == EV_2clicks) { @@ -130,7 +130,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_SUNSET_TIMER reset_sunset_timer(); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_LOCKOUT_MODE @@ -138,7 +138,7 @@ uint8_t steady_state(Event event, uint16_t arg) { else if (event == EV_4clicks) { set_level(0); set_state(lockout_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -147,12 +147,12 @@ uint8_t steady_state(Event event, uint16_t arg) { else if ((event == EV_click1_hold) || (event == EV_click2_hold)) { // ramp slower in discrete mode if (cfg.ramp_style && (arg % HOLD_TIMEOUT != 0)) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_RAMP_SPEED_CONFIG // ramp slower if user configured things that way if ((! cfg.ramp_style) && (arg % ramp_speed)) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // fix ramp direction on first frame if necessary @@ -228,7 +228,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_SUNSET_TIMER reset_sunset_timer(); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // reverse ramp direction on hold release else if ((event == EV_click1_hold_release) @@ -237,7 +237,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef START_AT_MEMORIZED_LEVEL save_config_wl(); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } else if (event == EV_tick) { @@ -292,7 +292,7 @@ uint8_t steady_state(Event event, uint16_t arg) { } } #endif // ifdef USE_SET_LEVEL_GRADUALLY - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_THERMAL_REGULATION @@ -322,7 +322,7 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(stepdown); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // underheating: increase slowly if we're lower than the target // (proportional to how low we are) @@ -341,7 +341,7 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(stepup); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_SET_LEVEL_GRADUALLY // temperature is within target window @@ -352,7 +352,7 @@ uint8_t steady_state(Event event, uint16_t arg) { gradual_target = actual_level + 1; else if (gradual_target < actual_level) gradual_target = actual_level - 1; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // ifdef USE_SET_LEVEL_GRADUALLY #endif // ifdef USE_THERMAL_REGULATION @@ -397,7 +397,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_SUNSET_TIMER reset_sunset_timer(); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // If we allowed 3C in Simple UI, now block further actions @@ -428,7 +428,7 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level_and_therm_target(turbo_level); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } else if ((event == EV_click3_hold_release) #ifdef USE_CHANNEL_MODE_ARGS @@ -442,7 +442,7 @@ uint8_t steady_state(Event event, uint16_t arg) { return EVENT_NOT_HANDLED; #endif set_level_and_therm_target(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_MOMENTARY_MODE @@ -450,7 +450,7 @@ uint8_t steady_state(Event event, uint16_t arg) { else if (event == EV_5clicks) { set_level(0); set_state(momentary_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -458,7 +458,7 @@ uint8_t steady_state(Event event, uint16_t arg) { // 7H: configure this ramp mode else if (event == EV_click7_hold) { push_state(ramp_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif @@ -468,7 +468,7 @@ uint8_t steady_state(Event event, uint16_t arg) { manual_memory_save(); save_config(); blink_once(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } else if (event == EV_click10_hold) { #ifdef USE_RAMP_EXTRAS_CONFIG @@ -482,7 +482,7 @@ uint8_t steady_state(Event event, uint16_t arg) { blink_once(); } #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // ifdef USE_MANUAL_MEMORY diff --git a/spaghetti-monster/anduril/sos-mode.c b/spaghetti-monster/anduril/sos-mode.c index 4704297..2a4e97c 100644 --- a/spaghetti-monster/anduril/sos-mode.c +++ b/spaghetti-monster/anduril/sos-mode.c @@ -11,7 +11,7 @@ uint8_t sos_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: next blinky mode else if (event == EV_2clicks) { @@ -22,7 +22,7 @@ uint8_t sos_state(Event event, uint16_t arg) { #elif defined(USE_BEACON_MODE) set_state(beacon_state, 0); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/anduril/strobe-modes.c b/spaghetti-monster/anduril/strobe-modes.c index 9963c80..0a4ff98 100644 --- a/spaghetti-monster/anduril/strobe-modes.c +++ b/spaghetti-monster/anduril/strobe-modes.c @@ -29,24 +29,24 @@ uint8_t strobe_state(Event event, uint16_t arg) { // init anything which needs to be initialized else if (event == EV_enter_state) { ramp_direction = 1; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: off else if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: rotate through strobe/flasher modes else if (event == EV_2clicks) { cfg.strobe_type = (st + 1) % NUM_STROBES; save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 4 clicks: rotate backward through strobe/flasher modes else if (event == EV_4clicks) { cfg.strobe_type = (st - 1 + NUM_STROBES) % NUM_STROBES; save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: change speed (go faster) // or change brightness (brighter) @@ -83,14 +83,14 @@ uint8_t strobe_state(Event event, uint16_t arg) { } #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // reverse ramp direction on hold release // ... and save new strobe settings else if (event == EV_click1_hold_release) { ramp_direction = -ramp_direction; save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold: change speed (go slower) // or change brightness (dimmer) @@ -124,19 +124,19 @@ uint8_t strobe_state(Event event, uint16_t arg) { } #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // release hold: save new strobe settings else if (event == EV_click2_hold_release) { save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_MOMENTARY_MODE // 5 clicks: go to momentary mode (momentary strobe) else if (event == EV_5clicks) { set_state(momentary_state, 0); set_level(0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif #if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) @@ -146,7 +146,7 @@ uint8_t strobe_state(Event event, uint16_t arg) { if (arg == AUTO_REVERSE_TIME) ramp_direction = 1; pseudo_rand_seed += arg; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif return EVENT_NOT_HANDLED; diff --git a/spaghetti-monster/anduril/sunset-timer.c b/spaghetti-monster/anduril/sunset-timer.c index bb59ec9..e4fc512 100644 --- a/spaghetti-monster/anduril/sunset-timer.c +++ b/spaghetti-monster/anduril/sunset-timer.c @@ -17,7 +17,7 @@ uint8_t sunset_timer_state(Event event, uint16_t arg) { if (event == EV_enter_state) { sunset_timer = 0; sunset_ticks = 0; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: maybe "bump" the timer if it's active and almost expired else if (event == EV_hold) { @@ -40,7 +40,7 @@ uint8_t sunset_timer_state(Event event, uint16_t arg) { blink_once(); } } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // tick: count down until time expires else if (event == EV_tick) { @@ -53,7 +53,7 @@ uint8_t sunset_timer_state(Event event, uint16_t arg) { sunset_timer --; } } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/anduril/tactical-mode.c b/spaghetti-monster/anduril/tactical-mode.c index 2f5c3b0..8f2e73d 100644 --- a/spaghetti-monster/anduril/tactical-mode.c +++ b/spaghetti-monster/anduril/tactical-mode.c @@ -83,7 +83,7 @@ uint8_t tactical_state(Event event, uint16_t arg) { // 7H: configure tactical mode else if (event == EV_click7_hold) { push_state(tactical_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return ret; diff --git a/spaghetti-monster/anduril/tempcheck-mode.c b/spaghetti-monster/anduril/tempcheck-mode.c index 4a413c9..5d160bd 100644 --- a/spaghetti-monster/anduril/tempcheck-mode.c +++ b/spaghetti-monster/anduril/tempcheck-mode.c @@ -10,7 +10,7 @@ uint8_t tempcheck_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: next blinky mode else if (event == EV_2clicks) { @@ -21,12 +21,12 @@ uint8_t tempcheck_state(Event event, uint16_t arg) { #elif defined(USE_BATTCHECK) set_state(battcheck_state, 0); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 7H: thermal config mode else if (event == EV_click7_hold) { push_state(thermal_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/baton/baton.c b/spaghetti-monster/baton/baton.c index 8a80134..e672755 100644 --- a/spaghetti-monster/baton/baton.c +++ b/spaghetti-monster/baton/baton.c @@ -152,12 +152,12 @@ uint8_t lockout_state(Event event, uint16_t arg) { PWM1_LVL = 0; PWM2_LVL = 0; // make sure emitters are off // sleep 1 second after user stops pressing buttons if (arg > TICKS_PER_SECOND) { go_to_standby = 1; } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 4 clicks: exit, and turn on at "low" level else if (event == EV_4clicks) { set_state(steady_state, 1); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/darkhorse/darkhorse.c b/spaghetti-monster/darkhorse/darkhorse.c index 4058c2f..aa37b92 100644 --- a/spaghetti-monster/darkhorse/darkhorse.c +++ b/spaghetti-monster/darkhorse/darkhorse.c @@ -166,12 +166,12 @@ uint8_t any_mode_state(Event event, uint16_t arg, uint8_t *primary, uint8_t *sec // turn on LED when entering the mode if (event == EV_enter_state) { set_any_mode(*primary, *secondary, modes); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: off else if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: change brightness (low, med, hi, always starting at low) else if (event == EV_click1_hold) { @@ -187,14 +187,14 @@ uint8_t any_mode_state(Event event, uint16_t arg, uint8_t *primary, uint8_t *sec set_state(hi_mode_state, 0); break; } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: toggle primary/secondary level else if (event == EV_2clicks) { *primary ^= 1; set_any_mode(*primary, *secondary, modes); save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click-release-hold: change secondary level else if (event == EV_click2_hold) { @@ -204,7 +204,7 @@ uint8_t any_mode_state(Event event, uint16_t arg, uint8_t *primary, uint8_t *sec *primary = 0; set_any_mode(*primary, *secondary, modes); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold, release: save secondary level else if (event == EV_click2_hold_release) { @@ -259,20 +259,20 @@ uint8_t strobe_beacon_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click (initially): cancel current blink // FIXME: this is no longer necessary; FSM does this automatically now if (event == EV_click1_release) { interrupt_nice_delays(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: rotate through blinky modes else if (event == EV_2clicks) { strobe_beacon_mode = (strobe_beacon_mode + 1) & 3; save_config(); interrupt_nice_delays(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/fireflies-ui/fireflies-ui.c b/spaghetti-monster/fireflies-ui/fireflies-ui.c index 93a3180..34f8293 100644 --- a/spaghetti-monster/fireflies-ui/fireflies-ui.c +++ b/spaghetti-monster/fireflies-ui/fireflies-ui.c @@ -460,7 +460,7 @@ uint8_t off_state(Event event, uint16_t arg) { #endif // sleep while off (lower power use) go_to_standby = 1; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // go back to sleep eventually if we got bumped but didn't leave "off" state else if (event == EV_tick) { @@ -470,7 +470,7 @@ uint8_t off_state(Event event, uint16_t arg) { indicator_led(indicator_led_mode & 0x03); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) // blink the indicator LED, maybe @@ -478,13 +478,13 @@ uint8_t off_state(Event event, uint16_t arg) { if ((indicator_led_mode & 0b00000011) == 0b00000011) { indicator_blink(arg); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // hold (initially): go to lowest level (floor), but allow abort for regular click else if (event == EV_click1_press) { set_level(nearest_level(1)); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: go to lowest level else if (event == EV_click1_hold) { @@ -500,75 +500,75 @@ uint8_t off_state(Event event, uint16_t arg) { if (arg >= (!ramp_style) * HOLD_TIMEOUT) { // more consistent set_state(steady_state, 1); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold, release quickly: go to lowest level (floor) else if (event == EV_click1_hold_release) { set_state(steady_state, 1); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click (before timeout): go to memorized level, but allow abort for double click else if (event == EV_click1_release) { set_level(nearest_level(memorized_level)); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: regular mode else if (event == EV_1click) { set_state(steady_state, memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold: go to highest level (ceiling) (for ramping down) else if (event == EV_click2_hold) { set_state(steady_state, MAX_LEVEL); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: highest mode (ceiling) else if (event == EV_2clicks) { set_state(steady_state, MAX_LEVEL); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 3 clicks (initial press): off, to prep for later events else if (event == EV_click3_press) { set_level(0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_BATTCHECK // 3 clicks: battcheck mode / blinky mode group 1 else if (event == EV_3clicks) { set_state(battcheck_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // click, click, long-click: strobe mode #ifdef USE_STROBE_STATE else if (event == EV_click3_hold) { set_state(strobe_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #elif defined(USE_BORING_STROBE_STATE) else if (event == EV_click3_hold) { set_state(boring_strobe_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // 4 clicks: soft lockout else if (event == EV_4clicks) { blink_confirm(2); set_state(lockout_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 5 clicks: momentary mode else if (event == EV_5clicks) { blink_confirm(1); set_state(momentary_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_MUGGLE_MODE // 6 clicks: muggle mode else if (event == EV_6clicks) { blink_confirm(1); set_state(muggle_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif #ifdef USE_INDICATOR_LED @@ -586,19 +586,19 @@ uint8_t off_state(Event event, uint16_t arg) { indicator_led_mode = (indicator_led_mode & 0b11111100) | mode; indicator_led(mode); save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // 8 clicks: temperature check else if (event == EV_8clicks) { set_state(tempcheck_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_TENCLICK_THERMAL_CONFIG // 10 clicks: thermal config mode else if (event == EV_10clicks) { push_state(thermal_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif return EVENT_NOT_HANDLED; @@ -637,12 +637,12 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_REVERSING ramp_direction = 1; #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: off else if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: go to/from highest level else if (event == EV_2clicks) { @@ -659,7 +659,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #endif set_level(memorized_level); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 3 clicks: toggle smooth vs discrete ramping else if (event == EV_3clicks) { @@ -677,20 +677,20 @@ uint8_t steady_state(Event event, uint16_t arg) { #endif blip(); set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_RAMP_CONFIG // 4 clicks: configure this ramp mode else if (event == EV_4clicks) { push_state(ramp_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // hold: change brightness (brighter) else if (event == EV_click1_hold) { // ramp slower in discrete mode if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_REVERSING // fix ramp direction on first frame if necessary @@ -744,7 +744,7 @@ uint8_t steady_state(Event event, uint16_t arg) { } #endif set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(USE_REVERSING) || defined(START_AT_MEMORIZED_LEVEL) // reverse ramp direction on hold release @@ -755,7 +755,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef START_AT_MEMORIZED_LEVEL save_config_wl(); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // click, hold: change brightness (dimmer) @@ -765,7 +765,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #endif // ramp slower in discrete mode if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // TODO? make it ramp up instead, if already at min? memorized_level = nearest_level((int16_t)actual_level - ramp_step_size); @@ -804,13 +804,13 @@ uint8_t steady_state(Event event, uint16_t arg) { } #endif set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef START_AT_MEMORIZED_LEVEL // click, release, hold, release: save new ramp level (if necessary) else if (event == EV_click2_hold_release) { save_config_wl(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif #if defined(USE_SET_LEVEL_GRADUALLY) || defined(USE_REVERSING) @@ -822,7 +822,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_SET_LEVEL_GRADUALLY // make thermal adjustment speed scale with magnitude if ((arg & 1) && (actual_level < THERM_FASTER_LEVEL)) { - return MISCHIEF_MANAGED; // adjust slower when not a high mode + return EVENT_HANDLED; // adjust slower when not a high mode } #ifdef THERM_HARD_TURBO_DROP else if ((! (actual_level < THERM_FASTER_LEVEL)) @@ -864,7 +864,7 @@ uint8_t steady_state(Event event, uint16_t arg) { } #endif #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif #ifdef USE_THERMAL_REGULATION @@ -893,7 +893,7 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(stepdown); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // underheating: increase slowly if we're lower than the target // (proportional to how low we are) @@ -912,7 +912,7 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(stepup); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif return EVENT_NOT_HANDLED; @@ -1004,18 +1004,18 @@ uint8_t strobe_state(Event event, uint16_t arg) { // init anything which needs to be initialized else if (event == EV_enter_state) { ramp_direction = 1; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: off else if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: rotate through strobe/flasher modes else if (event == EV_2clicks) { strobe_type = (st + 1) % NUM_STROBES; save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: change speed (go faster) // or change brightness (brighter) @@ -1052,14 +1052,14 @@ uint8_t strobe_state(Event event, uint16_t arg) { } #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // reverse ramp direction on hold release // ... and save new strobe settings else if (event == EV_click1_hold_release) { ramp_direction = -ramp_direction; save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold: change speed (go slower) // or change brightness (dimmer) @@ -1093,12 +1093,12 @@ uint8_t strobe_state(Event event, uint16_t arg) { } #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // release hold: save new strobe settings else if (event == EV_click2_hold_release) { save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(USE_LIGHTNING_MODE) || defined(USE_CANDLE_MODE) // clock tick: bump the random seed @@ -1107,7 +1107,7 @@ uint8_t strobe_state(Event event, uint16_t arg) { if (arg == TICKS_PER_SECOND) ramp_direction = 1; pseudo_rand_seed += arg; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif return EVENT_NOT_HANDLED; @@ -1223,14 +1223,14 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { if (event == EV_enter_state) { candle_mode_timer = 0; // in case any time was left over from earlier ramp_direction = 1; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: cancel timer else if (event == EV_2clicks) { // parent state just rotated through strobe/flasher modes, // so cancel timer... in case any time was left over from earlier candle_mode_timer = 0; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: change brightness (brighter) else if (event == EV_click1_hold) { @@ -1243,19 +1243,19 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { candle_mode_brightness += ramp_direction; if (candle_mode_brightness < 1) candle_mode_brightness = 1; else if (candle_mode_brightness > MAX_CANDLE_LEVEL) candle_mode_brightness = MAX_CANDLE_LEVEL; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // reverse ramp direction on hold release else if (event == EV_click1_hold_release) { ramp_direction = -ramp_direction; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold: change brightness (dimmer) else if (event == EV_click2_hold) { ramp_direction = 1; if (candle_mode_brightness > 1) candle_mode_brightness --; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 3 clicks: add 30m to candle timer else if (event == EV_3clicks) { @@ -1266,7 +1266,7 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { set_level(actual_level + 32); delay_4ms(2); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // clock tick: animate candle brightness else if (event == EV_tick) { @@ -1328,7 +1328,7 @@ uint8_t candle_mode_state(Event event, uint16_t arg) { // random amplitude //candle_wave3_depth = 2 + (pseudo_rand() % ((CANDLE_WAVE3_MAXDEPTH * CANDLE_AMPLITUDE / 100) - 2)); candle_wave3_depth = pseudo_rand() % (CANDLE_WAVE3_MAXDEPTH * CANDLE_AMPLITUDE / 100); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -1345,19 +1345,19 @@ uint8_t boring_strobe_state(Event event, uint16_t arg) { momentary_mode = 1; // 0 = ramping, 1 = strobes if (event == EV_enter_state) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: off else if (event == EV_1click) { // reset to police strobe for next time boring_strobe_type = 0; set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: rotate through strobe/flasher modes else if (event == EV_2clicks) { boring_strobe_type = (st + 1) % NUM_BORING_STROBES; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -1411,7 +1411,7 @@ uint8_t battcheck_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(USE_GOODNIGHT_MODE) || defined(USE_BEACON_MODE) // 2 clicks: next mode @@ -1421,7 +1421,7 @@ uint8_t battcheck_state(Event event, uint16_t arg) { #elif defined(USE_BEACON_MODE) set_state(beacon_state, 0); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif return EVENT_NOT_HANDLED; @@ -1434,19 +1434,19 @@ uint8_t tempcheck_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if 0 // not part of a loop in this UI // 2 clicks: battcheck mode else if (event == EV_2clicks) { set_state(battcheck_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // 4 clicks: thermal config mode else if (event == EV_4clicks) { push_state(thermal_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -1458,7 +1458,7 @@ uint8_t beacon_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // TODO: use sleep ticks to measure time between pulses, // to save power @@ -1469,12 +1469,12 @@ uint8_t beacon_state(Event event, uint16_t arg) { #else set_state(battcheck_state, 0); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 4 clicks: beacon config mode else if (event == EV_4clicks) { push_state(beacon_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -1490,12 +1490,12 @@ uint8_t goodnight_state(Event event, uint16_t arg) { ticks_since_stepdown = 0; blink_confirm(2); set_level(GOODNIGHT_LEVEL); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: off else if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: beacon mode else if (event == EV_2clicks) { @@ -1504,7 +1504,7 @@ uint8_t goodnight_state(Event event, uint16_t arg) { #elif defined(USE_TEMPCHECK_MODE) set_state(tempcheck_state, 0); #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // tick: step down (maybe) or off (maybe) else if (event == EV_tick) { @@ -1520,7 +1520,7 @@ uint8_t goodnight_state(Event event, uint16_t arg) { set_state(off_state, 0); } } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -1572,14 +1572,14 @@ uint8_t lockout_state(Event event, uint16_t arg) { indicator_led(indicator_led_mode >> 2); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) else if (event == EV_sleep_tick) { if ((indicator_led_mode & 0b00001100) == 0b00001100) { indicator_blink(arg); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif #ifdef USE_INDICATOR_LED @@ -1597,7 +1597,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { indicator_led_mode = (mode << 2) + (indicator_led_mode & 0x03); indicator_led(mode); save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if 0 // old method, deprecated in favor of "7 clicks from off" // click, click, hold: rotate through indicator LED modes (off mode) @@ -1624,12 +1624,12 @@ uint8_t lockout_state(Event event, uint16_t arg) { indicator_led(mode); #endif //save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, click, hold, release: save indicator LED mode (off mode) else if (event == EV_click3_hold_release) { save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif #endif @@ -1637,7 +1637,7 @@ uint8_t lockout_state(Event event, uint16_t arg) { else if (event == EV_4clicks) { blink_confirm(1); set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; @@ -1660,14 +1660,14 @@ uint8_t momentary_state(Event event, uint16_t arg) { if (momentary_mode == 0) { set_level(memorized_level); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // button was released else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) { momentary_active = 0; set_level(0); //go_to_standby = 1; // sleep while light is off - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // Sleep, dammit! (but wait a few seconds first) @@ -1688,7 +1688,7 @@ uint8_t momentary_state(Event event, uint16_t arg) { // TODO: lighted button should use lockout config? } } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; @@ -1721,7 +1721,7 @@ uint8_t muggle_state(Event event, uint16_t arg) { //memorized_level = MAX_1x7135; memorized_level = (MUGGLE_FLOOR + MUGGLE_CEILING) / 2; #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // initial press: moon hint else if (event == EV_click1_press) { @@ -1749,12 +1749,12 @@ uint8_t muggle_state(Event event, uint16_t arg) { set_level(memorized_level); } */ - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: change brightness else if (event == EV_click1_hold) { // ramp at half speed - if (arg & 1) return MISCHIEF_MANAGED; + if (arg & 1) return EVENT_HANDLED; // if off, start at bottom if (muggle_off_mode) { @@ -1776,7 +1776,7 @@ uint8_t muggle_state(Event event, uint16_t arg) { memorized_level = m; set_level(m); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // reverse ramp direction on hold release else if (event == EV_click1_hold_release) { @@ -1784,7 +1784,7 @@ uint8_t muggle_state(Event event, uint16_t arg) { #ifdef START_AT_MEMORIZED_LEVEL save_config_wl(); // momentary use should retain brightness level #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } /* // click, hold: change brightness (dimmer) @@ -1793,7 +1793,7 @@ uint8_t muggle_state(Event event, uint16_t arg) { if (memorized_level > MUGGLE_FLOOR) memorized_level = actual_level - 1; set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } */ // 6 clicks: exit muggle mode @@ -1802,7 +1802,7 @@ uint8_t muggle_state(Event event, uint16_t arg) { muggle_mode_active = 0; save_config(); set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // tick: housekeeping else if (event == EV_tick) { @@ -1815,7 +1815,7 @@ uint8_t muggle_state(Event event, uint16_t arg) { go_to_standby = 1; // sleep while light is off } } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_THERMAL_REGULATION // overheating is handled specially in muggle mode @@ -1827,7 +1827,7 @@ uint8_t muggle_state(Event event, uint16_t arg) { uint8_t new = actual_level - arg; if (new < MUGGLE_FLOOR) { new = MUGGLE_FLOOR; } set_level(new); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // low voltage is handled specially in muggle mode @@ -1838,7 +1838,7 @@ uint8_t muggle_state(Event event, uint16_t arg) { } else { muggle_off_mode = 1; } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; @@ -1854,7 +1854,7 @@ uint8_t config_state_base(Event event, uint16_t arg, if (event == EV_enter_state) { config_step = 0; set_level(0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // advance forward through config steps else if (event == EV_tick) { @@ -1868,13 +1868,13 @@ uint8_t config_state_base(Event event, uint16_t arg, //set_state(retstate, retval); pop_state(); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // an option was set (return from number_entry_state) else if (event == EV_reenter_state) { config_state_values[config_step] = number_entry_value; config_step ++; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } //return EVENT_NOT_HANDLED; // eat all other events; don't pass any through to parent @@ -1978,7 +1978,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { blinks_left = arg; entry_step = 0; wait_ticks = 0; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // advance through the process: // 0: wait a moment @@ -2035,7 +2035,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { number_entry_value = value; pop_state(); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // count clicks else if (event == EV_click1_release) { @@ -2048,7 +2048,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { delay_4ms(8/2); set_level(0); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/meteor/meteor.c b/spaghetti-monster/meteor/meteor.c index 7d854a1..9c1c000 100644 --- a/spaghetti-monster/meteor/meteor.c +++ b/spaghetti-monster/meteor/meteor.c @@ -262,7 +262,7 @@ uint8_t base_on_state(Event event, uint16_t arg, uint8_t *mode, uint8_t *group) // 1 click: off if (event == EV_1click) { set_state(base_off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_THERMAL_REGULATION // overheating: drop by an amount proportional to how far we are above the ceiling @@ -312,17 +312,17 @@ uint8_t ui1_on_state(Event event, uint16_t arg) { else if (event == EV_2clicks) { *mode ^= 1; set_any_mode(*mode, group); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: turbo else if (event == EV_hold) { if (arg == 0) set_level(MAX_LEVEL); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // release: exit turbo else if (event == EV_click1_hold_release) { set_any_mode(*mode, group); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return base_on_state(event, arg, mode, group); } @@ -361,7 +361,7 @@ uint8_t ui2_on_state(Event event, uint16_t arg) { else if (event == EV_2clicks) { *mode ^= 1; set_any_mode(*mode, group); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: rotate through low/mid/high/turbo else if (event == EV_hold) { @@ -371,7 +371,7 @@ uint8_t ui2_on_state(Event event, uint16_t arg) { else if (arg % HOLD_TIMEOUT == 1) { set_any_mode(*mode, group); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return base_on_state(event, arg, mode, group); } @@ -413,7 +413,7 @@ uint8_t ui3_on_state(Event event, uint16_t arg) { /* else if (event == EV_click1_hold) { set_level(levels[*mode]); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } */ // hold: turbo @@ -427,7 +427,7 @@ uint8_t blinky_base_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(base_off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/ramping-ui/ramping-ui.c b/spaghetti-monster/ramping-ui/ramping-ui.c index 5eb7d8f..583498a 100644 --- a/spaghetti-monster/ramping-ui/ramping-ui.c +++ b/spaghetti-monster/ramping-ui/ramping-ui.c @@ -59,43 +59,43 @@ uint8_t off_state(Event event, uint16_t arg) { set_level(0); // sleep while off (lower power use) go_to_standby = 1; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold (initially): go to lowest level, but allow abort for regular click else if (event == EV_click1_press) { set_level(1); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click (before timeout): go to memorized level, but allow abort for double click else if (event == EV_click1_release) { set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: regular mode else if (event == EV_1click) { set_state(steady_state, memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks (initial press): off, to prep for later events else if (event == EV_click2_press) { set_level(0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: highest mode else if (event == EV_2clicks) { set_state(steady_state, MAX_LEVEL); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 3 clicks: strobe mode else if (event == EV_3clicks) { set_state(strobe_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_BATTCHECK // 4 clicks: battcheck mode else if (event == EV_4clicks) { set_state(battcheck_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // hold: go to lowest level @@ -104,17 +104,17 @@ uint8_t off_state(Event event, uint16_t arg) { // give the user time to release at moon level if (arg >= HOLD_TIMEOUT) set_state(steady_state, 1); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold, release quickly: go to lowest level else if (event == EV_click1_hold_release) { set_state(steady_state, 1); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold: go to highest level (for ramping down) else if (event == EV_click2_hold) { set_state(steady_state, MAX_LEVEL); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -131,12 +131,12 @@ uint8_t steady_state(Event event, uint16_t arg) { target_level = arg; #endif set_level(arg); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: off else if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: go to/from highest level else if (event == EV_2clicks) { @@ -153,12 +153,12 @@ uint8_t steady_state(Event event, uint16_t arg) { #endif set_level(memorized_level); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 3 clicks: go to strobe modes else if (event == EV_3clicks) { set_state(strobe_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 4 clicks: toggle smooth vs discrete ramping else if (event == EV_4clicks) { @@ -167,13 +167,13 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(0); delay_4ms(20/4); set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: change brightness (brighter) else if (event == EV_click1_hold) { // ramp slower in discrete mode if (arg % ramp_step_size != 0) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // FIXME: make it ramp down instead, if already at max if (actual_level + ramp_step_size < MAX_LEVEL) @@ -190,13 +190,13 @@ uint8_t steady_state(Event event, uint16_t arg) { delay_4ms(8/4); } set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold: change brightness (dimmer) else if (event == EV_click2_hold) { // ramp slower in discrete mode if (arg % ramp_step_size != 0) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // FIXME: make it ramp up instead, if already at min if (actual_level > ramp_step_size) @@ -214,7 +214,7 @@ uint8_t steady_state(Event event, uint16_t arg) { delay_4ms(8/4); } set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_THERMAL_REGULATION // TODO: test this on a real light @@ -225,7 +225,7 @@ uint8_t steady_state(Event event, uint16_t arg) { if (stepdown < MAX_LEVEL/4) stepdown = MAX_LEVEL/4; set_level(stepdown); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // underheating: increase slowly if we're lower than the target // (proportional to how low we are) @@ -235,7 +235,7 @@ uint8_t steady_state(Event event, uint16_t arg) { if (stepup > target_level) stepup = target_level; set_level(stepup); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif return EVENT_NOT_HANDLED; @@ -244,36 +244,36 @@ uint8_t steady_state(Event event, uint16_t arg) { uint8_t strobe_state(Event event, uint16_t arg) { if (event == EV_enter_state) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: off else if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: toggle party strobe vs tactical strobe else if (event == EV_2clicks) { strobe_type ^= 1; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 3 clicks: go back to regular modes else if (event == EV_3clicks) { set_state(steady_state, memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: change speed (go faster) else if (event == EV_click1_hold) { if ((arg & 1) == 0) { if (strobe_delay > 8) strobe_delay --; } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold: change speed (go slower) else if (event == EV_click2_hold) { if ((arg & 1) == 0) { if (strobe_delay < 255) strobe_delay ++; } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -284,12 +284,12 @@ uint8_t battcheck_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: tempcheck mode else if (event == EV_2clicks) { set_state(tempcheck_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -298,7 +298,7 @@ uint8_t tempcheck_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/rampingios/rampingiosv3.c b/spaghetti-monster/rampingios/rampingiosv3.c index 7b6baee..e990a5a 100644 --- a/spaghetti-monster/rampingios/rampingiosv3.c +++ b/spaghetti-monster/rampingios/rampingiosv3.c @@ -247,7 +247,7 @@ uint8_t off_state(Event event, uint16_t arg) { #endif // sleep while off (lower power use) go_to_standby = 1; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // go back to sleep eventually if we got bumped but didn't leave "off" state else if (event == EV_tick) { @@ -257,7 +257,7 @@ uint8_t off_state(Event event, uint16_t arg) { indicator_led(indicator_led_mode & 0x03); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) // blink the indicator LED, maybe @@ -265,13 +265,13 @@ uint8_t off_state(Event event, uint16_t arg) { if ((indicator_led_mode & 0b00000011) == 0b00000011) { indicator_blink(arg); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // hold (initially): go to lowest level (floor), but allow abort for regular click else if (event == EV_click1_press) { set_level(nearest_level(1)); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: go to lowest level else if (event == EV_click1_hold) { @@ -290,56 +290,56 @@ uint8_t off_state(Event event, uint16_t arg) { if (arg >= (!ramp_style) * HOLD_TIMEOUT) { // more consistent set_state(steady_state, 1); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold, release quickly: go to lowest level (floor) else if (event == EV_click1_hold_release) { set_state(steady_state, 1); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click (before timeout): go to memorized level, but allow abort for double click else if (event == EV_click1_release) { set_level(nearest_level(memorized_level)); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: regular mode else if (event == EV_1click) { set_state(steady_state, memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold: go to highest level (ceiling) (for ramping down) else if (event == EV_click2_hold) { set_state(steady_state, MAX_LEVEL); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: highest mode (ceiling) else if (event == EV_2clicks) { set_state(steady_state, MAX_LEVEL); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 3 clicks (initial press): off, to prep for later events else if (event == EV_click3_press) { set_level(0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_BATTCHECK // 3 clicks: battcheck mode / blinky mode group 1 else if (event == EV_3clicks) { set_state(battcheck_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // 4 clicks: momentary else if (event == EV_4clicks) { blink_confirm(1); set_state(momentary_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 6 clicks: lockout mode else if (event == EV_6clicks) { blink_confirm(2); set_state(lockout_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_INDICATOR_LED // 7 clicks: next aux LED mode @@ -357,19 +357,19 @@ uint8_t off_state(Event event, uint16_t arg) { indicator_led_mode = (indicator_led_mode & 0b11111100) | mode; indicator_led(mode); save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // 8 clicks: beacon mode else if (event == EV_8clicks) { set_state(beacon_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_TENCLICK_THERMAL_CONFIG // 10 clicks: thermal config mode else if (event == EV_10clicks) { push_state(thermal_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif return EVENT_NOT_HANDLED; @@ -407,12 +407,12 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_REVERSING ramp_direction = 1; #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: off else if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: go to/from highest level else if (event == EV_2clicks) { @@ -429,7 +429,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #endif set_level(memorized_level); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 3 clicks: toggle smooth vs discrete ramping else if (event == EV_3clicks) { @@ -445,20 +445,20 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(0); delay_4ms(20/4); set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_RAMP_CONFIG // 4 clicks: configure this ramp mode else if (event == EV_4clicks) { push_state(ramp_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // hold: change brightness (brighter) else if (event == EV_click1_hold) { // ramp slower in discrete mode if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_REVERSING // make it ramp down instead, if already at max @@ -510,7 +510,7 @@ uint8_t steady_state(Event event, uint16_t arg) { } #endif set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(USE_REVERSING) // reverse ramp direction on hold release @@ -518,7 +518,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_REVERSING ramp_direction = -ramp_direction; #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // click, hold: change brightness (dimmer) @@ -528,7 +528,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #endif // ramp slower in discrete mode if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // TODO? make it ramp up instead, if already at min? memorized_level = nearest_level((int16_t)actual_level - ramp_step_size); @@ -569,7 +569,7 @@ uint8_t steady_state(Event event, uint16_t arg) { } #endif set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(USE_SET_LEVEL_GRADUALLY) || defined(USE_REVERSING) else if (event == EV_tick) { @@ -580,7 +580,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_SET_LEVEL_GRADUALLY // make thermal adjustment speed scale with magnitude if ((arg & 1) && (actual_level < THERM_FASTER_LEVEL)) { - return MISCHIEF_MANAGED; // adjust slower when not a high mode + return EVENT_HANDLED; // adjust slower when not a high mode } #ifdef THERM_HARD_TURBO_DROP else if ((! (actual_level < THERM_FASTER_LEVEL)) @@ -622,7 +622,7 @@ uint8_t steady_state(Event event, uint16_t arg) { } #endif #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif #ifdef USE_THERMAL_REGULATION @@ -654,7 +654,7 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(stepdown); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // underheating: increase slowly if we're lower than the target // (proportional to how low we are) @@ -676,7 +676,7 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(stepup); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif return EVENT_NOT_HANDLED; @@ -688,12 +688,12 @@ uint8_t battcheck_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: tempcheck mode else if (event == EV_2clicks) { set_state(tempcheck_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -705,12 +705,12 @@ uint8_t tempcheck_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 4 clicks: thermal config mode else if (event == EV_4clicks) { push_state(thermal_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -722,14 +722,14 @@ uint8_t beacon_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // TODO: use sleep ticks to measure time between pulses, // to save power // 4 clicks: beacon config mode else if (event == EV_4clicks) { push_state(beacon_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -781,14 +781,14 @@ uint8_t lockout_state(Event event, uint16_t arg) { indicator_led(indicator_led_mode >> 2); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) else if (event == EV_sleep_tick) { if ((indicator_led_mode & 0b00001100) == 0b00001100) { indicator_blink(arg); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif #ifdef USE_INDICATOR_LED @@ -806,14 +806,14 @@ uint8_t lockout_state(Event event, uint16_t arg) { indicator_led_mode = (mode << 2) + (indicator_led_mode & 0x03); indicator_led(mode); save_config(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // 6 clicks: exit else if (event == EV_6clicks) { blink_confirm(1); set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; @@ -827,13 +827,13 @@ uint8_t momentary_state(Event event, uint16_t arg) { // button is being held if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) { set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // button was released else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) { set_level(0); //go_to_standby = 1; // sleep while light is off - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // Sleep, dammit! (but wait a few seconds first) @@ -846,7 +846,7 @@ uint8_t momentary_state(Event event, uint16_t arg) { go_to_standby = 1; // sleep while light is off // TODO: lighted button should use lockout config? } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; @@ -861,7 +861,7 @@ uint8_t config_state_base(Event event, uint16_t arg, if (event == EV_enter_state) { config_step = 0; set_level(0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // advance forward through config steps else if (event == EV_tick) { @@ -875,13 +875,13 @@ uint8_t config_state_base(Event event, uint16_t arg, //set_state(retstate, retval); pop_state(); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // an option was set (return from number_entry_state) else if (event == EV_reenter_state) { config_state_values[config_step] = number_entry_value; config_step ++; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } //return EVENT_NOT_HANDLED; // eat all other events; don't pass any through to parent @@ -985,7 +985,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { blinks_left = arg; entry_step = 0; wait_ticks = 0; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // advance through the process: // 0: wait a moment @@ -1042,7 +1042,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { number_entry_value = value; pop_state(); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // count clicks else if (event == EV_click1_release) { @@ -1055,7 +1055,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { delay_4ms(8/2); set_level(0); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } diff --git a/spaghetti-monster/werner/werner.c b/spaghetti-monster/werner/werner.c index 1c3d4ad..f3241ee 100644 --- a/spaghetti-monster/werner/werner.c +++ b/spaghetti-monster/werner/werner.c @@ -152,19 +152,19 @@ uint8_t off_state(Event event, uint16_t arg) { set_level(0); // sleep while off (lower power use) go_to_standby = 1; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // go back to sleep eventually if we got bumped but didn't leave "off" state else if (event == EV_tick) { if (arg > TICKS_PER_SECOND*2) { go_to_standby = 1; } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold (initially): go to lowest level, but allow abort for regular click else if (event == EV_click1_press) { set_level(nearest_level(1)); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: go to lowest level else if (event == EV_click1_hold) { @@ -173,49 +173,49 @@ uint8_t off_state(Event event, uint16_t arg) { if (arg >= HOLD_TIMEOUT) { set_state(steady_state, 1); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold, release quickly: go to lowest level else if (event == EV_click1_hold_release) { set_state(steady_state, 1); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click (before timeout): go to memorized level, but allow abort for double click else if (event == EV_click1_release) { set_level(nearest_level(memorized_level)); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 1 click: regular mode else if (event == EV_1click) { set_state(steady_state, memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks (initial press): off, to prep for later events else if (event == EV_click2_press) { set_level(0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click, hold: go to highest level (for ramping down) else if (event == EV_click2_hold) { set_state(steady_state, MAX_LEVEL); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: highest mode else if (event == EV_2clicks) { set_state(steady_state, nearest_level(MAX_LEVEL)); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_BATTCHECK // 3 clicks: battcheck mode / blinky mode group else if (event == EV_3clicks) { set_state(battcheck_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif // 4 clicks: configure ramp else if (event == EV_4clicks) { push_state(ramp_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -240,7 +240,7 @@ uint8_t steady_state(Event event, uint16_t arg) { target_level = arg; #endif set_level(nearest_level(arg)); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // click: brighter else if (event == EV_click1_release) { @@ -253,25 +253,25 @@ uint8_t steady_state(Event event, uint16_t arg) { empty_event_sequence(); // remember mode for later save_config_wl(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // hold: dimmer else if (event == EV_click1_hold) { // ramp slower in discrete mode if (arg % HOLD_TIMEOUT != 0) { - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } memorized_level = nearest_level((int16_t)actual_level - ramp_step_size); #ifdef USE_THERMAL_REGULATION target_level = memorized_level; #endif set_level(memorized_level); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // reverse ramp direction on hold release else if (event == EV_click1_hold_release) { save_config_wl(); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #if defined(USE_SET_LEVEL_GRADUALLY) // gradual thermal regulation @@ -279,7 +279,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_SET_LEVEL_GRADUALLY // make thermal adjustment speed scale with magnitude if ((arg & 1) && (actual_level < THERM_FASTER_LEVEL)) { - return MISCHIEF_MANAGED; // adjust slower when not a high mode + return EVENT_HANDLED; // adjust slower when not a high mode } #ifdef THERM_HARD_TURBO_DROP else if ((! (actual_level < THERM_FASTER_LEVEL)) @@ -317,7 +317,7 @@ uint8_t steady_state(Event event, uint16_t arg) { } #endif #endif - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif #ifdef USE_THERMAL_REGULATION @@ -342,7 +342,7 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(stepdown); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // underheating: increase slowly if we're lower than the target // (proportional to how low we are) @@ -358,7 +358,7 @@ uint8_t steady_state(Event event, uint16_t arg) { set_level(stepup); #endif } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif return EVENT_NOT_HANDLED; @@ -370,14 +370,14 @@ uint8_t battcheck_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #ifdef USE_THERMAL_REGULATION // 2 clicks: tempcheck mode else if (event == EV_2clicks) { blink_confirm(2); set_state(tempcheck_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } #endif return EVENT_NOT_HANDLED; @@ -389,18 +389,18 @@ uint8_t tempcheck_state(Event event, uint16_t arg) { // 1 click: off if (event == EV_1click) { set_state(off_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 2 clicks: battcheck mode else if (event == EV_2clicks) { blink_confirm(1); set_state(battcheck_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // 4 clicks: thermal config mode else if (event == EV_4clicks) { push_state(thermal_config_state, 0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } @@ -415,7 +415,7 @@ uint8_t config_state_base(Event event, uint16_t arg, if (event == EV_enter_state) { config_step = 0; set_level(0); - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // advance forward through config steps else if (event == EV_tick) { @@ -429,13 +429,13 @@ uint8_t config_state_base(Event event, uint16_t arg, //set_state(retstate, retval); pop_state(); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // an option was set (return from number_entry_state) else if (event == EV_reenter_state) { config_state_values[config_step] = number_entry_value; config_step ++; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } //return EVENT_NOT_HANDLED; // eat all other events; don't pass any through to parent @@ -502,7 +502,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { blinks_left = arg; entry_step = 0; wait_ticks = 0; - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // advance through the process: // 0: wait a moment @@ -559,7 +559,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { number_entry_value = value; pop_state(); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } // count clicks else if (event == EV_click1_release) { @@ -572,7 +572,7 @@ uint8_t number_entry_state(Event event, uint16_t arg) { delay_4ms(8/2); set_level(0); } - return MISCHIEF_MANAGED; + return EVENT_HANDLED; } return EVENT_NOT_HANDLED; } -- cgit v1.2.3 From 43c020c3f195414a73b7bc4b80379a82731fdebc Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 29 Jun 2023 03:59:53 -0600 Subject: fixed KR4 thermal regulation (r714 on 2023-05-30 removed one line too many, and the value defaulted to MAX_1x7135, which was way too high) https://budgetlightforum.com/t/emisar-d4k-no-stepdown-with-anduril-2023-05-30-noctigon-kr4-hex/218956 --- spaghetti-monster/anduril/cfg-noctigon-kr4.h | 1 + 1 file changed, 1 insertion(+) diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index d2e8107..7a8ea5a 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -22,6 +22,7 @@ #define PWM1_LEVELS 0,1,1,2,2,3,4,5,6,7,8,9,11,12,14,16,17,19,22,24,26,29,31,34,37,40,43,46,49,53,56,60,63,67,71,74,78,82,86,89,93,96,99,103,105,108,110,112,114,115,116,116,115,114,112,109,106,101,95,89,81,71,60,48,34,19,20,21,22,23,24,26,27,28,30,31,32,34,36,37,39,41,43,45,47,49,51,53,56,58,61,63,66,69,72,75,78,81,84,88,91,95,99,103,107,111,115,119,124,129,133,138,143,149,154,159,165,171,177,183,189,196,203,210,217,224,231,239,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,20,30,41,52,63,75,87,99,112,125,138,151,165,179,194,208,224,239,255 #define PWM_TOPS 16383,16383,11750,14690,9183,12439,13615,13955,13877,13560,13093,12529,13291,12513,12756,12769,11893,11747,12085,11725,11329,11316,10851,10713,10518,10282,10016,9729,9428,9298,8971,8794,8459,8257,8043,7715,7497,7275,7052,6753,6538,6260,5994,5798,5501,5271,5006,4758,4525,4268,4030,3775,3508,3263,3010,2752,2517,2256,1998,1763,1512,1249,994,749,497,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#define MIN_THERM_STEPDOWN 66 // should be above highest dyn_pwm level // less ripple, but lows are a bit higher than ideal: // maxreg at 130, dynamic PWM: level_calc.py 5.01 2 149 7135 1 0.3 1740 FET 1 10 3190 --pwm dyn:64:4096:255 -- cgit v1.2.3 From fb146684fa9e7b960de0c52d55fc3e04d71ee13c Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 3 Jul 2023 02:54:09 -0600 Subject: added Noctigon M44 sources (oops, forgot to do this earlier) (files are dated 2023-05-30) --- hwdef-noctigon-m44.c | 165 +++++++++++++++++++++ hwdef-noctigon-m44.h | 207 +++++++++++++++++++++++++++ spaghetti-monster/anduril/cfg-noctigon-m44.h | 110 ++++++++++++++ 3 files changed, 482 insertions(+) create mode 100644 hwdef-noctigon-m44.c create mode 100644 hwdef-noctigon-m44.h create mode 100644 spaghetti-monster/anduril/cfg-noctigon-m44.h diff --git a/hwdef-noctigon-m44.c b/hwdef-noctigon-m44.c new file mode 100644 index 0000000..482ef05 --- /dev/null +++ b/hwdef-noctigon-m44.c @@ -0,0 +1,165 @@ +// hwdef for Noctigon M44 2-channel light +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// set new values for both channels, +// handling any possible combination +// and any before/after state +void set_pwms(uint16_t ch1_pwm, uint16_t ch2_pwm, uint16_t top) { + bool was_on = (CH1_PWM>0) | (CH2_PWM>0); + bool now_on = (ch1_pwm>0) | (ch2_pwm>0); + + if (! now_on) { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_TOP = PWM_TOP_INIT; + PWM_CNT = 0; + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp + CH2_ENABLE_PORT &= ~(1 << CH2_ENABLE_PIN); // disable opamp + return; + } + + if (ch1_pwm) + CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable opamp + else + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp + + if (ch2_pwm) + CH2_ENABLE_PORT |= (1 << CH2_ENABLE_PIN); // enable opamp + else + CH2_ENABLE_PORT &= ~(1 << CH2_ENABLE_PIN); // disable opamp + + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; + + // manual phase sync when changing level while already on + if (was_on && now_on) while(PWM_CNT > (top - 32)) {} + + PWM_TOP = top; + + // reset phase when turning on or off + //if ((! was_on) | (! now_on)) PWM_CNT = 0; + if (! was_on) PWM_CNT = 0; +} + +void set_level_ch1(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, PWM_TOP_INIT); + + level --; + uint16_t pwm = PWM_GET(pwm1_levels, level); + uint16_t top = PWM_GET(pwm_tops, level); + set_pwms(pwm, 0, top); +} + +void set_level_ch2(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, PWM_TOP_INIT); + + level --; + uint16_t pwm = PWM_GET(pwm1_levels, level); + uint16_t top = PWM_GET(pwm_tops, level); + set_pwms(0, pwm, top); +} + +void set_level_both(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, PWM_TOP_INIT); + + level --; + uint16_t pwm = PWM_GET(pwm1_levels, level); + uint16_t top = PWM_GET(pwm_tops, level); + set_pwms(pwm, pwm, top); +} + +void set_level_blend(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, PWM_TOP_INIT); + + level --; + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + PWM_DATATYPE top = PWM_GET(pwm_tops, level); + uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); + + // don't turn off either emitter entirely while using middle blends + if ((0 == ch1_pwm) && (blend < 255)) ch1_pwm = 1; + if ((0 == ch2_pwm) && (blend > 0)) ch2_pwm = 1; + + set_pwms(ch1_pwm, ch2_pwm, top); +} + +void set_level_auto(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, PWM_TOP_INIT); + + level --; + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + PWM_DATATYPE top = PWM_GET(pwm_tops, level); + uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; + if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + blend = 255 - blend; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); + + set_pwms(ch1_pwm, ch2_pwm, top); +} + + +///// bump each channel toward a target value ///// +bool gradual_adjust(uint16_t ch1_pwm, uint16_t ch2_pwm) { + GRADUAL_ADJUST_SIMPLE(ch1_pwm, CH1_PWM); + GRADUAL_ADJUST_SIMPLE(ch2_pwm, CH2_PWM); + + // check for completion + if ((ch1_pwm == CH1_PWM) + && (ch2_pwm == CH2_PWM)) { + return true; // done + } + return false; // not done yet +} + +bool gradual_tick_ch1(uint8_t gt) { + uint16_t pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(pwm, 0); +} + +bool gradual_tick_ch2(uint8_t gt) { + uint16_t pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(0, pwm); +} + +bool gradual_tick_both(uint8_t gt) { + uint16_t pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(pwm, pwm); +} + +bool gradual_tick_blend(uint8_t gt) { + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE top = PWM_GET(pwm_tops, gt); + uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); + + return gradual_adjust(ch1_pwm, ch2_pwm); +} + +bool gradual_tick_auto(uint8_t gt) { + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE top = PWM_GET(pwm_tops, gt); + uint8_t blend = 255 * (uint16_t)gt / RAMP_SIZE; + if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + blend = 255 - blend; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); + + return gradual_adjust(ch1_pwm, ch2_pwm); +} + + diff --git a/hwdef-noctigon-m44.h b/hwdef-noctigon-m44.h new file mode 100644 index 0000000..02b5904 --- /dev/null +++ b/hwdef-noctigon-m44.h @@ -0,0 +1,207 @@ +// hwdef for Noctigon M44 2-channel light +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * Pin / Name / Function + * 1 PA6 ch2 LED PWM (boost) (PWM1B) + * 2 PA5 R: red aux LED (PWM0B) + * 3 PA4 G: green aux LED + * 4 PA3 B: blue aux LED + * 5 PA2 button LED + * 6 PA1 (none) + * 7 PA0 Opamp 2 enable (channel 2 LEDs) + * 8 GND GND + * 9 VCC VCC + * 10 PC5 (none) + * 11 PC4 (none) + * 12 PC3 RESET + * 13 PC2 (none) + * 14 PC1 SCK + * 15 PC0 (none) + * 16 PB3 ch1 LED PWM (linear) (PWM1A) + * 17 PB2 MISO + * 18 PB1 MOSI / battery voltage (ADC6) + * 19 PB0 Opamp 1 enable (channel 1 LEDs) + * 20 PA7 e-switch (PCINT7) + * ADC12 thermal sensor + */ + +#define HWDEF_C_FILE hwdef-noctigon-m44.c + +#define ATTINY 1634 +#include + +// channel modes: +// * 0. channel 1 only +// * 1. channel 2 only +// * 2. both channels, tied together +// * 3. both channels, manual blend +// * 4? both channels, manual blend, max 200% power +// * 4. both channels, auto blend, reversible +#define NUM_CHANNEL_MODES 5 +#define CM_CH1 0 +#define CM_CH2 1 +#define CM_BOTH 2 +#define CM_BLEND 3 +#define CM_AUTO 4 +// TODO: Add RGB aux channel modes + +#define CHANNEL_MODES_ENABLED 0b00011111 +#define CHANNEL_HAS_ARGS 0b00011000 +// _, _, _, 128=middle CCT, 0=warm-to-cool +#define CHANNEL_MODE_ARGS 0,0,0,128,0 + +#define USE_CHANNEL_MODES +#define USE_CHANNEL_MODE_ARGS +#define SET_LEVEL_MODES set_level_ch1, \ + set_level_ch2, \ + set_level_both, \ + set_level_blend, \ + set_level_auto +// gradual ticking for thermal regulation +#define GRADUAL_TICK_MODES gradual_tick_ch1, \ + gradual_tick_ch2, \ + gradual_tick_both, \ + gradual_tick_blend, \ + gradual_tick_auto +// can use some of the common handlers +#define USE_CALC_2CH_BLEND + + +#define PWM_CHANNELS 1 // old, remove this + +#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // regular ramp table +//#define PWM2_DATATYPE uint16_t // max "200% power" ramp table +//#define PWM3_DATATYPE uint16_t // PWM_TOPs for 2nd ramp table + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 511 +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +#define CH1_PIN PB3 // pin 16, Opamp reference +#define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 +#define CH1_ENABLE_PIN PB0 // pin 19, Opamp power +#define CH1_ENABLE_PORT PORTB // control port for PB0 + +#define CH2_PIN PA6 // pin 1, 2nd LED Opamp reference +#define CH2_PWM OCR1B // OCR1B is the output compare register for PA6 +#define CH2_ENABLE_PIN PA0 // pin 7, Opamp power +#define CH2_ENABLE_PORT PORTA // control port for PA0 + + +#ifndef SWITCH_PIN +#define SWITCH_PIN PA7 // pin 20 +#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt +#define SWITCH_PCIE PCIE0 // PCIE1 is for PCINT[7:0] +#define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] +#define SWITCH_PORT PINA // PINA or PINB or PINC +#define SWITCH_PUE PUEA // pullup group A +#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#endif + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 +// pin to ADC mappings are in DS table 19-4 +#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 +// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 +#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D +// DS tables 19-3, 19-4 +// Bit 7 6 5 4 3 2 1 0 +// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 +// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 +// divided by ... +// REFS[1:0] = 1, 0 for internal 1.1V reference +// other bits reserved +#define ADMUX_VOLTAGE_DIVIDER 0b10000110 +#define ADC_PRSCL 0x07 // clk/128 + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// D1, R1, R2 = 0, 330, 100 +#ifndef ADC_44 +//#define ADC_44 981 // raw value at 4.40V +#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 +#endif +#ifndef ADC_22 +//#define ADC_22 489 // raw value at 2.20V +#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 +#endif + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + +#define BUTTON_LED_PIN PA2 // pin 5 +#define BUTTON_LED_PORT PORTA // for all "PA" pins +#define BUTTON_LED_DDR DDRA // for all "PA" pins +#define BUTTON_LED_PUE PUEA // for all "PA" pins + + +void set_level_ch1(uint8_t level); +void set_level_ch2(uint8_t level); +void set_level_both(uint8_t level); +void set_level_blend(uint8_t level); +void set_level_auto(uint8_t level); + +bool gradual_tick_ch1(uint8_t gt); +bool gradual_tick_ch2(uint8_t gt); +bool gradual_tick_both(uint8_t gt); +bool gradual_tick_blend(uint8_t gt); +bool gradual_tick_auto(uint8_t gt); + + +// with so many pins, doing this all with #ifdefs gets awkward... +// ... so just hardcode it in each hwdef file instead +inline void hwdef_setup() { + // enable output ports + //DDRC = (1 << CH3_PIN); + DDRB = (1 << CH1_PIN) + | (1 << CH1_ENABLE_PIN) + ; + DDRA = (1 << CH2_PIN) + | (1 << CH2_ENABLE_PIN) + | (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + | (1 << BUTTON_LED_PIN) + ; + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // Linear opamp PWM for both main and 2nd LEDs (10-bit) + // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) + TCCR1A = (1< v) { v += 64; } + // fixed-rate lowpass, stable but very slow + // (move by only 0.5 ADC units per measurement, 1 ADC unit = 64) + if (r < s) { s -= 32; } + if (r > s) { s += 32; } + #elif 1 + // 1/8th proportional lowpass, faster but less stable + int16_t diff = (r/8) - (s/8); + s += diff; #else - // weighted lowpass, faster but less stable - v = (m>>1) + (v>>1); + // 50% proportional lowpass, fastest but least stable + s = (r>>1) + (s>>1); #endif - adc_smooth[0] = v; - measurement = v; + adc_smooth[0] = s; + measurement = s; } #endif else measurement = adc_smooth[0]; diff --git a/spaghetti-monster/fsm-wdt.c b/spaghetti-monster/fsm-wdt.c index 7c25e9f..64f006e 100644 --- a/spaghetti-monster/fsm-wdt.c +++ b/spaghetti-monster/fsm-wdt.c @@ -122,8 +122,10 @@ void WDT_inner() { #ifndef USE_SLEEP_LVP return; // no sleep LVP needed if nothing drains power while off #else - // stop here, usually... but proceed often enough for sleep LVP to work - if (0 != (ticks_since_last & 0x07)) return; + // stop here, usually... except during the first few seconds asleep, + // and once in a while afterward for sleep LVP + if ((ticks_since_last > (8 * SLEEP_TICKS_PER_SECOND)) + && (0 != (ticks_since_last & 0x0f))) return; adc_trigger = 0; // make sure a measurement will happen adc_active_now = 1; // use ADC noise reduction sleep mode -- cgit v1.2.3 From 95a9eb6b3078915a2686c7ec55320273ef429838 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 10 Jul 2023 11:56:04 -0600 Subject: refactored how channel modes are defined, and converted emisar-2ch build --- hwdef-emisar-2ch.c | 46 +++ hwdef-emisar-2ch.h | 53 ++-- spaghetti-monster/anduril/cfg-emisar-2ch.h | 3 + spaghetti-monster/anduril/load-save-config-fsm.h | 2 +- spaghetti-monster/chan-rgbaux.h | 50 ++++ spaghetti-monster/fsm-channels.c | 347 +++++++++++++++++++++++ spaghetti-monster/fsm-channels.h | 136 +++++++++ spaghetti-monster/fsm-ramping.c | 345 +--------------------- spaghetti-monster/fsm-ramping.h | 85 +----- spaghetti-monster/spaghetti-monster.h | 2 + 10 files changed, 610 insertions(+), 459 deletions(-) create mode 100644 spaghetti-monster/fsm-channels.c create mode 100644 spaghetti-monster/fsm-channels.h diff --git a/hwdef-emisar-2ch.c b/hwdef-emisar-2ch.c index 53117e0..427509f 100644 --- a/hwdef-emisar-2ch.c +++ b/hwdef-emisar-2ch.c @@ -3,6 +3,52 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once +#include "chan-rgbaux.c" + + +void set_level_ch1(uint8_t level); +void set_level_ch2(uint8_t level); +void set_level_both(uint8_t level); +void set_level_blend(uint8_t level); +void set_level_auto(uint8_t level); + +bool gradual_tick_ch1(uint8_t gt); +bool gradual_tick_ch2(uint8_t gt); +bool gradual_tick_both(uint8_t gt); +bool gradual_tick_blend(uint8_t gt); +bool gradual_tick_auto(uint8_t gt); + + +Channel channels[] = { + { // channel 1 only + .set_level = set_level_ch1, + .gradual_tick = gradual_tick_ch1, + .has_args = 0 + }, + { // channel 2 only + .set_level = set_level_ch2, + .gradual_tick = gradual_tick_ch2, + .has_args = 0 + }, + { // both channels, tied together (max "200%" power) + .set_level = set_level_both, + .gradual_tick = gradual_tick_both, + .has_args = 0 + }, + { // both channels, manual blend (max "100%" power) + .set_level = set_level_blend, + .gradual_tick = gradual_tick_blend, + .has_args = 1 + }, + { // both channels, auto blend + .set_level = set_level_auto, + .gradual_tick = gradual_tick_auto, + .has_args = 1 + }, + RGB_AUX_CHANNELS +}; + + // set new values for both channels, // handling any possible combination // and any before/after state diff --git a/hwdef-emisar-2ch.h b/hwdef-emisar-2ch.h index 9d1b185..32cbc3b 100644 --- a/hwdef-emisar-2ch.h +++ b/hwdef-emisar-2ch.h @@ -33,37 +33,31 @@ #define HWDEF_C_FILE hwdef-emisar-2ch.c -#define USE_CHANNEL_MODES +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + // channel modes: // * 0. channel 1 only // * 1. channel 2 only // * 2. both channels, tied together // * 3. both channels, manual blend, max 200% power? // * 4. both channels, auto blend, reversible -#define NUM_CHANNEL_MODES 5 -#define CM_CH1 0 -#define CM_CH2 1 -#define CM_BOTH 2 -#define CM_BLEND 3 -#define CM_AUTO 4 - -#define CHANNEL_MODES_ENABLED 0b00011111 -#define CHANNEL_HAS_ARGS 0b00011000 +#define NUM_CHANNEL_MODES (5 + NUM_RGB_AUX_CHANNEL_MODES) +enum channel_modes_e { + CM_CH1 = 0, + CM_CH2, + CM_BOTH, + CM_BLEND, + CM_AUTO, + RGB_AUX_ENUMS +}; + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000011111 #define USE_CHANNEL_MODE_ARGS // _, _, _, 128=middle CCT, 0=warm-to-cool -#define CHANNEL_MODE_ARGS 0,0,0,128,0 - -#define SET_LEVEL_MODES set_level_ch1, \ - set_level_ch2, \ - set_level_both, \ - set_level_blend, \ - set_level_auto -// gradual ticking for thermal regulation -#define GRADUAL_TICK_MODES gradual_tick_ch1, \ - gradual_tick_ch2, \ - gradual_tick_both, \ - gradual_tick_blend, \ - gradual_tick_auto +#define CHANNEL_MODE_ARGS 0,0,0,128,0,RGB_AUX_CM_ARGS + // can use some of the common handlers #define USE_CALC_2CH_BLEND @@ -151,19 +145,6 @@ #define BUTTON_LED_PUE PUEA // for all "PA" pins -void set_level_ch1(uint8_t level); -void set_level_ch2(uint8_t level); -void set_level_both(uint8_t level); -void set_level_blend(uint8_t level); -void set_level_auto(uint8_t level); - -bool gradual_tick_ch1(uint8_t gt); -bool gradual_tick_ch2(uint8_t gt); -bool gradual_tick_both(uint8_t gt); -bool gradual_tick_blend(uint8_t gt); -bool gradual_tick_auto(uint8_t gt); - - inline void hwdef_setup() { // enable output ports //DDRC = (1 << CH3_PIN); diff --git a/spaghetti-monster/anduril/cfg-emisar-2ch.h b/spaghetti-monster/anduril/cfg-emisar-2ch.h index 97e46fc..d158b88 100644 --- a/spaghetti-monster/anduril/cfg-emisar-2ch.h +++ b/spaghetti-monster/anduril/cfg-emisar-2ch.h @@ -31,6 +31,9 @@ //#define CONFIG_WAITING_CHANNEL CM_CH2 //#define CONFIG_BLINK_CHANNEL CM_BOTH +// blink numbers on the main LEDs by default (but allow user to change it) +#define DEFAULT_BLINK_CHANNEL CM_BLEND + #define POLICE_COLOR_STROBE_CH1 CM_CH1 #define POLICE_COLOR_STROBE_CH2 CM_CH2 diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h index 64ff6fd..462b41c 100644 --- a/spaghetti-monster/anduril/load-save-config-fsm.h +++ b/spaghetti-monster/anduril/load-save-config-fsm.h @@ -48,7 +48,7 @@ typedef struct Config { ///// channel modes / color modes #if NUM_CHANNEL_MODES > 1 uint8_t channel_mode; - uint8_t channel_modes_enabled; + uint16_t channel_modes_enabled; #ifdef USE_MANUAL_MEMORY uint8_t manual_memory_channel_mode; #endif diff --git a/spaghetti-monster/chan-rgbaux.h b/spaghetti-monster/chan-rgbaux.h index d19f6ad..ebb1bb9 100644 --- a/spaghetti-monster/chan-rgbaux.h +++ b/spaghetti-monster/chan-rgbaux.h @@ -3,6 +3,56 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once +#define RGB_AUX_ENUMS \ + CM_AUXRED, \ + CM_AUXYEL, \ + CM_AUXGRN, \ + CM_AUXCYN, \ + CM_AUXBLU, \ + CM_AUXPRP, \ + CM_AUXWHT + +#define RGB_AUX_CM_ARGS 0,0,0,0,0,0,0 + +#define NUM_RGB_AUX_CHANNEL_MODES 7 + +#define RGB_AUX_CHANNELS \ + { \ + .set_level = set_level_auxred, \ + .gradual_tick = gradual_tick_null, \ + .has_args = 0 \ + }, \ + { \ + .set_level = set_level_auxyel, \ + .gradual_tick = gradual_tick_null, \ + .has_args = 0 \ + }, \ + { \ + .set_level = set_level_auxgrn, \ + .gradual_tick = gradual_tick_null, \ + .has_args = 0 \ + }, \ + { \ + .set_level = set_level_auxcyn, \ + .gradual_tick = gradual_tick_null, \ + .has_args = 0 \ + }, \ + { \ + .set_level = set_level_auxblu, \ + .gradual_tick = gradual_tick_null, \ + .has_args = 0 \ + }, \ + { \ + .set_level = set_level_auxprp, \ + .gradual_tick = gradual_tick_null, \ + .has_args = 0 \ + }, \ + { \ + .set_level = set_level_auxwht, \ + .gradual_tick = gradual_tick_null, \ + .has_args = 0 \ + } + void set_level_auxred(uint8_t level); void set_level_auxyel(uint8_t level); void set_level_auxgrn(uint8_t level); diff --git a/spaghetti-monster/fsm-channels.c b/spaghetti-monster/fsm-channels.c new file mode 100644 index 0000000..3b30b58 --- /dev/null +++ b/spaghetti-monster/fsm-channels.c @@ -0,0 +1,347 @@ +// fsm-channels.c: Channel mode functions for SpaghettiMonster. +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "fsm-ramping.h" + + +void set_channel_mode(uint8_t mode) { + uint8_t cur_level = actual_level; + // turn off old LEDs before changing channel + set_level(0); + + // change the channel + CH_MODE = mode; + + // update the LEDs + set_level(cur_level); +} + + +#ifdef USE_CALC_2CH_BLEND +// calculate a "tint ramp" blend between 2 channels +// results are placed in *warm and *cool vars +// brightness : total amount of light units to distribute +// top : maximum allowed brightness per channel +// blend : ratio between warm and cool (0 = warm, 128 = 50%, 255 = cool) +void calc_2ch_blend( + PWM_DATATYPE *warm, + PWM_DATATYPE *cool, + PWM_DATATYPE brightness, + PWM_DATATYPE top, + uint8_t blend) { + + #ifndef TINT_RAMPING_CORRECTION + #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint + #endif + + // calculate actual PWM levels based on a single-channel ramp + // and a blend value + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE2 base_PWM = brightness; + + #if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0) + uint8_t level = actual_level - 1; + + // middle tints sag, so correct for that effect + // by adding extra power which peaks at the middle tint + // (correction is only necessary when PWM is fast) + if (level > HALFSPEED_LEVEL) { + base_PWM = brightness + + ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64) + * triangle_wave(blend) / 255); + } + // fade the triangle wave out when above 100% power, + // so it won't go over 200% + if (brightness > top) { + base_PWM -= 2 * ( + ((brightness - top) * TINT_RAMPING_CORRECTION / 64) + * triangle_wave(blend) / 255 + ); + } + // guarantee no more than 200% power + if (base_PWM > (top << 1)) { base_PWM = top << 1; } + #endif + + cool_PWM = (((PWM_DATATYPE2)blend * (PWM_DATATYPE2)base_PWM) + 127) / 255; + warm_PWM = base_PWM - cool_PWM; + // when running at > 100% power, spill extra over to other channel + if (cool_PWM > top) { + warm_PWM += (cool_PWM - top); + cool_PWM = top; + } else if (warm_PWM > top) { + cool_PWM += (warm_PWM - top); + warm_PWM = top; + } + + *warm = warm_PWM; + *cool = cool_PWM; +} +#endif // ifdef USE_CALC_2CH_BLEND + + +#ifdef USE_HSV2RGB +RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v) { + RGB_t color; + + uint16_t region, fpart, high, low, rising, falling; + + if (s == 0) { // grey + color.r = color.g = color.b = v; + return color; + } + + // make hue 0-5 + region = ((uint16_t)h * 6) >> 8; + // find remainder part, make it from 0-255 + fpart = ((uint16_t)h * 6) - (region << 8); + + // calculate graph segments, doing integer multiplication + high = v; + low = (v * (255 - s)) >> 8; + falling = (v * (255 - ((s * fpart) >> 8))) >> 8; + rising = (v * (255 - ((s * (255 - fpart)) >> 8))) >> 8; + + // default floor + color.r = low; + color.g = low; + color.b = low; + + // assign graph shapes based on color cone region + switch (region) { + case 0: + color.r = high; + color.g = rising; + //color.b = low; + break; + case 1: + color.r = falling; + color.g = high; + //color.b = low; + break; + case 2: + //color.r = low; + color.g = high; + color.b = rising; + break; + case 3: + //color.r = low; + color.g = falling; + color.b = high; + break; + case 4: + color.r = rising; + //color.g = low; + color.b = high; + break; + default: + color.r = high; + //color.g = low; + color.b = falling; + break; + } + + return color; +} +#endif // ifdef USE_HSV2RGB + + +///// Common set_level_*() functions shared by multiple lights ///// +// (unique lights should use their own, +// but these common versions cover most of the common hardware designs) + +// TODO: upgrade some older lights to dynamic PWM +// TODO: 1ch w/ dynamic PWM +// TODO: 1ch w/ dynamic PWM and opamp enable pins? +// TODO: 2ch stacked w/ dynamic PWM +// TODO: 2ch stacked w/ dynamic PWM and opamp enable pins? + + +#ifdef USE_SET_LEVEL_1CH +// single set of LEDs with 1 power channel +void set_level_1ch(uint8_t level) { + if (level == 0) { + LOW_PWM_LVL = 0; + } else { + level --; // PWM array index = level - 1 + LOW_PWM_LVL = PWM_GET(low_pwm_levels, level); + } +} +#endif + + +#ifdef USE_SET_LEVEL_2CH_STACKED +// single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear +void set_level_2ch_stacked(uint8_t level) { + if (level == 0) { + LOW_PWM_LVL = 0; + HIGH_PWM_LVL = 0; + } else { + level --; // PWM array index = level - 1 + LOW_PWM_LVL = PWM_GET(low_pwm_levels, level); + HIGH_PWM_LVL = PWM_GET(high_pwm_levels, level); + } +} +#endif + + +#ifdef USE_SET_LEVEL_3CH_STACKED +// single set of LEDs with 3 stacked power channels, like DDFET+N+1 +void set_level_3ch_stacked(uint8_t level) { + if (level == 0) { + LOW_PWM_LVL = 0; + MED_PWM_LVL = 0; + HIGH_PWM_LVL = 0; + } else { + level --; // PWM array index = level - 1 + LOW_PWM_LVL = PWM_GET(low_pwm_levels, level); + MED_PWM_LVL = PWM_GET(med_pwm_levels, level); + HIGH_PWM_LVL = PWM_GET(high_pwm_levels, level); + } +} +#endif + + +#if defined(USE_TINT_RAMPING) && (!defined(TINT_RAMP_TOGGLE_ONLY)) +void set_level_2ch_blend() { + #ifndef TINT_RAMPING_CORRECTION + #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint + #endif + + // calculate actual PWM levels based on a single-channel ramp + // and a global tint value + //PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + uint16_t brightness = PWM1_LVL; + uint16_t warm_PWM, cool_PWM; + #ifdef USE_STACKED_DYN_PWM + uint16_t top = PWM1_TOP; + //uint16_t top = PWM_GET(pwm_tops, actual_level-1); + #else + const uint16_t top = PWM_TOP; + #endif + + // auto-tint modes + uint8_t mytint; + uint8_t level = actual_level - 1; + #if 1 + // perceptual by ramp level + if (tint == 0) { mytint = 255 * (uint16_t)level / RAMP_SIZE; } + else if (tint == 255) { mytint = 255 - (255 * (uint16_t)level / RAMP_SIZE); } + #else + // linear with power level + //if (tint == 0) { mytint = brightness; } + //else if (tint == 255) { mytint = 255 - brightness; } + #endif + // stretch 1-254 to fit 0-255 range (hits every value except 98 and 198) + else { mytint = (tint * 100 / 99) - 1; } + + PWM_DATATYPE2 base_PWM = brightness; + #if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0) + // middle tints sag, so correct for that effect + // by adding extra power which peaks at the middle tint + // (correction is only necessary when PWM is fast) + if (level > HALFSPEED_LEVEL) { + base_PWM = brightness + + ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64) * triangle_wave(mytint) / 255); + } + // fade the triangle wave out when above 100% power, + // so it won't go over 200% + if (brightness > top) { + base_PWM -= 2 * ( + ((brightness - top) * TINT_RAMPING_CORRECTION / 64) + * triangle_wave(mytint) / 255 + ); + } + // guarantee no more than 200% power + if (base_PWM > (top << 1)) { base_PWM = top << 1; } + #endif + + cool_PWM = (((PWM_DATATYPE2)mytint * (PWM_DATATYPE2)base_PWM) + 127) / 255; + warm_PWM = base_PWM - cool_PWM; + // when running at > 100% power, spill extra over to other channel + if (cool_PWM > top) { + warm_PWM += (cool_PWM - top); + cool_PWM = top; + } else if (warm_PWM > top) { + cool_PWM += (warm_PWM - top); + warm_PWM = top; + } + + TINT1_LVL = warm_PWM; + TINT2_LVL = cool_PWM; + + // disable the power channel, if relevant + #ifdef LED_ENABLE_PIN + if (warm_PWM) + LED_ENABLE_PORT |= (1 << LED_ENABLE_PIN); + else + LED_ENABLE_PORT &= ~(1 << LED_ENABLE_PIN); + #endif + #ifdef LED2_ENABLE_PIN + if (cool_PWM) + LED2_ENABLE_PORT |= (1 << LED2_ENABLE_PIN); + else + LED2_ENABLE_PORT &= ~(1 << LED2_ENABLE_PIN); + #endif +} +#endif // ifdef USE_TINT_RAMPING + + +#ifdef USE_GRADUAL_TICK_1CH +void gradual_tick_1ch() { + GRADUAL_TICK_SETUP(); + + GRADUAL_ADJUST_1CH(low_pwm_levels, LOW_PWM_LVL); + + // did we go far enough to hit the next defined ramp level? + // if so, update the main ramp level tracking var + if ((LOW_PWM_LVL == PWM_GET(low_pwm_levels, gt))) + { + GRADUAL_IS_ACTUAL(); + } +} +#endif + + +#ifdef USE_GRADUAL_TICK_2CH_STACKED +void gradual_tick_2ch_stacked() { + GRADUAL_TICK_SETUP(); + + GRADUAL_ADJUST(low_pwm_levels, LOW_PWM_LVL, PWM_TOP); + GRADUAL_ADJUST_1CH(high_pwm_levels, HIGH_PWM_LVL); + + // did we go far enough to hit the next defined ramp level? + // if so, update the main ramp level tracking var + if ( (LOW_PWM_LVL == PWM_GET(low_pwm_levels, gt)) + && (HIGH_PWM_LVL == PWM_GET(high_pwm_levels, gt)) + ) + { + GRADUAL_IS_ACTUAL(); + } +} +#endif + + +#ifdef USE_GRADUAL_TICK_3CH_STACKED +void gradual_tick_3ch_stacked() { + GRADUAL_TICK_SETUP(); + + GRADUAL_ADJUST(low_pwm_levels, LOW_PWM_LVL, PWM_TOP); + GRADUAL_ADJUST(med_pwm_levels, MED_PWM_LVL, PWM_TOP); + GRADUAL_ADJUST_1CH(high_pwm_levels, HIGH_PWM_LVL); + + // did we go far enough to hit the next defined ramp level? + // if so, update the main ramp level tracking var + if ( (LOW_PWM_LVL == PWM_GET(low_pwm_levels, gt)) + && (MED_PWM_LVL == PWM_GET(med_pwm_levels, gt)) + && (HIGH_PWM_LVL == PWM_GET(high_pwm_levels, gt)) + ) + { + GRADUAL_IS_ACTUAL(); + } +} +#endif + + diff --git a/spaghetti-monster/fsm-channels.h b/spaghetti-monster/fsm-channels.h new file mode 100644 index 0000000..b86e9ba --- /dev/null +++ b/spaghetti-monster/fsm-channels.h @@ -0,0 +1,136 @@ +// fsm-channels.h: Channel mode functions for SpaghettiMonster. +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +// always enable channel modes, even if there is only one +#define USE_CHANNEL_MODES + +// typedefs +typedef void SetLevelFunc(uint8_t level); +typedef SetLevelFunc * SetLevelFuncPtr; + +typedef bool GradualTickFunc(uint8_t gt); +typedef GradualTickFunc * GradualTickFuncPtr; + +typedef struct Channel { + SetLevelFuncPtr set_level; + #ifdef USE_SET_LEVEL_GRADUALLY + GradualTickFuncPtr gradual_tick; + #endif + #ifdef USE_CHANNEL_MODE_ARGS + bool has_args; + //uint8_t arg; // is in the config struct, not here + #endif +} Channel; + +Channel channels[]; // values are defined in the hwdef-*.c + +// TODO: size-optimize the case with only 1 channel mode? +// (the arrays and stuff shouldn't be needed) + +#ifdef USE_CFG + #define CH_MODE cfg.channel_mode +#else + // current multi-channel mode + uint8_t channel_mode = DEFAULT_CHANNEL_MODE; + #define CH_MODE channel_mode +#endif + +// FIXME: remove this? +#if NUM_CHANNEL_MODES > 1 +#define USE_CHANNEL_MODES +#endif + +#ifdef USE_CUSTOM_CHANNEL_3H_MODES +// different 3H behavior per channel? +// TODO: move to progmem +// TODO: move to Anduril, not FSM +StatePtr channel_3H_modes[NUM_CHANNEL_MODES]; +#endif + +//#ifdef USE_CHANNEL_MODE_TOGGLES +#if NUM_CHANNEL_MODES > 1 +// user can take unwanted modes out of the rotation +// bitmask +#ifdef USE_CFG + #define channel_mode_enabled(n) ((cfg.channel_modes_enabled >> n) & 1) + #define channel_mode_enable(n) cfg.channel_modes_enabled |= (1 << n) + #define channel_mode_disable(n) cfg.channel_modes_enabled &= ((1 << n) ^ 0xff) +#else + uint16_t channel_modes_enabled = CHANNEL_MODES_ENABLED; + #define channel_mode_enabled(n) ((channel_modes_enabled >> n) & 1) + #define channel_mode_enable(n) channel_modes_enabled |= (1 << n) + #define channel_mode_disable(n) channel_modes_enabled &= ((1 << n) ^ 0xff) + #endif +#endif + +#ifdef USE_CHANNEL_MODE_ARGS + #ifndef USE_CFG + // one byte of extra data per channel mode, like for tint value + uint8_t channel_mode_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; + #endif + // which modes respond to their "arg", and which don't? + //const uint8_t channel_has_args = CHANNEL_HAS_ARGS; + //#define channel_has_args(n) ((CHANNEL_HAS_ARGS >> n) & 1) + // struct member + #define channel_has_args(n) (channels[n].has_args) +#endif + +void set_channel_mode(uint8_t mode); + +#ifdef USE_CALC_2CH_BLEND +void calc_2ch_blend( + PWM_DATATYPE *warm, + PWM_DATATYPE *cool, + PWM_DATATYPE brightness, + PWM_DATATYPE top, + uint8_t blend); +#endif + +#ifdef USE_HSV2RGB +typedef struct RGB_t { + uint8_t r; + uint8_t g; + uint8_t b; +} RGB_t; +RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v); +#endif // ifdef USE_HSV2RGB + + +#ifdef USE_SET_LEVEL_1CH +// TODO: remove this +void set_level_1ch(uint8_t level); +#endif + +#ifdef USE_SET_LEVEL_2CH_STACKED +// TODO: remove this +void set_level_2ch_stacked(uint8_t level); +#endif + +#ifdef USE_SET_LEVEL_3CH_STACKED +// TODO: remove this +void set_level_3ch_stacked(uint8_t level); +#endif + +#if defined(USE_TINT_RAMPING) && (!defined(TINT_RAMP_TOGGLE_ONLY)) +// TODO: remove this +void set_level_2ch_blend(); +#endif + +#ifdef USE_GRADUAL_TICK_1CH +// TODO: remove this +void gradual_tick_1ch(); +#endif + +#ifdef USE_GRADUAL_TICK_2CH_STACKED +// TODO: remove this +void gradual_tick_2ch_stacked(); +#endif + +#ifdef USE_GRADUAL_TICK_3CH_STACKED +// TODO: remove this +void gradual_tick_3ch_stacked(); +#endif + diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c index d4e2068..6419bfd 100644 --- a/spaghetti-monster/fsm-ramping.c +++ b/spaghetti-monster/fsm-ramping.c @@ -6,18 +6,6 @@ #ifdef USE_RAMPING -void set_channel_mode(uint8_t mode) { - uint8_t cur_level = actual_level; - // turn off old LEDs before changing channel - set_level(0); - - // change the channel - CH_MODE = mode; - - // update the LEDs - set_level(cur_level); -} - #ifdef HAS_AUX_LEDS inline void set_level_aux_leds(uint8_t level) { #ifdef USE_INDICATOR_LED_WHILE_RAMPING @@ -55,6 +43,9 @@ void set_level(uint8_t level) { // (pulse the output high for a moment to wake up the power regulator) // (only do this when starting from off and going to a low level) // TODO: allow different jump start behavior per channel mode + // FIXME: don't jump-start during factory reset + // (it seems to cause some eeprom issues on KR4 + // when doing a click with a loose tailcap) if ((! actual_level) && level && (level < JUMP_START_LEVEL)) { @@ -68,7 +59,7 @@ void set_level(uint8_t level) { #endif // call the relevant hardware-specific set_level_*() - SetLevelFuncPtr set_level_func = channel_modes[CH_MODE]; + SetLevelFuncPtr set_level_func = channels[CH_MODE].set_level; set_level_func(level); if (actual_level != level) prev_level = actual_level; @@ -83,185 +74,6 @@ void set_level(uint8_t level) { #endif } -///// Common set_level_*() functions shared by multiple lights ///// -// (unique lights should use their own, -// but these common versions cover most of the common hardware designs) - -#ifdef USE_SET_LEVEL_1CH -// single set of LEDs with 1 power channel -void set_level_1ch(uint8_t level) { - if (level == 0) { - LOW_PWM_LVL = 0; - } else { - level --; // PWM array index = level - 1 - LOW_PWM_LVL = PWM_GET(low_pwm_levels, level); - } -} -#endif - -#ifdef USE_SET_LEVEL_2CH_STACKED -// single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear -void set_level_2ch_stacked(uint8_t level) { - if (level == 0) { - LOW_PWM_LVL = 0; - HIGH_PWM_LVL = 0; - } else { - level --; // PWM array index = level - 1 - LOW_PWM_LVL = PWM_GET(low_pwm_levels, level); - HIGH_PWM_LVL = PWM_GET(high_pwm_levels, level); - } -} -#endif - -#ifdef USE_SET_LEVEL_3CH_STACKED -// single set of LEDs with 3 stacked power channels, like DDFET+N+1 -void set_level_3ch_stacked(uint8_t level) { - if (level == 0) { - LOW_PWM_LVL = 0; - MED_PWM_LVL = 0; - HIGH_PWM_LVL = 0; - } else { - level --; // PWM array index = level - 1 - LOW_PWM_LVL = PWM_GET(low_pwm_levels, level); - MED_PWM_LVL = PWM_GET(med_pwm_levels, level); - HIGH_PWM_LVL = PWM_GET(high_pwm_levels, level); - } -} -#endif - -// TODO: upgrade some older lights to dynamic PWM -// TODO: 1ch w/ dynamic PWM -// TODO: 1ch w/ dynamic PWM and opamp enable pins? -// TODO: 2ch stacked w/ dynamic PWM -// TODO: 2ch stacked w/ dynamic PWM and opamp enable pins? - -#ifdef USE_CALC_2CH_BLEND -// calculate a "tint ramp" blend between 2 channels -// results are placed in *warm and *cool vars -// brightness : total amount of light units to distribute -// top : maximum allowed brightness per channel -// blend : ratio between warm and cool (0 = warm, 128 = 50%, 255 = cool) -void calc_2ch_blend( - PWM_DATATYPE *warm, - PWM_DATATYPE *cool, - PWM_DATATYPE brightness, - PWM_DATATYPE top, - uint8_t blend) { - - #ifndef TINT_RAMPING_CORRECTION - #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint - #endif - - // calculate actual PWM levels based on a single-channel ramp - // and a blend value - PWM_DATATYPE warm_PWM, cool_PWM; - PWM_DATATYPE2 base_PWM = brightness; - - #if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0) - uint8_t level = actual_level - 1; - - // middle tints sag, so correct for that effect - // by adding extra power which peaks at the middle tint - // (correction is only necessary when PWM is fast) - if (level > HALFSPEED_LEVEL) { - base_PWM = brightness - + ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64) - * triangle_wave(blend) / 255); - } - // fade the triangle wave out when above 100% power, - // so it won't go over 200% - if (brightness > top) { - base_PWM -= 2 * ( - ((brightness - top) * TINT_RAMPING_CORRECTION / 64) - * triangle_wave(blend) / 255 - ); - } - // guarantee no more than 200% power - if (base_PWM > (top << 1)) { base_PWM = top << 1; } - #endif - - cool_PWM = (((PWM_DATATYPE2)blend * (PWM_DATATYPE2)base_PWM) + 127) / 255; - warm_PWM = base_PWM - cool_PWM; - // when running at > 100% power, spill extra over to other channel - if (cool_PWM > top) { - warm_PWM += (cool_PWM - top); - cool_PWM = top; - } else if (warm_PWM > top) { - cool_PWM += (warm_PWM - top); - warm_PWM = top; - } - - *warm = warm_PWM; - *cool = cool_PWM; -} -#endif // ifdef USE_CALC_2CH_BLEND - -#ifdef USE_HSV2RGB -RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v) { - RGB_t color; - - uint16_t region, fpart, high, low, rising, falling; - - if (s == 0) { // grey - color.r = color.g = color.b = v; - return color; - } - - // make hue 0-5 - region = ((uint16_t)h * 6) >> 8; - // find remainder part, make it from 0-255 - fpart = ((uint16_t)h * 6) - (region << 8); - - // calculate graph segments, doing integer multiplication - high = v; - low = (v * (255 - s)) >> 8; - falling = (v * (255 - ((s * fpart) >> 8))) >> 8; - rising = (v * (255 - ((s * (255 - fpart)) >> 8))) >> 8; - - // default floor - color.r = low; - color.g = low; - color.b = low; - - // assign graph shapes based on color cone region - switch (region) { - case 0: - color.r = high; - color.g = rising; - //color.b = low; - break; - case 1: - color.r = falling; - color.g = high; - //color.b = low; - break; - case 2: - //color.r = low; - color.g = high; - color.b = rising; - break; - case 3: - //color.r = low; - color.g = falling; - color.b = high; - break; - case 4: - color.r = rising; - //color.g = low; - color.b = high; - break; - default: - color.r = high; - //color.g = low; - color.b = falling; - break; - } - - return color; -} -#endif // ifdef USE_HSV2RGB - - #ifdef USE_LEGACY_SET_LEVEL // (this is mostly just here for reference, temporarily) // single set of LEDs with 1 to 3 stacked power channels, @@ -405,7 +217,7 @@ void gradual_tick() { gt --; // call the relevant hardware-specific function - GradualTickFuncPtr gradual_tick_func = gradual_tick_modes[CH_MODE]; + GradualTickFuncPtr gradual_tick_func = channels[CH_MODE].gradual_tick; bool done = gradual_tick_func(gt); if (done) { @@ -414,155 +226,8 @@ void gradual_tick() { gradual_target = orig; } } - - -#ifdef USE_GRADUAL_TICK_1CH -void gradual_tick_1ch() { - GRADUAL_TICK_SETUP(); - - GRADUAL_ADJUST_1CH(low_pwm_levels, LOW_PWM_LVL); - - // did we go far enough to hit the next defined ramp level? - // if so, update the main ramp level tracking var - if ((LOW_PWM_LVL == PWM_GET(low_pwm_levels, gt))) - { - GRADUAL_IS_ACTUAL(); - } -} -#endif - -#ifdef USE_GRADUAL_TICK_2CH_STACKED -void gradual_tick_2ch_stacked() { - GRADUAL_TICK_SETUP(); - - GRADUAL_ADJUST(low_pwm_levels, LOW_PWM_LVL, PWM_TOP); - GRADUAL_ADJUST_1CH(high_pwm_levels, HIGH_PWM_LVL); - - // did we go far enough to hit the next defined ramp level? - // if so, update the main ramp level tracking var - if ( (LOW_PWM_LVL == PWM_GET(low_pwm_levels, gt)) - && (HIGH_PWM_LVL == PWM_GET(high_pwm_levels, gt)) - ) - { - GRADUAL_IS_ACTUAL(); - } -} -#endif - -#ifdef USE_GRADUAL_TICK_3CH_STACKED -void gradual_tick_3ch_stacked() { - GRADUAL_TICK_SETUP(); - - GRADUAL_ADJUST(low_pwm_levels, LOW_PWM_LVL, PWM_TOP); - GRADUAL_ADJUST(med_pwm_levels, MED_PWM_LVL, PWM_TOP); - GRADUAL_ADJUST_1CH(high_pwm_levels, HIGH_PWM_LVL); - - // did we go far enough to hit the next defined ramp level? - // if so, update the main ramp level tracking var - if ( (LOW_PWM_LVL == PWM_GET(low_pwm_levels, gt)) - && (MED_PWM_LVL == PWM_GET(med_pwm_levels, gt)) - && (HIGH_PWM_LVL == PWM_GET(high_pwm_levels, gt)) - ) - { - GRADUAL_IS_ACTUAL(); - } -} -#endif #endif // ifdef USE_SET_LEVEL_GRADUALLY -#if defined(USE_TINT_RAMPING) && (!defined(TINT_RAMP_TOGGLE_ONLY)) -void set_level_2ch_blend() { - #ifndef TINT_RAMPING_CORRECTION - #define TINT_RAMPING_CORRECTION 26 // 140% brightness at middle tint - #endif - - // calculate actual PWM levels based on a single-channel ramp - // and a global tint value - //PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); - uint16_t brightness = PWM1_LVL; - uint16_t warm_PWM, cool_PWM; - #ifdef USE_STACKED_DYN_PWM - uint16_t top = PWM1_TOP; - //uint16_t top = PWM_GET(pwm_tops, actual_level-1); - #else - const uint16_t top = PWM_TOP; - #endif - - // auto-tint modes - uint8_t mytint; - uint8_t level = actual_level - 1; - #if 1 - // perceptual by ramp level - if (tint == 0) { mytint = 255 * (uint16_t)level / RAMP_SIZE; } - else if (tint == 255) { mytint = 255 - (255 * (uint16_t)level / RAMP_SIZE); } - #else - // linear with power level - //if (tint == 0) { mytint = brightness; } - //else if (tint == 255) { mytint = 255 - brightness; } - #endif - // stretch 1-254 to fit 0-255 range (hits every value except 98 and 198) - else { mytint = (tint * 100 / 99) - 1; } - - PWM_DATATYPE2 base_PWM = brightness; - #if defined(TINT_RAMPING_CORRECTION) && (TINT_RAMPING_CORRECTION > 0) - // middle tints sag, so correct for that effect - // by adding extra power which peaks at the middle tint - // (correction is only necessary when PWM is fast) - if (level > HALFSPEED_LEVEL) { - base_PWM = brightness - + ((((PWM_DATATYPE2)brightness) * TINT_RAMPING_CORRECTION / 64) * triangle_wave(mytint) / 255); - } - // fade the triangle wave out when above 100% power, - // so it won't go over 200% - if (brightness > top) { - base_PWM -= 2 * ( - ((brightness - top) * TINT_RAMPING_CORRECTION / 64) - * triangle_wave(mytint) / 255 - ); - } - // guarantee no more than 200% power - if (base_PWM > (top << 1)) { base_PWM = top << 1; } - #endif - - cool_PWM = (((PWM_DATATYPE2)mytint * (PWM_DATATYPE2)base_PWM) + 127) / 255; - warm_PWM = base_PWM - cool_PWM; - // when running at > 100% power, spill extra over to other channel - if (cool_PWM > top) { - warm_PWM += (cool_PWM - top); - cool_PWM = top; - } else if (warm_PWM > top) { - cool_PWM += (warm_PWM - top); - warm_PWM = top; - } - - TINT1_LVL = warm_PWM; - TINT2_LVL = cool_PWM; - - // disable the power channel, if relevant - #ifdef LED_ENABLE_PIN - if (warm_PWM) - LED_ENABLE_PORT |= (1 << LED_ENABLE_PIN); - else - LED_ENABLE_PORT &= ~(1 << LED_ENABLE_PIN); - #endif - #ifdef LED2_ENABLE_PIN - if (cool_PWM) - LED2_ENABLE_PORT |= (1 << LED2_ENABLE_PIN); - else - LED2_ENABLE_PORT &= ~(1 << LED2_ENABLE_PIN); - #endif -} -#endif // ifdef USE_TINT_RAMPING - - -// define the channel mode lists -// TODO: move to progmem -SetLevelFuncPtr channel_modes[NUM_CHANNEL_MODES] = { SET_LEVEL_MODES }; -#ifdef USE_SET_LEVEL_GRADUALLY -GradualTickFuncPtr gradual_tick_modes[NUM_CHANNEL_MODES] = { GRADUAL_TICK_MODES }; -#endif - - #endif // ifdef USE_RAMPING diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index 36cf89c..0c299c4 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -11,91 +11,9 @@ uint8_t actual_level = 0; // the level used before actual uint8_t prev_level = 0; -// TODO: size-optimize the case with only 1 channel mode -// (the arrays and stuff shouldn't be needed) - -#ifdef USE_CFG - #define CH_MODE cfg.channel_mode -#else - // current multi-channel mode - uint8_t channel_mode = DEFAULT_CHANNEL_MODE; - #define CH_MODE channel_mode -#endif - -#if NUM_CHANNEL_MODES > 1 -#define USE_CHANNEL_MODES -#endif - -// one function per channel mode -typedef void SetLevelFunc(uint8_t level); -typedef SetLevelFunc * SetLevelFuncPtr; -// TODO: move to progmem -SetLevelFuncPtr channel_modes[NUM_CHANNEL_MODES]; - -#ifdef USE_SET_LEVEL_GRADUALLY -// the gradual tick mechanism may be different per channel -typedef bool GradualTickFunc(uint8_t gt); -typedef GradualTickFunc * GradualTickFuncPtr; -// TODO: move to progmem -GradualTickFuncPtr gradual_tick_modes[NUM_CHANNEL_MODES]; -#endif - -#ifdef USE_CUSTOM_CHANNEL_3H_MODES -// different 3H behavior per channel? -// TODO: move to progmem -// TODO: move to Anduril, not FSM -StatePtr channel_3H_modes[NUM_CHANNEL_MODES]; -#endif - -//#ifdef USE_CHANNEL_MODE_TOGGLES -#if NUM_CHANNEL_MODES > 1 -// user can take unwanted modes out of the rotation -// bitmask -#ifdef USE_CFG - #define channel_mode_enabled(n) ((cfg.channel_modes_enabled >> n) & 1) - #define channel_mode_enable(n) cfg.channel_modes_enabled |= (1 << n) - #define channel_mode_disable(n) cfg.channel_modes_enabled &= ((1 << n) ^ 0xff) -#else - uint8_t channel_modes_enabled = CHANNEL_MODES_ENABLED; - #define channel_mode_enabled(n) ((channel_modes_enabled >> n) & 1) - #define channel_mode_enable(n) channel_modes_enabled |= (1 << n) - #define channel_mode_disable(n) channel_modes_enabled &= ((1 << n) ^ 0xff) - #endif -#endif - -#ifdef USE_CHANNEL_MODE_ARGS - #ifndef USE_CFG - // one byte of extra data per channel mode, like for tint value - uint8_t channel_mode_args[NUM_CHANNEL_MODES] = { CHANNEL_MODE_ARGS }; - #endif - // bitmask: which modes respond to their "arg", and which don't? - //const uint8_t channel_has_args = CHANNEL_HAS_ARGS; - #define channel_has_args(n) ((CHANNEL_HAS_ARGS >> n) & 1) -#endif - -void set_channel_mode(uint8_t mode); - void set_level(uint8_t level); //void set_level_smooth(uint8_t level); -#ifdef USE_CALC_2CH_BLEND -void calc_2ch_blend( - PWM_DATATYPE *warm, - PWM_DATATYPE *cool, - PWM_DATATYPE brightness, - PWM_DATATYPE top, - uint8_t blend); -#endif - -#ifdef USE_HSV2RGB -typedef struct RGB_t { - uint8_t r; - uint8_t g; - uint8_t b; -} RGB_t; -RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v); -#endif // ifdef USE_HSV2RGB - #ifdef USE_SET_LEVEL_GRADUALLY // adjust brightness very smoothly uint8_t gradual_target; @@ -140,6 +58,7 @@ void gradual_tick(); // auto-detect the data type for PWM tables // FIXME: PWM bits and data type should be per PWM table +// FIXME: this whole thing is a mess and should be removed #ifndef PWM1_BITS #define PWM1_BITS 8 #define PWM1_TOP 255 @@ -188,6 +107,7 @@ PROGMEM const PWM3_DATATYPE pwm3_levels[] = { PWM3_LEVELS }; #endif // convenience defs for 1 LED with stacked channels +// FIXME: remove this, use pwm1/2/3 instead #ifdef LOW_PWM_LEVELS PROGMEM const PWM_DATATYPE low_pwm_levels[] = { LOW_PWM_LEVELS }; #endif @@ -200,6 +120,7 @@ PROGMEM const PWM_DATATYPE high_pwm_levels[] = { HIGH_PWM_LEVELS }; // 2 channel CCT blending ramp #ifdef BLEND_PWM_LEVELS +// FIXME: remove this, use pwm1/2/3 instead PROGMEM const PWM_DATATYPE blend_pwm_levels[] = { BLEND_PWM_LEVELS }; #endif diff --git a/spaghetti-monster/spaghetti-monster.h b/spaghetti-monster/spaghetti-monster.h index a6916e3..77431f8 100644 --- a/spaghetti-monster/spaghetti-monster.h +++ b/spaghetti-monster/spaghetti-monster.h @@ -25,6 +25,7 @@ #include "fsm-wdt.h" #include "fsm-pcint.h" #include "fsm-standby.h" +#include "fsm-channels.h" #include "fsm-ramping.h" #include "fsm-random.h" #ifdef USE_EEPROM @@ -63,6 +64,7 @@ void loop(); #include "fsm-wdt.c" #include "fsm-pcint.c" #include "fsm-standby.c" +#include "fsm-channels.c" #include "fsm-ramping.c" #include "fsm-random.c" #ifdef USE_EEPROM -- cgit v1.2.3 From 723b5b1ffa8f12b29110a2133a8f09beaf528aad Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 16 Jul 2023 16:27:44 -0600 Subject: fixed d4v2, kr4, m44, emisar-2ch (using new refactor), added RGB aux channel modes to models which didn't have it --- hwdef-emisar-2ch.c | 1 + hwdef-emisar-d4v2.c | 13 +++ hwdef-emisar-d4v2.h | 45 +-------- hwdef-noctigon-kr4-nofet.c | 13 +++ hwdef-noctigon-kr4.c | 13 +++ hwdef-noctigon-kr4.h | 45 +-------- hwdef-noctigon-m44.c | 47 ++++++++++ hwdef-noctigon-m44.h | 131 +++++++++++---------------- spaghetti-monster/anduril/cfg-emisar-2ch.h | 4 +- spaghetti-monster/anduril/cfg-noctigon-m44.h | 6 +- spaghetti-monster/chan-rgbaux.h | 35 ++++--- 11 files changed, 181 insertions(+), 172 deletions(-) diff --git a/hwdef-emisar-2ch.c b/hwdef-emisar-2ch.c index 427509f..793e9bc 100644 --- a/hwdef-emisar-2ch.c +++ b/hwdef-emisar-2ch.c @@ -1,6 +1,7 @@ // Emisar 2-channel generic w/ tint ramping // Copyright (C) 2021-2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later + #pragma once #include "chan-rgbaux.c" diff --git a/hwdef-emisar-d4v2.c b/hwdef-emisar-d4v2.c index db32f19..c4ae5dd 100644 --- a/hwdef-emisar-d4v2.c +++ b/hwdef-emisar-d4v2.c @@ -6,6 +6,19 @@ #include "chan-rgbaux.c" +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // channel 1 only + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, + RGB_AUX_CHANNELS +}; + + // single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear void set_level_main(uint8_t level) { if (level == 0) { diff --git a/hwdef-emisar-d4v2.h b/hwdef-emisar-d4v2.h index 728d9e4..6837bcd 100644 --- a/hwdef-emisar-d4v2.h +++ b/hwdef-emisar-d4v2.h @@ -36,54 +36,23 @@ // allow using aux LEDs as extra channel modes #include "chan-rgbaux.h" -#define USE_CHANNEL_MODES // channel modes: // * 0. FET+7135 stacked -// * 1. aux red -// * 2. aux yellow -// * 3. aux green -// * 4. aux cyan -// * 5. aux blue -// * 6. aux purple -// * 7. aux white -#define NUM_CHANNEL_MODES 8 +// * 1+. aux RGB +#define NUM_CHANNEL_MODES (1 + NUM_RGB_AUX_CHANNEL_MODES) enum CHANNEL_MODES { CM_MAIN = 0, - CM_AUXRED, - CM_AUXYEL, - CM_AUXGRN, - CM_AUXCYN, - CM_AUXBLU, - CM_AUXPRP, - CM_AUXWHT, + RGB_AUX_ENUMS }; #define DEFAULT_CHANNEL_MODE CM_MAIN -#define CHANNEL_MODES_ENABLED 0b00000001 -#define CHANNEL_HAS_ARGS 0b00000000 +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 // no args //#define USE_CHANNEL_MODE_ARGS //#define CHANNEL_MODE_ARGS 0,0,0,0,0,0,0,0 -#define SET_LEVEL_MODES set_level_main, \ - set_level_auxred, \ - set_level_auxyel, \ - set_level_auxgrn, \ - set_level_auxcyn, \ - set_level_auxblu, \ - set_level_auxprp, \ - set_level_auxwht -// gradual ticking for thermal regulation -#define GRADUAL_TICK_MODES gradual_tick_main, \ - gradual_tick_null, \ - gradual_tick_null, \ - gradual_tick_null, \ - gradual_tick_null, \ - gradual_tick_null, \ - gradual_tick_null, \ - gradual_tick_null - #define PWM_CHANNELS 2 // old, remove this @@ -146,10 +115,6 @@ enum CHANNEL_MODES { #undef USE_INDICATOR_LED_WHILE_RAMPING #endif -void set_level_main(uint8_t level); - -bool gradual_tick_main(uint8_t gt); - inline void hwdef_setup() { // enable output ports diff --git a/hwdef-noctigon-kr4-nofet.c b/hwdef-noctigon-kr4-nofet.c index ec984df..8ce9525 100644 --- a/hwdef-noctigon-kr4-nofet.c +++ b/hwdef-noctigon-kr4-nofet.c @@ -6,6 +6,19 @@ #include "chan-rgbaux.c" +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // channel 1 only + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, + RGB_AUX_CHANNELS +}; + + // single set of LEDs with linear power channel void set_level_main(uint8_t level) { if (level == 0) { diff --git a/hwdef-noctigon-kr4.c b/hwdef-noctigon-kr4.c index 5813a9b..e49ff69 100644 --- a/hwdef-noctigon-kr4.c +++ b/hwdef-noctigon-kr4.c @@ -6,6 +6,19 @@ #include "chan-rgbaux.c" +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // channel 1 only + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, + RGB_AUX_CHANNELS +}; + + // single set of LEDs with 2 stacked power channels, linear + DD FET void set_level_main(uint8_t level) { if (level == 0) { diff --git a/hwdef-noctigon-kr4.h b/hwdef-noctigon-kr4.h index 806aeab..202a302 100644 --- a/hwdef-noctigon-kr4.h +++ b/hwdef-noctigon-kr4.h @@ -44,54 +44,23 @@ // allow using aux LEDs as extra channel modes #include "chan-rgbaux.h" -#define USE_CHANNEL_MODES // channel modes: // * 0. linear + DD FET stacked -// * 1. aux red -// * 2. aux yellow -// * 3. aux green -// * 4. aux cyan -// * 5. aux blue -// * 6. aux purple -// * 7. aux white -#define NUM_CHANNEL_MODES 8 +// * 1+. aux RGB +#define NUM_CHANNEL_MODES (1 + NUM_RGB_AUX_CHANNEL_MODES) enum CHANNEL_MODES { CM_MAIN = 0, - CM_AUXRED, - CM_AUXYEL, - CM_AUXGRN, - CM_AUXCYN, - CM_AUXBLU, - CM_AUXPRP, - CM_AUXWHT, + RGB_AUX_ENUMS }; #define DEFAULT_CHANNEL_MODE CM_MAIN -#define CHANNEL_MODES_ENABLED 0b00000001 -#define CHANNEL_HAS_ARGS 0b00000000 +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 // no args //#define USE_CHANNEL_MODE_ARGS //#define CHANNEL_MODE_ARGS 0,0,0,0,0,0,0,0 -#define SET_LEVEL_MODES set_level_main, \ - set_level_auxred, \ - set_level_auxyel, \ - set_level_auxgrn, \ - set_level_auxcyn, \ - set_level_auxblu, \ - set_level_auxprp, \ - set_level_auxwht -// gradual ticking for thermal regulation -#define GRADUAL_TICK_MODES gradual_tick_main, \ - gradual_tick_null, \ - gradual_tick_null, \ - gradual_tick_null, \ - gradual_tick_null, \ - gradual_tick_null, \ - gradual_tick_null, \ - gradual_tick_null - #define PWM_CHANNELS 2 // old, remove this @@ -182,10 +151,6 @@ enum CHANNEL_MODES { #undef USE_INDICATOR_LED_WHILE_RAMPING #endif -void set_level_main(uint8_t level); - -bool gradual_tick_main(uint8_t gt); - inline void hwdef_setup() { // enable output ports diff --git a/hwdef-noctigon-m44.c b/hwdef-noctigon-m44.c index 482ef05..3fc6abe 100644 --- a/hwdef-noctigon-m44.c +++ b/hwdef-noctigon-m44.c @@ -1,8 +1,55 @@ // hwdef for Noctigon M44 2-channel light // Copyright (C) 2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later + #pragma once +#include "chan-rgbaux.c" + + +void set_level_ch1(uint8_t level); +void set_level_ch2(uint8_t level); +void set_level_both(uint8_t level); +void set_level_blend(uint8_t level); +void set_level_auto(uint8_t level); + +bool gradual_tick_ch1(uint8_t gt); +bool gradual_tick_ch2(uint8_t gt); +bool gradual_tick_both(uint8_t gt); +bool gradual_tick_blend(uint8_t gt); +bool gradual_tick_auto(uint8_t gt); + + +Channel channels[] = { + { // channel 1 only + .set_level = set_level_ch1, + .gradual_tick = gradual_tick_ch1, + .has_args = 0 + }, + { // channel 2 only + .set_level = set_level_ch2, + .gradual_tick = gradual_tick_ch2, + .has_args = 0 + }, + { // both channels, tied together (max "200%" power) + .set_level = set_level_both, + .gradual_tick = gradual_tick_both, + .has_args = 0 + }, + { // both channels, manual blend (max "100%" power) + .set_level = set_level_blend, + .gradual_tick = gradual_tick_blend, + .has_args = 1 + }, + { // both channels, auto blend + .set_level = set_level_auto, + .gradual_tick = gradual_tick_auto, + .has_args = 1 + }, + RGB_AUX_CHANNELS +}; + + // set new values for both channels, // handling any possible combination // and any before/after state diff --git a/hwdef-noctigon-m44.h b/hwdef-noctigon-m44.h index 02b5904..f69fdd5 100644 --- a/hwdef-noctigon-m44.h +++ b/hwdef-noctigon-m44.h @@ -28,11 +28,14 @@ * ADC12 thermal sensor */ -#define HWDEF_C_FILE hwdef-noctigon-m44.c - #define ATTINY 1634 #include +#define HWDEF_C_FILE hwdef-noctigon-m44.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + // channel modes: // * 0. channel 1 only // * 1. channel 2 only @@ -40,32 +43,22 @@ // * 3. both channels, manual blend // * 4? both channels, manual blend, max 200% power // * 4. both channels, auto blend, reversible -#define NUM_CHANNEL_MODES 5 -#define CM_CH1 0 -#define CM_CH2 1 -#define CM_BOTH 2 -#define CM_BLEND 3 -#define CM_AUTO 4 -// TODO: Add RGB aux channel modes - -#define CHANNEL_MODES_ENABLED 0b00011111 -#define CHANNEL_HAS_ARGS 0b00011000 +#define NUM_CHANNEL_MODES (5 + NUM_RGB_AUX_CHANNEL_MODES) +enum channel_modes_e { + CM_CH1 = 0, + CM_CH2, + CM_BOTH, + CM_BLEND, + CM_AUTO, + RGB_AUX_ENUMS +}; + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000011111 +#define USE_CHANNEL_MODE_ARGS // _, _, _, 128=middle CCT, 0=warm-to-cool -#define CHANNEL_MODE_ARGS 0,0,0,128,0 +#define CHANNEL_MODE_ARGS 0,0,0,128,0,RGB_AUX_CM_ARGS -#define USE_CHANNEL_MODES -#define USE_CHANNEL_MODE_ARGS -#define SET_LEVEL_MODES set_level_ch1, \ - set_level_ch2, \ - set_level_both, \ - set_level_blend, \ - set_level_auto -// gradual ticking for thermal regulation -#define GRADUAL_TICK_MODES gradual_tick_ch1, \ - gradual_tick_ch2, \ - gradual_tick_both, \ - gradual_tick_blend, \ - gradual_tick_auto // can use some of the common handlers #define USE_CALC_2CH_BLEND @@ -96,6 +89,7 @@ #define CH2_ENABLE_PORT PORTA // control port for PA0 +// e-switch #ifndef SWITCH_PIN #define SWITCH_PIN PA7 // pin 20 #define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt @@ -150,57 +144,42 @@ #define BUTTON_LED_PUE PUEA // for all "PA" pins -void set_level_ch1(uint8_t level); -void set_level_ch2(uint8_t level); -void set_level_both(uint8_t level); -void set_level_blend(uint8_t level); -void set_level_auto(uint8_t level); - -bool gradual_tick_ch1(uint8_t gt); -bool gradual_tick_ch2(uint8_t gt); -bool gradual_tick_both(uint8_t gt); -bool gradual_tick_blend(uint8_t gt); -bool gradual_tick_auto(uint8_t gt); - - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead inline void hwdef_setup() { - // enable output ports - //DDRC = (1 << CH3_PIN); - DDRB = (1 << CH1_PIN) - | (1 << CH1_ENABLE_PIN) - ; - DDRA = (1 << CH2_PIN) - | (1 << CH2_ENABLE_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - | (1 << BUTTON_LED_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // Linear opamp PWM for both main and 2nd LEDs (10-bit) - // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) - TCCR1A = (1< warm white -> cool white) // results are placed in *a, *b, and *c vars diff --git a/hwdef-Sofirn_LT1S-Pro.h b/hwdef-Sofirn_LT1S-Pro.h index a63f906..fa30a09 100644 --- a/hwdef-Sofirn_LT1S-Pro.h +++ b/hwdef-Sofirn_LT1S-Pro.h @@ -13,11 +13,11 @@ * Voltage: VCC */ -#define HWDEF_C_FILE hwdef-Sofirn_LT1S-Pro.c - #define ATTINY 1616 #include +#define HWDEF_C_FILE hwdef-Sofirn_LT1S-Pro.c + // channel modes: // * 0. warm/cool white blend // * 1. auto 2ch white blend (warm -> cool by ramp level) @@ -25,37 +25,24 @@ // * 3. red only // * 4. red + white blend #define NUM_CHANNEL_MODES 5 -#define CM_WHITE 0 -#define CM_AUTO2 1 -#define CM_AUTO3 2 -#define CM_RED 3 -#define CM_WHITE_RED 4 +enum channel_modes_e { + CM_WHITE = 0, + CM_AUTO2, + CM_AUTO3, + CM_RED, + CM_WHITE_RED, +}; #define CHANNEL_MODES_ENABLED 0b00011111 -#define CHANNEL_HAS_ARGS 0b00010001 +#define USE_CHANNEL_MODE_ARGS // 128=middle CCT, _, _, _, 255=100% red #define CHANNEL_MODE_ARGS 128,0,0,0,255 -// TODO: blend mode should enable this automatically? -#define USE_CHANNEL_MODES -// TODO: blend mode should enable this automatically? -#define USE_CHANNEL_MODE_ARGS -// TODO: or maybe if args are defined, the USE_ should be auto-set? -#define SET_LEVEL_MODES set_level_white_blend, \ - set_level_auto_2ch_blend, \ - set_level_auto_3ch_blend, \ - set_level_red, \ - set_level_red_white_blend -// gradual ticking for thermal regulation -#define GRADUAL_TICK_MODES gradual_tick_white_blend, \ - gradual_tick_auto_2ch_blend, \ - gradual_tick_auto_3ch_blend, \ - gradual_tick_red, \ - gradual_tick_red_white_blend // can use some of the common handlers #define USE_CALC_2CH_BLEND //#define USE_CALC_AUTO_3CH_BLEND + // TODO: remove this as soon as it's not needed #define PWM_CHANNELS 1 @@ -108,19 +95,6 @@ #define USE_INDICATOR_LED_WHILE_RAMPING -// custom channel modes -void set_level_red(uint8_t level); -void set_level_white_blend(uint8_t level); -void set_level_auto_2ch_blend(uint8_t level); -void set_level_auto_3ch_blend(uint8_t level); -void set_level_red_white_blend(uint8_t level); - -bool gradual_tick_red(uint8_t gt); -bool gradual_tick_white_blend(uint8_t gt); -bool gradual_tick_auto_2ch_blend(uint8_t gt); -bool gradual_tick_auto_3ch_blend(uint8_t gt); -bool gradual_tick_red_white_blend(uint8_t gt); - inline void hwdef_setup() { -- cgit v1.2.3 From ba8a3d37c3a03c420799ce11d12a1d380ad4e54b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 18 Jul 2023 12:28:24 -0600 Subject: lowercase'd sofirn-lt1s-pro files --- hwdef-Sofirn_LT1S-Pro.c | 269 ------------------------ hwdef-Sofirn_LT1S-Pro.h | 153 -------------- hwdef-sofirn-lt1s-pro.c | 269 ++++++++++++++++++++++++ hwdef-sofirn-lt1s-pro.h | 153 ++++++++++++++ spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h | 2 +- 5 files changed, 423 insertions(+), 423 deletions(-) delete mode 100644 hwdef-Sofirn_LT1S-Pro.c delete mode 100644 hwdef-Sofirn_LT1S-Pro.h create mode 100644 hwdef-sofirn-lt1s-pro.c create mode 100644 hwdef-sofirn-lt1s-pro.h diff --git a/hwdef-Sofirn_LT1S-Pro.c b/hwdef-Sofirn_LT1S-Pro.c deleted file mode 100644 index 6fe0fef..0000000 --- a/hwdef-Sofirn_LT1S-Pro.c +++ /dev/null @@ -1,269 +0,0 @@ -// BLF LT1S Pro hwdef functions -// Copyright (C) 2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - - -void set_level_red(uint8_t level); -void set_level_white_blend(uint8_t level); -void set_level_auto_2ch_blend(uint8_t level); -void set_level_auto_3ch_blend(uint8_t level); -void set_level_red_white_blend(uint8_t level); - -bool gradual_tick_red(uint8_t gt); -bool gradual_tick_white_blend(uint8_t gt); -bool gradual_tick_auto_2ch_blend(uint8_t gt); -bool gradual_tick_auto_3ch_blend(uint8_t gt); -bool gradual_tick_red_white_blend(uint8_t gt); - - -Channel channels[] = { - { // manual blend of warm and cool white - .set_level = set_level_white_blend, - .gradual_tick = gradual_tick_white_blend, - .has_args = 1 - }, - { // auto blend from warm white to cool white - .set_level = set_level_auto_2ch_blend, - .gradual_tick = gradual_tick_auto_2ch_blend, - .has_args = 0 - }, - { // auto blend from red to warm white to cool white - .set_level = set_level_auto_3ch_blend, - .gradual_tick = gradual_tick_auto_3ch_blend, - .has_args = 0 - }, - { // red only - .set_level = set_level_red, - .gradual_tick = gradual_tick_red, - .has_args = 0 - }, - { // manual white blend + adjustable red - .set_level = set_level_red_white_blend, - .gradual_tick = gradual_tick_red_white_blend, - .has_args = 1 - } -}; - - -// calculate a 3-channel "auto tint" blend -// (like red -> warm white -> cool white) -// results are placed in *a, *b, and *c vars -// level : ramp level to convert into 3 channel levels -// (assumes ramp table is "pwm1_levels") -void calc_auto_3ch_blend( - PWM_DATATYPE *a, - PWM_DATATYPE *b, - PWM_DATATYPE *c, - uint8_t level) { - - PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level); - - // tint goes from 0 (red) to 127 (warm white) to 255 (cool white) - uint8_t mytint; - mytint = 255 * (uint16_t)level / RAMP_SIZE; - - // red is high at 0, low at 255 (linear) - *a = (((PWM_DATATYPE2)(255 - mytint) - * (PWM_DATATYPE2)vpwm) + 127) / 255; - // warm white is low at 0 and 255, high at 127 (linear triangle) - *b = (((PWM_DATATYPE2)triangle_wave(mytint) - * (PWM_DATATYPE2)vpwm) + 127) / 255; - // cool white is low at 0, high at 255 (linear) - *c = (((PWM_DATATYPE2)mytint - * (PWM_DATATYPE2)vpwm) + 127) / 255; - -} - - -// single set of LEDs with 1 power channel and dynamic PWM -void set_level_red(uint8_t level) { - if (level == 0) { - RED_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - } else { - level --; // PWM array index = level - 1 - RED_PWM_LVL = PWM_GET(pwm1_levels, level); - // pulse frequency modulation, a.k.a. dynamic PWM - PWM_TOP = PWM_GET(pwm_tops, level); - // force reset phase when turning on from zero - // (because otherwise the initial response is inconsistent) - if (! actual_level) PWM_CNT = 0; - } -} - - -// warm + cool blend w/ dynamic PWM -void set_level_white_blend(uint8_t level) { - if (level == 0) { - WARM_PWM_LVL = 0; - COOL_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 - - PWM_DATATYPE warm_PWM, cool_PWM; - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); - PWM_DATATYPE top = PWM_GET(pwm_tops, level); - uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; - - calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); - - WARM_PWM_LVL = warm_PWM; - COOL_PWM_LVL = cool_PWM; - PWM_TOP = top; - if (! actual_level) PWM_CNT = 0; // reset phase -} - - -// same as white blend, but tint is calculated from the ramp level -void set_level_auto_2ch_blend(uint8_t level) { - if (level == 0) { - WARM_PWM_LVL = 0; - COOL_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 - - PWM_DATATYPE warm_PWM, cool_PWM; - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); - PWM_DATATYPE top = PWM_GET(pwm_tops, level); - uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; - - calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); - - WARM_PWM_LVL = warm_PWM; - COOL_PWM_LVL = cool_PWM; - PWM_TOP = top; - if (! actual_level) PWM_CNT = 0; // reset phase -} - - -// "auto tint" channel mode with dynamic PWM -void set_level_auto_3ch_blend(uint8_t level) { - if (level == 0) { - WARM_PWM_LVL = 0; - COOL_PWM_LVL = 0; - RED_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 - - PWM_DATATYPE a, b, c; - calc_auto_3ch_blend(&a, &b, &c, level); - - // pulse frequency modulation, a.k.a. dynamic PWM - uint16_t top = PWM_GET(pwm_tops, level); - - RED_PWM_LVL = a; - WARM_PWM_LVL = b; - COOL_PWM_LVL = c; - PWM_TOP = top; - if (! actual_level) PWM_CNT = 0; -} - - -// "white + red" channel mode -void set_level_red_white_blend(uint8_t level) { - // set the warm+cool white LEDs first - cfg.channel_mode = CM_WHITE; - set_level_white_blend(level); - cfg.channel_mode = CM_WHITE_RED; - - if (level == 0) { - RED_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 - PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level); - - // set the red LED as a ratio of the white output level - // 0 = no red - // 255 = red at 100% of white channel PWM - uint8_t ratio = cfg.channel_mode_args[cfg.channel_mode]; - - RED_PWM_LVL = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)vpwm) + 127) / 255; - if (! actual_level) PWM_CNT = 0; // reset phase -} - - -///// "gradual tick" functions for smooth thermal regulation ///// - -///// bump each channel toward a target value ///// -bool gradual_adjust(uint16_t red, uint16_t warm, uint16_t cool) { - GRADUAL_ADJUST_SIMPLE(red, RED_PWM_LVL ); - GRADUAL_ADJUST_SIMPLE(warm, WARM_PWM_LVL); - GRADUAL_ADJUST_SIMPLE(cool, COOL_PWM_LVL); - - // check for completion - if ((red == RED_PWM_LVL ) - && (warm == WARM_PWM_LVL) - && (cool == COOL_PWM_LVL)) { - return true; // done - } - return false; // not done yet -} - -bool gradual_tick_red(uint8_t gt) { - uint16_t red = PWM_GET(pwm1_levels, gt); - return gradual_adjust(red, 0, 0); -} - - -bool gradual_tick_white_blend(uint8_t gt) { - // figure out what exact PWM levels we're aiming for - PWM_DATATYPE warm_PWM, cool_PWM; - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); - PWM_DATATYPE top = PWM_GET(pwm_tops, gt); - uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; - - calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); - - return gradual_adjust(0, warm_PWM, cool_PWM); -} - - -// same as white blend, but tint is calculated from the ramp level -bool gradual_tick_auto_2ch_blend(uint8_t gt) { - // figure out what exact PWM levels we're aiming for - PWM_DATATYPE warm_PWM, cool_PWM; - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); - PWM_DATATYPE top = PWM_GET(pwm_tops, gt); - uint8_t blend = 255 * (uint16_t)gt / RAMP_SIZE; - - calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); - - return gradual_adjust(0, warm_PWM, cool_PWM); -} - - -bool gradual_tick_auto_3ch_blend(uint8_t gt) { - // figure out what exact PWM levels we're aiming for - PWM_DATATYPE red, warm, cool; - calc_auto_3ch_blend(&red, &warm, &cool, gt); - return gradual_adjust(red, warm, cool); -} - - -bool gradual_tick_red_white_blend(uint8_t gt) { - // figure out what exact PWM levels we're aiming for - PWM_DATATYPE red, warm, cool; - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); - PWM_DATATYPE top = PWM_GET(pwm_tops, gt); - uint8_t blend = cfg.channel_mode_args[CM_WHITE]; - uint8_t ratio = cfg.channel_mode_args[cfg.channel_mode]; - - red = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)brightness) + 127) / 255; - calc_2ch_blend(&warm, &cool, brightness, top, blend); - - return gradual_adjust(red, warm, cool); -} - diff --git a/hwdef-Sofirn_LT1S-Pro.h b/hwdef-Sofirn_LT1S-Pro.h deleted file mode 100644 index fa30a09..0000000 --- a/hwdef-Sofirn_LT1S-Pro.h +++ /dev/null @@ -1,153 +0,0 @@ -// BLF LT1S Pro driver layout using the Attiny1616 -// Copyright (C) 2022-2023 (FIXME) -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * Driver pinout: - * eSwitch: PA5 - * Aux LED: PB5 - * WW PWM: PB0 (TCA0 WO0) - * CW PWM: PB1 (TCA0 WO1) - * Red PWM: PB2 (TCA0 WO2) - * Voltage: VCC - */ - -#define ATTINY 1616 -#include - -#define HWDEF_C_FILE hwdef-Sofirn_LT1S-Pro.c - -// channel modes: -// * 0. warm/cool white blend -// * 1. auto 2ch white blend (warm -> cool by ramp level) -// * 2. auto 3ch blend (red -> warm -> cool by ramp level) -// * 3. red only -// * 4. red + white blend -#define NUM_CHANNEL_MODES 5 -enum channel_modes_e { - CM_WHITE = 0, - CM_AUTO2, - CM_AUTO3, - CM_RED, - CM_WHITE_RED, -}; - -#define CHANNEL_MODES_ENABLED 0b00011111 -#define USE_CHANNEL_MODE_ARGS -// 128=middle CCT, _, _, _, 255=100% red -#define CHANNEL_MODE_ARGS 128,0,0,0,255 - -// can use some of the common handlers -#define USE_CALC_2CH_BLEND -//#define USE_CALC_AUTO_3CH_BLEND - - -// TODO: remove this as soon as it's not needed -#define PWM_CHANNELS 1 - -#define SWITCH_PIN PIN5_bp -#define SWITCH_PORT VPORTA.IN -#define SWITCH_ISC_REG PORTA.PIN2CTRL -#define SWITCH_VECT PORTA_PORT_vect -#define SWITCH_INTFLG VPORTA.INTFLAGS - - -// dynamic PWM -// PWM parameters of all channels are tied together because they share a counter -#define PWM_TOP_INIT 511 // highest value used in the top half of the ramp -#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM -#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment - -// warm tint channel -//#define WARM_PWM_PIN PB0 -#define WARM_PWM_LVL TCA0.SINGLE.CMP0BUF // CMP1 is the output compare register for PB0 - -// cold tint channel -//#define COOL_PWM_PIN PB1 -#define COOL_PWM_LVL TCA0.SINGLE.CMP1BUF // CMP0 is the output compare register for PB1 - -// red channel -//#define RED_PWM_PIN PB2 -#define RED_PWM_LVL TCA0.SINGLE.CMP2BUF // CMP2 is the output compare register for PB2 - -// only using 16-bit PWM on this light -#define PWM_BITS 16 -#define PWM_GET PWM_GET16 -#define PWM_DATATYPE uint16_t -#define PWM1_DATATYPE uint16_t -#define PWM_DATATYPE2 uint32_t - - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V -#endif - - -// lighted button -#define AUXLED_PIN PIN5_bp -#define AUXLED_PORT PORTB - -// the button lights up -#define USE_INDICATOR_LED -// the button is visible while main LEDs are on -#define USE_INDICATOR_LED_WHILE_RAMPING - - - -inline void hwdef_setup() { - - // set up the system clock to run at 10 MHz instead of the default 3.33 MHz - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); - - //VPORTA.DIR = ...; - // Outputs: - VPORTB.DIR = PIN0_bm // warm white - | PIN1_bm // cool white - | PIN2_bm // red - | PIN5_bm; // aux LED - //VPORTC.DIR = ...; - - // enable pullups on the unused pins to reduce power - PORTA.PIN0CTRL = PORT_PULLUPEN_bm; - PORTA.PIN1CTRL = PORT_PULLUPEN_bm; - PORTA.PIN2CTRL = PORT_PULLUPEN_bm; - PORTA.PIN3CTRL = PORT_PULLUPEN_bm; - PORTA.PIN4CTRL = PORT_PULLUPEN_bm; - PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch - PORTA.PIN6CTRL = PORT_PULLUPEN_bm; - PORTA.PIN7CTRL = PORT_PULLUPEN_bm; - - //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // warm tint channel - //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // cold tint channel - //PORTB.PIN2CTRL = PORT_PULLUPEN_bm; // red LEDs - PORTB.PIN3CTRL = PORT_PULLUPEN_bm; - PORTB.PIN4CTRL = PORT_PULLUPEN_bm; - //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED - - PORTC.PIN0CTRL = PORT_PULLUPEN_bm; - PORTC.PIN1CTRL = PORT_PULLUPEN_bm; - PORTC.PIN2CTRL = PORT_PULLUPEN_bm; - PORTC.PIN3CTRL = PORT_PULLUPEN_bm; - - // set up the PWM - // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf - // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm - // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm - // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm - // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc - // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc - // TODO: add references to MCU documentation - TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm - | TCA_SINGLE_CMP1EN_bm - | TCA_SINGLE_CMP2EN_bm - | TCA_SINGLE_WGMODE_DSBOTTOM_gc; - PWM_TOP = PWM_TOP_INIT; - TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc - | TCA_SINGLE_ENABLE_bm; -} - - -#define LAYOUT_DEFINED - diff --git a/hwdef-sofirn-lt1s-pro.c b/hwdef-sofirn-lt1s-pro.c new file mode 100644 index 0000000..6fe0fef --- /dev/null +++ b/hwdef-sofirn-lt1s-pro.c @@ -0,0 +1,269 @@ +// BLF LT1S Pro hwdef functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + + +void set_level_red(uint8_t level); +void set_level_white_blend(uint8_t level); +void set_level_auto_2ch_blend(uint8_t level); +void set_level_auto_3ch_blend(uint8_t level); +void set_level_red_white_blend(uint8_t level); + +bool gradual_tick_red(uint8_t gt); +bool gradual_tick_white_blend(uint8_t gt); +bool gradual_tick_auto_2ch_blend(uint8_t gt); +bool gradual_tick_auto_3ch_blend(uint8_t gt); +bool gradual_tick_red_white_blend(uint8_t gt); + + +Channel channels[] = { + { // manual blend of warm and cool white + .set_level = set_level_white_blend, + .gradual_tick = gradual_tick_white_blend, + .has_args = 1 + }, + { // auto blend from warm white to cool white + .set_level = set_level_auto_2ch_blend, + .gradual_tick = gradual_tick_auto_2ch_blend, + .has_args = 0 + }, + { // auto blend from red to warm white to cool white + .set_level = set_level_auto_3ch_blend, + .gradual_tick = gradual_tick_auto_3ch_blend, + .has_args = 0 + }, + { // red only + .set_level = set_level_red, + .gradual_tick = gradual_tick_red, + .has_args = 0 + }, + { // manual white blend + adjustable red + .set_level = set_level_red_white_blend, + .gradual_tick = gradual_tick_red_white_blend, + .has_args = 1 + } +}; + + +// calculate a 3-channel "auto tint" blend +// (like red -> warm white -> cool white) +// results are placed in *a, *b, and *c vars +// level : ramp level to convert into 3 channel levels +// (assumes ramp table is "pwm1_levels") +void calc_auto_3ch_blend( + PWM_DATATYPE *a, + PWM_DATATYPE *b, + PWM_DATATYPE *c, + uint8_t level) { + + PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level); + + // tint goes from 0 (red) to 127 (warm white) to 255 (cool white) + uint8_t mytint; + mytint = 255 * (uint16_t)level / RAMP_SIZE; + + // red is high at 0, low at 255 (linear) + *a = (((PWM_DATATYPE2)(255 - mytint) + * (PWM_DATATYPE2)vpwm) + 127) / 255; + // warm white is low at 0 and 255, high at 127 (linear triangle) + *b = (((PWM_DATATYPE2)triangle_wave(mytint) + * (PWM_DATATYPE2)vpwm) + 127) / 255; + // cool white is low at 0, high at 255 (linear) + *c = (((PWM_DATATYPE2)mytint + * (PWM_DATATYPE2)vpwm) + 127) / 255; + +} + + +// single set of LEDs with 1 power channel and dynamic PWM +void set_level_red(uint8_t level) { + if (level == 0) { + RED_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + } else { + level --; // PWM array index = level - 1 + RED_PWM_LVL = PWM_GET(pwm1_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + PWM_TOP = PWM_GET(pwm_tops, level); + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; + } +} + + +// warm + cool blend w/ dynamic PWM +void set_level_white_blend(uint8_t level) { + if (level == 0) { + WARM_PWM_LVL = 0; + COOL_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + return; + } + + level --; // PWM array index = level - 1 + + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + PWM_DATATYPE top = PWM_GET(pwm_tops, level); + uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + + WARM_PWM_LVL = warm_PWM; + COOL_PWM_LVL = cool_PWM; + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; // reset phase +} + + +// same as white blend, but tint is calculated from the ramp level +void set_level_auto_2ch_blend(uint8_t level) { + if (level == 0) { + WARM_PWM_LVL = 0; + COOL_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + return; + } + + level --; // PWM array index = level - 1 + + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + PWM_DATATYPE top = PWM_GET(pwm_tops, level); + uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + + WARM_PWM_LVL = warm_PWM; + COOL_PWM_LVL = cool_PWM; + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; // reset phase +} + + +// "auto tint" channel mode with dynamic PWM +void set_level_auto_3ch_blend(uint8_t level) { + if (level == 0) { + WARM_PWM_LVL = 0; + COOL_PWM_LVL = 0; + RED_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + return; + } + + level --; // PWM array index = level - 1 + + PWM_DATATYPE a, b, c; + calc_auto_3ch_blend(&a, &b, &c, level); + + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET(pwm_tops, level); + + RED_PWM_LVL = a; + WARM_PWM_LVL = b; + COOL_PWM_LVL = c; + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; +} + + +// "white + red" channel mode +void set_level_red_white_blend(uint8_t level) { + // set the warm+cool white LEDs first + cfg.channel_mode = CM_WHITE; + set_level_white_blend(level); + cfg.channel_mode = CM_WHITE_RED; + + if (level == 0) { + RED_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + return; + } + + level --; // PWM array index = level - 1 + PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level); + + // set the red LED as a ratio of the white output level + // 0 = no red + // 255 = red at 100% of white channel PWM + uint8_t ratio = cfg.channel_mode_args[cfg.channel_mode]; + + RED_PWM_LVL = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)vpwm) + 127) / 255; + if (! actual_level) PWM_CNT = 0; // reset phase +} + + +///// "gradual tick" functions for smooth thermal regulation ///// + +///// bump each channel toward a target value ///// +bool gradual_adjust(uint16_t red, uint16_t warm, uint16_t cool) { + GRADUAL_ADJUST_SIMPLE(red, RED_PWM_LVL ); + GRADUAL_ADJUST_SIMPLE(warm, WARM_PWM_LVL); + GRADUAL_ADJUST_SIMPLE(cool, COOL_PWM_LVL); + + // check for completion + if ((red == RED_PWM_LVL ) + && (warm == WARM_PWM_LVL) + && (cool == COOL_PWM_LVL)) { + return true; // done + } + return false; // not done yet +} + +bool gradual_tick_red(uint8_t gt) { + uint16_t red = PWM_GET(pwm1_levels, gt); + return gradual_adjust(red, 0, 0); +} + + +bool gradual_tick_white_blend(uint8_t gt) { + // figure out what exact PWM levels we're aiming for + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE top = PWM_GET(pwm_tops, gt); + uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + + return gradual_adjust(0, warm_PWM, cool_PWM); +} + + +// same as white blend, but tint is calculated from the ramp level +bool gradual_tick_auto_2ch_blend(uint8_t gt) { + // figure out what exact PWM levels we're aiming for + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE top = PWM_GET(pwm_tops, gt); + uint8_t blend = 255 * (uint16_t)gt / RAMP_SIZE; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + + return gradual_adjust(0, warm_PWM, cool_PWM); +} + + +bool gradual_tick_auto_3ch_blend(uint8_t gt) { + // figure out what exact PWM levels we're aiming for + PWM_DATATYPE red, warm, cool; + calc_auto_3ch_blend(&red, &warm, &cool, gt); + return gradual_adjust(red, warm, cool); +} + + +bool gradual_tick_red_white_blend(uint8_t gt) { + // figure out what exact PWM levels we're aiming for + PWM_DATATYPE red, warm, cool; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE top = PWM_GET(pwm_tops, gt); + uint8_t blend = cfg.channel_mode_args[CM_WHITE]; + uint8_t ratio = cfg.channel_mode_args[cfg.channel_mode]; + + red = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)brightness) + 127) / 255; + calc_2ch_blend(&warm, &cool, brightness, top, blend); + + return gradual_adjust(red, warm, cool); +} + diff --git a/hwdef-sofirn-lt1s-pro.h b/hwdef-sofirn-lt1s-pro.h new file mode 100644 index 0000000..3cc0ca9 --- /dev/null +++ b/hwdef-sofirn-lt1s-pro.h @@ -0,0 +1,153 @@ +// BLF LT1S Pro driver layout using the Attiny1616 +// Copyright (C) 2022-2023 (FIXME) +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * Driver pinout: + * eSwitch: PA5 + * Aux LED: PB5 + * WW PWM: PB0 (TCA0 WO0) + * CW PWM: PB1 (TCA0 WO1) + * Red PWM: PB2 (TCA0 WO2) + * Voltage: VCC + */ + +#define ATTINY 1616 +#include + +#define HWDEF_C_FILE hwdef-sofirn-lt1s-pro.c + +// channel modes: +// * 0. warm/cool white blend +// * 1. auto 2ch white blend (warm -> cool by ramp level) +// * 2. auto 3ch blend (red -> warm -> cool by ramp level) +// * 3. red only +// * 4. red + white blend +#define NUM_CHANNEL_MODES 5 +enum channel_modes_e { + CM_WHITE = 0, + CM_AUTO2, + CM_AUTO3, + CM_RED, + CM_WHITE_RED, +}; + +#define CHANNEL_MODES_ENABLED 0b00011111 +#define USE_CHANNEL_MODE_ARGS +// 128=middle CCT, _, _, _, 255=100% red +#define CHANNEL_MODE_ARGS 128,0,0,0,255 + +// can use some of the common handlers +#define USE_CALC_2CH_BLEND +//#define USE_CALC_AUTO_3CH_BLEND + + +// TODO: remove this as soon as it's not needed +#define PWM_CHANNELS 1 + +#define SWITCH_PIN PIN5_bp +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN2CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS + + +// dynamic PWM +// PWM parameters of all channels are tied together because they share a counter +#define PWM_TOP_INIT 511 // highest value used in the top half of the ramp +#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM +#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment + +// warm tint channel +//#define WARM_PWM_PIN PB0 +#define WARM_PWM_LVL TCA0.SINGLE.CMP0BUF // CMP1 is the output compare register for PB0 + +// cold tint channel +//#define COOL_PWM_PIN PB1 +#define COOL_PWM_LVL TCA0.SINGLE.CMP1BUF // CMP0 is the output compare register for PB1 + +// red channel +//#define RED_PWM_PIN PB2 +#define RED_PWM_LVL TCA0.SINGLE.CMP2BUF // CMP2 is the output compare register for PB2 + +// only using 16-bit PWM on this light +#define PWM_BITS 16 +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM1_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t + + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + + +// lighted button +#define AUXLED_PIN PIN5_bp +#define AUXLED_PORT PORTB + +// the button lights up +#define USE_INDICATOR_LED +// the button is visible while main LEDs are on +#define USE_INDICATOR_LED_WHILE_RAMPING + + + +inline void hwdef_setup() { + + // set up the system clock to run at 10 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + + //VPORTA.DIR = ...; + // Outputs: + VPORTB.DIR = PIN0_bm // warm white + | PIN1_bm // cool white + | PIN2_bm // red + | PIN5_bm; // aux LED + //VPORTC.DIR = ...; + + // enable pullups on the unused pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + PORTA.PIN1CTRL = PORT_PULLUPEN_bm; + PORTA.PIN2CTRL = PORT_PULLUPEN_bm; + PORTA.PIN3CTRL = PORT_PULLUPEN_bm; + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch + PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // warm tint channel + //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // cold tint channel + //PORTB.PIN2CTRL = PORT_PULLUPEN_bm; // red LEDs + PORTB.PIN3CTRL = PORT_PULLUPEN_bm; + PORTB.PIN4CTRL = PORT_PULLUPEN_bm; + //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED + + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + + // set up the PWM + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf + // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm + // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm + // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm + // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc + // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc + // TODO: add references to MCU documentation + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm + | TCA_SINGLE_CMP1EN_bm + | TCA_SINGLE_CMP2EN_bm + | TCA_SINGLE_WGMODE_DSBOTTOM_gc; + PWM_TOP = PWM_TOP_INIT; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc + | TCA_SINGLE_ENABLE_bm; +} + + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index 76ddbba..9744244 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -4,7 +4,7 @@ #pragma once #define MODEL_NUMBER "0623" -#include "hwdef-Sofirn_LT1S-Pro.h" +#include "hwdef-sofirn-lt1s-pro.h" // ATTINY: 1616 // off mode: low (1) -- cgit v1.2.3 From 6c7c99b1be9a684e3a6ccc533f46979b39f7a529 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 18 Jul 2023 14:44:40 -0600 Subject: converted Emisar D4 and BLF Q8 to multi-channel, and enabled previously-removed tactical mode on the Q8 since there seems to be enough space now (also lowercased their hwdef files) --- hwdef-BLF_Q8.h | 20 ------ hwdef-Emisar_D4.h | 48 -------------- hwdef-blf-q8.h | 20 ++++++ hwdef-emisar-d4.c | 59 +++++++++++++++++ hwdef-emisar-d4.h | 104 ++++++++++++++++++++++++++++++ hwdef-emisar-d4v2.c | 2 +- spaghetti-monster/anduril/cfg-blf-q8.h | 9 ++- spaghetti-monster/anduril/cfg-emisar-d4.h | 8 ++- spaghetti-monster/chan-aux.h | 16 +++++ spaghetti-monster/fsm-channels.h | 10 ++- spaghetti-monster/fsm-main.c | 88 +++++++++++++------------ 11 files changed, 267 insertions(+), 117 deletions(-) delete mode 100644 hwdef-BLF_Q8.h delete mode 100644 hwdef-Emisar_D4.h create mode 100644 hwdef-blf-q8.h create mode 100644 hwdef-emisar-d4.c create mode 100644 hwdef-emisar-d4.h diff --git a/hwdef-BLF_Q8.h b/hwdef-BLF_Q8.h deleted file mode 100644 index da55bd4..0000000 --- a/hwdef-BLF_Q8.h +++ /dev/null @@ -1,20 +0,0 @@ -// BLF Q8 driver layout -// Copyright (C) 2018-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -// Q8 driver is the same as a D4, basically - -// ... except the Q8 has a lighted button -#ifndef AUXLED_PIN -#define AUXLED_PIN PB4 // pin 3 -#endif - -// ... and slightly different calibration -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V -#endif - -// Q8 driver is the same as a D4, basically -#include "hwdef-Emisar_D4.h" - diff --git a/hwdef-Emisar_D4.h b/hwdef-Emisar_D4.h deleted file mode 100644 index fdb42a1..0000000 --- a/hwdef-Emisar_D4.h +++ /dev/null @@ -1,48 +0,0 @@ -// Emisar D4 driver layout -// Copyright (C) 2017-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * ---- - * Reset -|1 8|- VCC - * eswitch -|2 7|- - * AUX LED -|3 6|- PWM (FET) - * GND -|4 5|- PWM (1x7135) - * ---- - */ - -#define LAYOUT_DEFINED - -#define PWM_CHANNELS 2 - -//#define AUXLED_PIN PB4 // pin 3 - -#ifndef SWITCH_PIN -#define SWITCH_PIN PB3 // pin 2 -#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt -#endif - -#ifndef PWM1_PIN -#define PWM1_PIN PB0 // pin 5, 1x7135 PWM -#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 -#endif -#ifndef PWM2_PIN -#define PWM2_PIN PB1 // pin 6, FET PWM -#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 -#endif - -// (FIXME: remove? not used?) -//#define VOLTAGE_PIN PB2 // pin 7, voltage ADC -//#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 -//#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 -#define ADC_PRSCL 0x07 // clk/128 - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V -#endif - -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels - diff --git a/hwdef-blf-q8.h b/hwdef-blf-q8.h new file mode 100644 index 0000000..cdf311d --- /dev/null +++ b/hwdef-blf-q8.h @@ -0,0 +1,20 @@ +// BLF Q8 driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// Q8 driver is the same as a D4, basically + +// ... except the Q8 has a lighted button +#ifndef AUXLED_PIN +#define AUXLED_PIN PB4 // pin 3 +#endif + +// ... and slightly different calibration +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + +// Q8 driver is the same as a D4, basically +#include "hwdef-emisar-d4.h" + diff --git a/hwdef-emisar-d4.c b/hwdef-emisar-d4.c new file mode 100644 index 0000000..6069530 --- /dev/null +++ b/hwdef-emisar-d4.c @@ -0,0 +1,59 @@ +// Emisar D4 PWM helper functions +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +//#ifdef AUXLED_PIN +#if 0 +#include "chan-aux.c" +#else +#define AUX_CHANNELS +#endif + +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // main LEDs + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, + AUX_CHANNELS +}; + + +// TODO: implement delta-sigma modulation for better low modes + +// single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear +void set_level_main(uint8_t level) { + if (level == 0) { + CH1_PWM = 0; + CH2_PWM = 0; + return; + } + + level --; // PWM array index = level - 1 + PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); + PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); + + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE pwm2 = PWM_GET(pwm2_levels, gt); + + GRADUAL_ADJUST_STACKED(pwm1, CH1_PWM, PWM_TOP_INIT); + GRADUAL_ADJUST_SIMPLE (pwm2, CH2_PWM); + + if ( (pwm1 == CH1_PWM) + && (pwm2 == CH2_PWM) + ) { + return true; // done + } + return false; // not done yet +} + diff --git a/hwdef-emisar-d4.h b/hwdef-emisar-d4.h new file mode 100644 index 0000000..b3a7500 --- /dev/null +++ b/hwdef-emisar-d4.h @@ -0,0 +1,104 @@ +// Emisar D4 driver layout +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * ---- + * Reset -|1 8|- VCC + * eswitch -|2 7|- + * AUX LED -|3 6|- PWM (FET) + * GND -|4 5|- PWM (1x7135) + * ---- + */ + +#define ATTINY 85 +#include + +#define HWDEF_C_FILE hwdef-emisar-d4.c + +// allow using aux LEDs as extra channel modes (when they exist) +//#ifdef AUXLED_PIN +#if 0 +#include "chan-aux.h" +#else +#define NUM_AUX_CHANNEL_MODES 0 +#endif + +// channel modes +// * 0. FET+7135 stacked +// * 1. button LED (only on some derivative models, like BLF Q8) +#define NUM_CHANNEL_MODES (1 + NUM_AUX_CHANNEL_MODES) +enum CHANNEL_MODES { + CM_MAIN = 0, + CM_AUX, +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00000001 + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 8 // attiny85 only supports up to 8 bits +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define PWM_DATATYPE2 uint16_t +#define PWM1_DATATYPE uint8_t // 1x7135 ramp +#define PWM2_DATATYPE uint8_t // DD FET ramp + +#define PWM_TOP_INIT 255 // highest value used in top half of ramp + +//#define AUXLED_PIN PB4 // pin 3 + +// 1x7135 channel +#ifndef CH1_PIN +#define CH1_PIN PB0 // pin 5, 1x7135 PWM +#define CH1_PWM OCR0A // OCR0A is the output compare register for PB0 +#endif + +// DD FET channel +#ifndef CH2_PIN +#define CH2_PIN PB1 // pin 6, FET PWM +#define CH2_PWM OCR0B // OCR0B is the output compare register for PB1 +#endif + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt +#endif + +// (FIXME: remove? not used?) +//#define VOLTAGE_PIN PB2 // pin 7, voltage ADC +//#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 +//#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 +#define ADC_PRSCL 0x07 // clk/128 + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V +#endif + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + + +inline void hwdef_setup() { + // configure PWM channels + DDRB = (1 << CH1_PIN) + | (1 << CH2_PIN); + + TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) + TCCR0A = PHASE; + + // configure e-switch + PORTB = (1 << SWITCH_PIN); // e-switch is the only input + PCMSK = (1 << SWITCH_PIN); // pin change interrupt uses this pin +} + + +#define LAYOUT_DEFINED + diff --git a/hwdef-emisar-d4v2.c b/hwdef-emisar-d4v2.c index c4ae5dd..ada4eb8 100644 --- a/hwdef-emisar-d4v2.c +++ b/hwdef-emisar-d4v2.c @@ -11,7 +11,7 @@ bool gradual_tick_main(uint8_t gt); Channel channels[] = { - { // channel 1 only + { // main LEDs .set_level = set_level_main, .gradual_tick = gradual_tick_main }, diff --git a/spaghetti-monster/anduril/cfg-blf-q8.h b/spaghetti-monster/anduril/cfg-blf-q8.h index 166c8ca..7eda018 100644 --- a/spaghetti-monster/anduril/cfg-blf-q8.h +++ b/spaghetti-monster/anduril/cfg-blf-q8.h @@ -4,7 +4,9 @@ #pragma once #define MODEL_NUMBER "0611" -#include "hwdef-BLF_Q8.h" +#include "hwdef-blf-q8.h" + +#define RAMP_SIZE 150 // the button lights up #define USE_INDICATOR_LED @@ -18,10 +20,11 @@ // ../../bin/level_calc.py 1 65 7135 1 0.8 150 // ... mixed with this: // ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 -#define RAMP_LENGTH 150 #define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 + #define MAX_1x7135 65 +#define DEFAULT_LEVEL 65 #define HALFSPEED_LEVEL 14 #define QUARTERSPEED_LEVEL 5 @@ -57,4 +60,4 @@ //#undef USE_VOLTAGE_CORRECTION //#undef USE_2C_STYLE_CONFIG //#undef USE_TACTICAL_STROBE_MODE -#undef USE_TACTICAL_MODE +//#undef USE_TACTICAL_MODE diff --git a/spaghetti-monster/anduril/cfg-emisar-d4.h b/spaghetti-monster/anduril/cfg-emisar-d4.h index 15a72ac..4ae5694 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4.h @@ -4,16 +4,20 @@ #pragma once #define MODEL_NUMBER "0111" -#include "hwdef-Emisar_D4.h" +#include "hwdef-emisar-d4.h" #include "hank-cfg.h" +// ATTINY: 85 + +#define RAMP_SIZE 150 // ../../bin/level_calc.py 1 65 7135 1 0.8 150 // ... mixed with this: // ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 -#define RAMP_LENGTH 150 #define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 + #define MAX_1x7135 65 +#define DEFAULT_LEVEL 65 #define HALFSPEED_LEVEL 14 #define QUARTERSPEED_LEVEL 6 diff --git a/spaghetti-monster/chan-aux.h b/spaghetti-monster/chan-aux.h index c8264bd..ff599b8 100644 --- a/spaghetti-monster/chan-aux.h +++ b/spaghetti-monster/chan-aux.h @@ -3,6 +3,22 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once +#define NUM_AUX_CHANNEL_MODES 1 + +// include / exclude field based on compile options +#ifdef USE_CHANNEL_MODE_ARGS + #define AUX_HAS_ARGS , .has_args = 0 +#else + #define AUX_HAS_ARGS +#endif + +#define AUX_CHANNELS \ + { \ + .set_level = set_level_aux, \ + .gradual_tick = gradual_tick_null \ + AUX_HAS_ARGS \ + } + void set_level_aux(uint8_t level); bool gradual_tick_null(uint8_t gt); diff --git a/spaghetti-monster/fsm-channels.h b/spaghetti-monster/fsm-channels.h index b86e9ba..ba2d3fa 100644 --- a/spaghetti-monster/fsm-channels.h +++ b/spaghetti-monster/fsm-channels.h @@ -14,11 +14,19 @@ typedef SetLevelFunc * SetLevelFuncPtr; typedef bool GradualTickFunc(uint8_t gt); typedef GradualTickFunc * GradualTickFuncPtr; +// TODO: implement custom 3H handlers +typedef void ChannelArgFunc(); +typedef ChannelArgFunc * ChannelArgFuncPtr; + typedef struct Channel { SetLevelFuncPtr set_level; #ifdef USE_SET_LEVEL_GRADUALLY GradualTickFuncPtr gradual_tick; #endif + #ifdef USE_CUSTOM_3H_HANDLERS + // TODO: implement custom 3H handlers + ChannelArgFuncPtr ramp_channel_arg; + #endif #ifdef USE_CHANNEL_MODE_ARGS bool has_args; //uint8_t arg; // is in the config struct, not here @@ -30,7 +38,7 @@ Channel channels[]; // values are defined in the hwdef-*.c // TODO: size-optimize the case with only 1 channel mode? // (the arrays and stuff shouldn't be needed) -#ifdef USE_CFG +#if defined(USE_CFG) && (NUM_CHANNEL_MODES > 1) #define CH_MODE cfg.channel_mode #else // current multi-channel mode diff --git a/spaghetti-monster/fsm-main.c b/spaghetti-monster/fsm-main.c index 4116d3f..066188c 100644 --- a/spaghetti-monster/fsm-main.c +++ b/spaghetti-monster/fsm-main.c @@ -26,48 +26,52 @@ ISR(TIMER1_COMPA_vect) { // FIXME: hw_setup() shouldn't be here ... move it entirely to hwdef files #if (ATTINY == 25) || (ATTINY == 45) || (ATTINY == 85) static inline void hw_setup() { - // configure PWM channels - #if PWM_CHANNELS >= 1 - DDRB |= (1 << PWM1_PIN); - TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) - TCCR0A = PHASE; - #if (PWM1_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - // tint ramping needs second channel enabled, - // despite PWM_CHANNELS being only 1 - #if (PWM_CHANNELS >= 2) || defined(USE_TINT_RAMPING) - DDRB |= (1 << PWM2_PIN); - #if (PWM2_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - #if PWM_CHANNELS >= 3 - DDRB |= (1 << PWM3_PIN); - #if (PWM3_PIN == PB4) // Second PWM counter is ... weird - TCCR1 = _BV (CS10); - GTCCR = _BV (COM1B1) | _BV (PWM1B); - OCR1C = 255; // Set ceiling value to maximum - #endif - #endif - #if PWM_CHANNELS >= 4 - // 4th PWM channel is ... not actually supported in hardware :( - DDRB |= (1 << PWM4_PIN); - //OCR1C = 255; // Set ceiling value to maximum - TCCR1 = 1<= 1 + DDRB |= (1 << PWM1_PIN); + TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) + TCCR0A = PHASE; + #if (PWM1_PIN == PB4) // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = 255; // Set ceiling value to maximum + #endif + #endif + // tint ramping needs second channel enabled, + // despite PWM_CHANNELS being only 1 + #if (PWM_CHANNELS >= 2) || defined(USE_TINT_RAMPING) + DDRB |= (1 << PWM2_PIN); + #if (PWM2_PIN == PB4) // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = 255; // Set ceiling value to maximum + #endif + #endif + #if PWM_CHANNELS >= 3 + DDRB |= (1 << PWM3_PIN); + #if (PWM3_PIN == PB4) // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = 255; // Set ceiling value to maximum + #endif + #endif + #if PWM_CHANNELS >= 4 + // 4th PWM channel is ... not actually supported in hardware :( + DDRB |= (1 << PWM4_PIN); + //OCR1C = 255; // Set ceiling value to maximum + TCCR1 = 1<= (channel.lm_max + channel.prev_lm): # This shouldn't happen, the FET is assumed to be the highest channel @@ -176,19 +188,20 @@ def multi_pwm(answers, channels): lm_needed = goal_lm - channel.prev_lm - channel.lm_min pwm_top = max_pwms[i] - pwm_avail = pwm_top - channel.pwm_min + pwm_avail = pwm_top - channel.pwm_min - rise_time pwm_needed = pwm_avail * lm_needed / lm_avail + #pwm_needed = min(pwm_needed, pwm_avail) if dyn_pwm and (pwm_top > max_pwm): this_step = max(1, math.floor(pwm_needed)) next_step = this_step + 1 fpart = pwm_needed - math.floor(pwm_needed) correction = (next_step - fpart) / next_step pwm_top = int(pwm_avail * correction) + channel.pwm_min - pwm_avail = pwm_top - channel.pwm_min + pwm_avail = pwm_top - channel.pwm_min - rise_time pwm_needed = pwm_avail * lm_needed / lm_avail max_pwms[i] = pwm_top # save the result - pwm = max(0, pwm_needed + channel.pwm_min) + pwm = max(0, pwm_needed + channel.pwm_min + rise_time) channel.modes.append(pwm) # how close did we get? #ptop = int(round(pwm - channel.pwm_min)) @@ -206,13 +219,18 @@ def multi_pwm(answers, channels): for i in range(answers.num_levels): goal_vis, goal_lm = goals[i] pwms = [] + rise_time = calc_rise_time(i, answers) for c, channel in enumerate(channels): + #top = channel.modes[i] - channel.pwm_min - rise_time top = channel.modes[i] - channel.pwm_min if top < 0: top = 0 - bot = max_pwms[i] - channel.pwm_min - ratio = 100 * (int(round(top)) / float(bot)) - top, bot = channel.modes[i], max_pwms[i] - pwms.append('%.2f/%i (%.3f%%)' % (top, bot, ratio)) + #bot = max_pwms[i] - channel.pwm_min - rise_time + bot = max_pwms[i] + #ratio = 100 * (int(round(top)) / float(bot)) + topf, bot = channel.modes[i], max_pwms[i] + top = int(round(topf)) + ratio = 100 * top / float(bot) + pwms.append('(%.2f) %i/%i (%.3f%%)' % (topf, top, bot, ratio)) if (ratio < prev_ratios[c]) and (ratio > 0): pwms.append('WARN') prev_ratios[c] = ratio @@ -240,6 +258,19 @@ def multi_pwm(answers, channels): print('Ch%i max: %i (%.2f/%s)' % (cnum, i, channel.modes[i-1], max_pwms[i])) +def calc_rise_time(i, answers): + base = answers.rise_time_base + + if (i+1) < answers.quarterspeed_level: + rise_time = base / 4.0 + elif (i+1) < answers.halfspeed_level: + rise_time = base / 2.0 + else: + ratio = 1.0 - math.sqrt((i - base) / (answers.num_levels - base)) + rise_time = answers.rise_time_base * ratio + return rise_time + + def get_value(text, default, args): """Get input from the user, or from the command line args.""" if args: -- cgit v1.2.3 From 188eb9e0f2a31e07d5faee27c3f42dacb818e46e Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 21 Jul 2023 15:44:38 -0600 Subject: converted emisar-d4v2-nofet to multi-channel, and gave it a new ramp with dynamic PWM --- hwdef-emisar-d4v2-nofet.c | 55 +++++++++++++++++++++++ spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h | 31 ++++++------- 2 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 hwdef-emisar-d4v2-nofet.c diff --git a/hwdef-emisar-d4v2-nofet.c b/hwdef-emisar-d4v2-nofet.c new file mode 100644 index 0000000..60d80ea --- /dev/null +++ b/hwdef-emisar-d4v2-nofet.c @@ -0,0 +1,55 @@ +// Emisar D4v2 (no DD FET, 1x7135 only) PWM helper functions +// Copyright (C) 2017-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "chan-rgbaux.c" + +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // main LEDs + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, + RGB_AUX_CHANNELS +}; + + +// single set of LEDs with just a 1x7135 chip, max 350 mA or ~130 lm +void set_level_main(uint8_t level) { + if (level == 0) { + CH1_PWM = 0; + PWM_CNT = 0; // reset phase + return; + } + + level --; // PWM array index = level - 1 + PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET16(pwm_tops, level); + + CH1_PWM = ch1_pwm; + // wait to sync the counter and avoid flashes + while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + + GRADUAL_ADJUST_SIMPLE (pwm1, CH1_PWM); + + if ( (pwm1 == CH1_PWM) + ) { + return true; // done + } + return false; // not done yet +} + diff --git a/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h b/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h index 9c6f0b0..6eddb40 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4v2-nofet.h @@ -3,35 +3,35 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once +// switch to 1-channel support functions +#define HWDEF_C_FILE hwdef-emisar-d4v2-nofet.c + #include "cfg-emisar-d4v2.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0115" // ATTINY: 1634 -// switch to 1-channel support functions -#undef USE_SET_LEVEL_2CH_STACKED -#undef USE_GRADUAL_TICK_2CH_STACKED -#define USE_SET_LEVEL_1CH -#define USE_GRADUAL_TICK_1CH -#undef SET_LEVEL_MODES -#undef GRADUAL_TICK_MODES -#define SET_LEVEL_MODES set_level_1ch -#define GRADUAL_TICK_MODES gradual_tick_1ch - +// the ramp uses only 1x7135 chip, max ~130 lm #undef PWM_CHANNELS #define PWM_CHANNELS 1 -#undef LOW_PWM_LEVELS -#undef HIGH_PWM_LEVELS -#define LOW_PWM_LEVELS 1,1,1,2,2,2,2,3,3,3,3,4,4,5,5,6,6,6,7,8,8,9,9,10,10,11,12,13,13,14,15,16,16,17,18,19,20,21,22,23,23,24,26,27,28,29,30,31,32,33,34,36,37,38,39,41,42,43,45,46,47,49,50,52,53,55,56,58,59,61,62,64,66,67,69,71,72,74,76,78,80,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,116,118,120,122,125,127,129,132,134,136,139,141,144,146,148,151,154,156,159,161,164,166,169,172,174,177,180,183,185,188,191,194,197,200,203,205,208,211,214,217,220,223,226,230,233,236,239,242,245,249,252,255 +#undef PWM1_LEVELS +#undef PWM2_LEVELS +#undef PWM_TOPS +//#define PWM1_LEVELS 1,1,1,2,2,2,2,3,3,3,3,4,4,5,5,6,6,6,7,8,8,9,9,10,10,11,12,13,13,14,15,16,16,17,18,19,20,21,22,23,23,24,26,27,28,29,30,31,32,33,34,36,37,38,39,41,42,43,45,46,47,49,50,52,53,55,56,58,59,61,62,64,66,67,69,71,72,74,76,78,80,81,83,85,87,89,91,93,95,97,99,101,103,105,107,109,111,113,116,118,120,122,125,127,129,132,134,136,139,141,144,146,148,151,154,156,159,161,164,166,169,172,174,177,180,183,185,188,191,194,197,200,203,205,208,211,214,217,220,223,226,230,233,236,239,242,245,249,252,255 +// level_calc.py 3.01 1 150 7135 -1 0.1 140 --pwm dyn:64:4096:255:3 --clock 11:21:8.0 +// (and some manual tweaks to make half/quarter speed levels less bumpy) +#define PWM1_LEVELS 1,1,2,2,3,4,4,5,6,7,9,10,11,11,12,13,13,14,15,15,18,18,17,18,18,19,19,19,19,19,20,20,20,20,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,21,21,22,23,24,24,26,27,28,29,30,31,32,33,34,35,36,38,39,40,42,43,44,46,47,49,50,52,53,55,56,58,60,62,63,65,67,69,71,73,75,77,79,81,83,85,88,90,92,95,97,100,102,105,107,110,112,115,118,121,124,127,129,132,135,139,142,145,148,151,155,158,162,165,169,172,176,179,183,187,191,195,199,203,207,211,215,219,223,228,232,237,241,246,250,255 +#define PWM_TOPS 4094,2719,3280,1954,2599,3032,2342,2548,2626,2635,2246,2261,2244,1964,1956,1929,1743,1733,1763,1697,1492,1362,1245,1231,1132,1118,1034,958,889,826,821,767,717,671,629,591,556,523,493,465,440,416,394,373,354,336,319,304,299,293,279,282,269,257,260,249,251,252,253,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 #undef MAX_1x7135 #define MAX_1x7135 150 #undef QUARTERSPEED_LEVEL #undef HALFSPEED_LEVEL -#define QUARTERSPEED_LEVEL 8 -#define HALFSPEED_LEVEL 16 +#define QUARTERSPEED_LEVEL 11 +#define HALFSPEED_LEVEL 21 +#undef DEFAULT_LEVEL #define DEFAULT_LEVEL 80 #undef RAMP_SMOOTH_CEIL @@ -50,6 +50,7 @@ #define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR #define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL +#undef CANDLE_AMPLITUDE #define CANDLE_AMPLITUDE 60 #undef THERM_FASTER_LEVEL -- cgit v1.2.3 From a9b54d50ea8a630c6d28fcb07f6b1e06245224fc Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 21 Jul 2023 15:45:44 -0600 Subject: forgot this file in previous commit --- hwdef-emisar-d4v2.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hwdef-emisar-d4v2.h b/hwdef-emisar-d4v2.h index 6837bcd..96c57a9 100644 --- a/hwdef-emisar-d4v2.h +++ b/hwdef-emisar-d4v2.h @@ -31,7 +31,9 @@ #define ATTINY 1634 #include +#ifndef HWDEF_C_FILE #define HWDEF_C_FILE hwdef-emisar-d4v2.c +#endif // allow using aux LEDs as extra channel modes #include "chan-rgbaux.h" -- cgit v1.2.3 From b53000bb197027478927a4155418aa32112eee31 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 21 Jul 2023 15:46:13 -0600 Subject: fixed default channel mode after using factory reset with colors --- spaghetti-monster/anduril/factory-reset.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spaghetti-monster/anduril/factory-reset.c b/spaghetti-monster/anduril/factory-reset.c index 1e9714a..f9fb472 100644 --- a/spaghetti-monster/anduril/factory-reset.c +++ b/spaghetti-monster/anduril/factory-reset.c @@ -33,6 +33,11 @@ void factory_reset() { } // explode, if button pressed long enough if (reset) { + #if defined(FACTORY_RESET_WARN_CHANNEL) && defined(DEFAULT_CHANNEL_MODE) + // return to default channel before saving + set_channel_mode(DEFAULT_CHANNEL_MODE); + #endif + // auto-calibrate temperature // AVR 1-Series has factory calibrated thermal sensor, always remove the offset on reset #if defined(USE_THERMAL_REGULATION) && defined(AVRXMEGA3) @@ -43,11 +48,6 @@ void factory_reset() { thermal_config_save(1, 21); #endif - #if defined(FACTORY_RESET_WARN_CHANNEL) && defined(DEFAULT_CHANNEL_MODE) && (FACTORY_RESET_WARN_CHANNEL != DEFAULT_CHANNEL_MODE) - // return to default channel before saving - set_channel_mode(DEFAULT_CHANNEL_MODE); - #endif - // save all settings to eeprom // (assuming they're all at default because we haven't loaded them yet) save_config(); -- cgit v1.2.3 From d4e948ab54c8f71db2790a964668e1f3b399e7db Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 21 Jul 2023 15:47:52 -0600 Subject: converted noctigon-k1 to multi-channel --- hwdef-Noctigon_K1.h | 135 ---------------------- hwdef-noctigon-k1.c | 65 +++++++++++ hwdef-noctigon-k1.h | 170 ++++++++++++++++++++++++++++ hwdef-noctigon-kr4.h | 2 +- spaghetti-monster/anduril/cfg-noctigon-k1.h | 42 +++++-- 5 files changed, 266 insertions(+), 148 deletions(-) delete mode 100644 hwdef-Noctigon_K1.h create mode 100644 hwdef-noctigon-k1.c create mode 100644 hwdef-noctigon-k1.h diff --git a/hwdef-Noctigon_K1.h b/hwdef-Noctigon_K1.h deleted file mode 100644 index 2e44e23..0000000 --- a/hwdef-Noctigon_K1.h +++ /dev/null @@ -1,135 +0,0 @@ -// Noctigon K1 driver layout (attiny1634) -// Copyright (C) 2019-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * (originally known as Emisar D1S V2) - * - * Pin / Name / Function - * 1 PA6 (none) (PWM1B) (reserved for DD drivers) - * 2 PA5 R: red aux LED (PWM0B) - * 3 PA4 G: green aux LED - * 4 PA3 B: blue aux LED - * 5 PA2 (none) (reserved for L: button LED (on some models)) - * 6 PA1 (none) - * 7 PA0 (none) - * 8 GND GND - * 9 VCC VCC - * 10 PC5 (none) - * 11 PC4 (none) - * 12 PC3 RESET - * 13 PC2 (none) - * 14 PC1 SCK - * 15 PC0 (none) PWM0A - * 16 PB3 main LED PWM (PWM1A) - * 17 PB2 MISO - * 18 PB1 MOSI / battery voltage (ADC6) - * 19 PB0 Opamp power - * 20 PA7 e-switch (PCINT7) - * ADC12 thermal sensor - * - * Main LED power uses one pin to turn the Opamp on/off, - * and one pin to control Opamp power level. - * All brightness control uses the power level pin, with 4 kHz 10-bit PWM. - * The on/off pin is only used to turn the main LED on and off, - * not to change brightness. - */ - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1634 -#include - -#define PWM_CHANNELS 1 -#define PWM_BITS 10 // 0 to 1023 at 4 kHz, not 0 to 255 at 16 kHz -#define PWM_TOP 1023 - -#define SWITCH_PIN PA7 // pin 20 -#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt -#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] -#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] -#define SWITCH_PORT PINA // PINA or PINB or PINC - -#define PWM1_PIN PB3 // pin 16, Opamp reference -#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 - -#define LED_ENABLE_PIN PB0 // pin 19, Opamp power -#define LED_ENABLE_PORT PORTB // control port for PB0 - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 256 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - // enable output ports - // Opamp level and Opamp on/off - DDRB = (1 << PWM1_PIN) - | (1 << LED_ENABLE_PIN); - // aux R/G/B - DDRA = (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // WGM1[3:0]: 0,0,1,1: PWM, Phase Correct, 10-bit (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 0,0: PWM OC1B disabled (DS table 12-4) - TCCR1A = (1< (top - 32))) {} + //PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + //if (! actual_level) PWM_CNT = 0; +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + //PWM_DATATYPE pwm2 = PWM_GET(pwm2_levels, gt); + + GRADUAL_ADJUST_SIMPLE (pwm1, CH1_PWM); + //GRADUAL_ADJUST_STACKED(pwm1, CH1_PWM, PWM_TOP_INIT); + //GRADUAL_ADJUST_SIMPLE (pwm2, CH2_PWM); + + if ( (pwm1 == CH1_PWM) + // && (pwm2 == CH2_PWM) + ) { + return true; // done + } + return false; // not done yet +} + diff --git a/hwdef-noctigon-k1.h b/hwdef-noctigon-k1.h new file mode 100644 index 0000000..6467567 --- /dev/null +++ b/hwdef-noctigon-k1.h @@ -0,0 +1,170 @@ +// Noctigon K1 driver layout (attiny1634) +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * (originally known as Emisar D1S V2) + * + * Pin / Name / Function + * 1 PA6 (none) (PWM1B) (reserved for DD drivers) + * 2 PA5 R: red aux LED (PWM0B) + * 3 PA4 G: green aux LED + * 4 PA3 B: blue aux LED + * 5 PA2 (none) (reserved for L: button LED (on some models)) + * 6 PA1 (none) + * 7 PA0 (none) + * 8 GND GND + * 9 VCC VCC + * 10 PC5 (none) + * 11 PC4 (none) + * 12 PC3 RESET + * 13 PC2 (none) + * 14 PC1 SCK + * 15 PC0 (none) PWM0A + * 16 PB3 main LED PWM (PWM1A) + * 17 PB2 MISO + * 18 PB1 MOSI / battery voltage (ADC6) + * 19 PB0 Opamp power + * 20 PA7 e-switch (PCINT7) + * ADC12 thermal sensor + * + * Main LED power uses one pin to turn the Opamp on/off, + * and one pin to control Opamp power level. + * All brightness control uses the power level pin, with 4 kHz 10-bit PWM. + * The on/off pin is only used to turn the main LED on and off, + * not to change brightness. + */ + +#define ATTINY 1634 +#include + +#ifndef HWDEF_C_FILE +#define HWDEF_C_FILE hwdef-noctigon-k1.c +#endif + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +// channel modes: +// * 0. main LED +// * 1+. aux RGB +#define NUM_CHANNEL_MODES (1 + NUM_RGB_AUX_CHANNEL_MODES) +enum CHANNEL_MODES { + CM_MAIN = 0, + RGB_AUX_ENUMS +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 +// no args +//#define USE_CHANNEL_MODE_ARGS +//#define CHANNEL_MODE_ARGS 0,0,0,0,0,0,0,0 + + +#define PWM_CHANNELS 1 // old, remove this + +#define PWM_BITS 10 // 0 to 1023 at 4 kHz, not 0 to 255 at 16 kHz +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // linear ramp + +#define PWM_TOP ICR1 // holds the TOP value for variable-resolution PWM +#define PWM_TOP_INIT 1023 // highest value used in top half of ramp +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +// linear channel +#define CH1_PIN PB3 // pin 16, Opamp reference +#define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 +#define CH1_ENABLE_PIN PB0 // pin 19, Opamp power +#define CH1_ENABLE_PORT PORTB // control port for PB0 + +// e-switch +#define SWITCH_PIN PA7 // pin 20 +#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt +#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] +#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] +#define SWITCH_PORT PINA // PINA or PINB or PINC +#define SWITCH_PUE PUEA // pullup group A +#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] + + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 +// pin to ADC mappings are in DS table 19-4 +#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 +// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 +#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D +// DS tables 19-3, 19-4 +// Bit 7 6 5 4 3 2 1 0 +// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 +// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 +// divided by ... +// REFS[1:0] = 1, 0 for internal 1.1V reference +// other bits reserved +#define ADMUX_VOLTAGE_DIVIDER 0b10000110 +#define ADC_PRSCL 0x07 // clk/128 + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// D1, R1, R2 = 0, 330, 100 +#ifndef ADC_44 +//#define ADC_44 981 // raw value at 4.40V +#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 +#endif +#ifndef ADC_22 +//#define ADC_22 489 // raw value at 2.20V +#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 +#endif + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + + +inline void hwdef_setup() { + // enable output ports + // Opamp level and Opamp on/off + DDRB = (1 << CH1_PIN) + | (1 << CH1_ENABLE_PIN); + // aux R/G/B + DDRA = (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + ; + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // WGM1[3:0]: 0,0,1,1: PWM, Phase Correct, 10-bit (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 0,0: PWM OC1B disabled (DS table 12-4) + TCCR1A = (1< - -#define PWM_CHANNELS 2 // override this for the no-FET version -#define PWM_BITS 16 // data type needs 16 bits, not 8 -#define PWM_TOP 255 // highest value used in top half of ramp -#define USE_DYN_PWM // dynamic frequency and speed - -#define SWITCH_PIN PB2 // pin 17 -#define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt -#define SWITCH_PCIE PCIE1 // PCIE1 is for PCINT[11:8] -#define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] -#define SWITCH_PORT PINB // PINA or PINB or PINC -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] - -#define PWM1_PIN PB3 // pin 16, Opamp reference -#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 -#define PWM1_CNT TCNT1 // for dynamic PWM, reset phase -#define PWM1_PHASE_RESET_OFF // force reset while shutting off -#define PWM1_PHASE_RESET_ON // force reset while turning on -#define PWM1_PHASE_SYNC // manual sync while changing level - -#define PWM2_PIN PA6 // pin 1, DD FET PWM -#define PWM2_LVL OCR1B // OCR1B is the output compare register for PA6 - -// PWM parameters of both channels are tied together because they share a counter -#define PWM1_TOP ICR1 // holds the TOP value for for variable-resolution PWM - -#define LED_ENABLE_PIN PB0 // pin 19, Opamp power -#define LED_ENABLE_PORT PORTB // control port for PB0 - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -#define BUTTON_LED_PIN PA2 // pin 5 -#define BUTTON_LED_PORT PORTA // for all "PA" pins -#define BUTTON_LED_DDR DDRA // for all "PA" pins -#define BUTTON_LED_PUE PUEA // for all "PA" pins - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - // enable output ports - // Opamp level and Opamp on/off - DDRB = (1 << PWM1_PIN) - | (1 << LED_ENABLE_PIN); - // DD FET PWM, aux R/G/B, button LED - DDRA = (1 << PWM2_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - | (1 << BUTTON_LED_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) - TCCR1A = (1< - -#define PWM_CHANNELS 2 // override this for the no-FET version -#define PWM_BITS 16 // data type needs 16 bits, not 8 -#define PWM_TOP 255 // highest value used in top half of ramp -#define USE_DYN_PWM // dynamic frequency and speed - -#define SWITCH_PIN PA7 // pin 20 -#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt -#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] -#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] -#define SWITCH_PORT PINA // PINA or PINB or PINC - -#define PWM1_PIN PB3 // pin 16, Opamp reference -#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 -#define PWM1_CNT TCNT1 // for dynamic PWM, reset phase -#define PWM1_PHASE_RESET_OFF // force reset while shutting off -#define PWM1_PHASE_RESET_ON // force reset while turning on -#define PWM1_PHASE_SYNC // manual sync while changing level - -#define PWM2_PIN PA6 // pin 1, DD FET PWM -#define PWM2_LVL OCR1B // OCR1B is the output compare register for PA6 - -// PWM parameters of both channels are tied together because they share a counter -#define PWM1_TOP ICR1 // holds the TOP value for for variable-resolution PWM - -#define LED_ENABLE_PIN PB0 // pin 19, Opamp power -#define LED_ENABLE_PORT PORTB // control port for PB0 - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -#define BUTTON_LED_PIN PA2 // pin 5 -#define BUTTON_LED_PORT PORTA // for all "PA" pins -#define BUTTON_LED_DDR DDRA // for all "PA" pins -#define BUTTON_LED_PUE PUEA // for all "PA" pins - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - // enable output ports - // Opamp level and Opamp on/off - DDRB = (1 << PWM1_PIN) - | (1 << LED_ENABLE_PIN); - // DD FET PWM, aux R/G/B, button LED - DDRA = (1 << PWM2_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - | (1 << BUTTON_LED_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) - TCCR1A = (1< + +#ifndef HWDEF_C_FILE +#define HWDEF_C_FILE hwdef-noctigon-kr4.c +#endif + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +// channel modes: +// * 0. linear + DD FET stacked +// * 1+. aux RGB +#define NUM_CHANNEL_MODES (1 + NUM_RGB_AUX_CHANNEL_MODES) +enum CHANNEL_MODES { + CM_MAIN = 0, + RGB_AUX_ENUMS +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 +// no args +//#define USE_CHANNEL_MODE_ARGS +//#define CHANNEL_MODE_ARGS 0,0,0,0,0,0,0,0 + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // linear ramp +#define PWM2_DATATYPE uint8_t // DD FET ramp + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP ICR1 // holds the TOP value for variable-resolution PWM +#define PWM_TOP_INIT 255 // highest value used in top half of ramp +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +// linear channel +#define CH1_PIN PB3 // pin 16, Opamp reference +#define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 +#define CH1_ENABLE_PIN PB0 // pin 19, Opamp power +#define CH1_ENABLE_PORT PORTB // control port for PB0 + +// DD FET channel +#define CH2_PIN PA6 // pin 1, DD FET PWM +#define CH2_PWM OCR1B // OCR1B is the output compare register for PA6 + +// e-switch +#define SWITCH_PIN PA7 // pin 20 +#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt +#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] +#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] +#define SWITCH_PORT PINA // PINA or PINB or PINC +#define SWITCH_PUE PUEA // pullup group A +#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] + + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 +// pin to ADC mappings are in DS table 19-4 +#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 +// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 +#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D +// DS tables 19-3, 19-4 +// Bit 7 6 5 4 3 2 1 0 +// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 +// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 +// divided by ... +// REFS[1:0] = 1, 0 for internal 1.1V reference +// other bits reserved +#define ADMUX_VOLTAGE_DIVIDER 0b10000110 +#define ADC_PRSCL 0x07 // clk/128 + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// D1, R1, R2 = 0, 330, 100 +#ifndef ADC_44 +//#define ADC_44 981 // raw value at 4.40V +#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 +#endif +#ifndef ADC_22 +//#define ADC_22 489 // raw value at 2.20V +#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 +#endif + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + +#define BUTTON_LED_PIN PA2 // pin 5 +#define BUTTON_LED_PORT PORTA // for all "PA" pins +#define BUTTON_LED_DDR DDRA // for all "PA" pins +#define BUTTON_LED_PUE PUEA // for all "PA" pins + +inline void hwdef_setup() { + // enable output ports + // Opamp level and Opamp on/off + DDRB = (1 << CH1_PIN) + | (1 << CH1_ENABLE_PIN); + // DD FET PWM, aux R/G/B, button LED + DDRA = (1 << CH2_PIN) + | (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + | (1 << BUTTON_LED_PIN) + ; + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) + TCCR1A = (1< end of dynamic PWM range #define HALFSPEED_LEVEL 12 #define QUARTERSPEED_LEVEL 4 @@ -39,18 +40,24 @@ // stop panicking at ~70% power or ~600 lm #define THERM_FASTER_LEVEL 130 -#define MIN_THERM_STEPDOWN 80 // must be > end of dynamic PWM range #define THERM_CAL_OFFSET 5 -//#define THERM_RESPONSE_MAGNITUDE 32 // smaller adjustments, this host changes temperature slowly -//#define THERM_NEXT_WARNING_THRESHOLD 32 // more error tolerance before adjusting +// the power regulator seems to "jump start" the LEDs all on its own, +// so the firmware doesn't have to +// (and unfortunately the power regulator jumps it a bit too hard) +#define DEFAULT_JUMP_START_LEVEL 1 +#define BLINK_BRIGHTNESS 50 +#define BLINK_ONCE_TIME 12 // show each channel while it scroll by in the menu #define USE_CONFIG_COLORS -// blink numbers on the aux LEDs by default -#define DEFAULT_BLINK_CHANNEL CM_AUXWHT +// blink numbers on the main LEDs by default (but allow user to change it) +#define DEFAULT_BLINK_CHANNEL CM_MAIN + +// slow down party strobe; this driver can't pulse for 2ms or less +#define PARTY_STROBE_ONTIME 3 // use aux red + aux blue for police strobe #define USE_POLICE_COLOR_STROBE_MODE @@ -61,21 +68,11 @@ // the default of 26 looks a bit rough, so increase it to make it smoother #define CANDLE_AMPLITUDE 33 -// slow down party strobe; this driver can't pulse for 2ms or less -#define PARTY_STROBE_ONTIME 3 - -// the power regulator seems to "jump start" the LEDs all on its own, -// so the firmware doesn't have to -// (and unfortunately the power regulator jumps it a bit too hard) -#define DEFAULT_JUMP_START_LEVEL 1 -#define BLINK_BRIGHTNESS 50 -#define BLINK_ONCE_TIME 12 - -// added for convenience -#define USE_SOFT_FACTORY_RESET - -// don't blink halfway up +// don't blink while ramping #ifdef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_MIDDLE #endif +// added for convenience +#define USE_SOFT_FACTORY_RESET + diff --git a/spaghetti-monster/anduril/cfg-noctigon-dm11-nofet.h b/spaghetti-monster/anduril/cfg-noctigon-dm11-nofet.h index ad71fa9..b2fdfdb 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-dm11-nofet.h +++ b/spaghetti-monster/anduril/cfg-noctigon-dm11-nofet.h @@ -1,8 +1,10 @@ -// Noctigon DM11-noFET config options for Anduril +// Noctigon DM11 (no DD FET) config options for Anduril // Copyright (C) 2021-2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once +// same support functions as a KR4 +#define HWDEF_C_FILE hwdef-noctigon-kr4-nofet.c #include "cfg-noctigon-dm11.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0272" @@ -11,6 +13,7 @@ // turn off the DD FET #undef PWM_CHANNELS #define PWM_CHANNELS 1 +#define RAMP_SIZE 150 // level_calc.py 5.01 1 149 7135 1 0.3 1740 --pwm dyn:78:16384:255 #undef PWM1_LEVELS diff --git a/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h b/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h index 94c9a52..9fac446 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h +++ b/spaghetti-monster/anduril/cfg-noctigon-dm11-sbt90.h @@ -3,9 +3,9 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once +#include "cfg-noctigon-kr4.h" +#undef MODEL_NUMBER #define MODEL_NUMBER "0274" -#include "hwdef-Noctigon_DM11-SBT90.h" -#include "hank-cfg.h" // ATTINY: 1634 // this light has three aux LED channels: R, G, B @@ -17,62 +17,30 @@ #undef USE_INDICATOR_LED_WHILE_RAMPING #endif - // power channels: // - linear: 5A? // - FET: DD -#define RAMP_LENGTH 150 -#define USE_DYN_PWM - -// maxreg at 130, dynamic PWM: level_calc.py 5.01 2 149 7135 1 0.3 1740 FET 1 10 3190 --pwm dyn:64:16384:255 -// (plus one extra level at the beginning for moon) -#define PWM1_LEVELS 0,1,1,2,2,3,4,5,6,7,8,9,11,12,14,16,17,19,22,24,26,29,31,34,37,40,43,46,49,53,56,60,63,67,71,74,78,82,86,89,93,96,99,103,105,108,110,112,114,115,116,116,115,114,112,109,106,101,95,89,81,71,60,48,34,19,20,21,22,23,24,26,27,28,30,31,32,34,36,37,39,41,43,45,47,49,51,53,56,58,61,63,66,69,72,75,78,81,84,88,91,95,99,103,107,111,115,119,124,129,133,138,143,149,154,159,165,171,177,183,189,196,203,210,217,224,231,239,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,20,30,41,52,63,75,87,99,112,125,138,151,165,179,194,208,224,239,255 -#define PWM_TOPS 16383,16383,11750,14690,9183,12439,13615,13955,13877,13560,13093,12529,13291,12513,12756,12769,11893,11747,12085,11725,11329,11316,10851,10713,10518,10282,10016,9729,9428,9298,8971,8794,8459,8257,8043,7715,7497,7275,7052,6753,6538,6260,5994,5798,5501,5271,5006,4758,4525,4268,4030,3775,3508,3263,3010,2752,2517,2256,1998,1763,1512,1249,994,749,497,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#undef DEFAULT_LEVEL #define DEFAULT_LEVEL 70 -#define MAX_1x7135 130 -#define HALFSPEED_LEVEL 12 -#define QUARTERSPEED_LEVEL 4 - -// don't blink halfway up -#ifdef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_MIDDLE -#endif +#undef RAMP_SMOOTH_FLOOR #define RAMP_SMOOTH_FLOOR 10 // low levels may be unreliable -#define RAMP_SMOOTH_CEIL 130 // 10, 30, 50, [70], 90, 110, 130 +#undef RAMP_DISCRETE_FLOOR #define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 7 // safe limit ~75% power -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR +#undef SIMPLE_UI_CEIL #define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL -#define SIMPLE_UI_STEPS 5 - -// make candle mode wobble more -#define CANDLE_AMPLITUDE 30 // stop panicking at ~70% power or ~600 lm +#undef THERM_FASTER_LEVEL #define THERM_FASTER_LEVEL 130 -#define MIN_THERM_STEPDOWN 66 // must be > end of dynamic PWM range - -//#define THERM_RESPONSE_MAGNITUDE 32 // smaller adjustments, this host changes temperature slowly -//#define THERM_NEXT_WARNING_THRESHOLD 32 // more error tolerance before adjusting - -// slow down party strobe; this driver can't pulse for 1ms or less -// (only needed on no-FET build) -//#define PARTY_STROBE_ONTIME 2 -#define THERM_CAL_OFFSET 5 - -// the power regulator is a bit slow, so push it harder for a quick response from off -#define DEFAULT_JUMP_START_LEVEL 21 +#undef BLINK_BRIGHTNESS #define BLINK_BRIGHTNESS 50 -#define BLINK_ONCE_TIME 12 -// added for convenience -#define USE_SOFT_FACTORY_RESET +#undef CANDLE_AMPLITUDE +#define CANDLE_AMPLITUDE 30 diff --git a/spaghetti-monster/anduril/cfg-noctigon-dm11.h b/spaghetti-monster/anduril/cfg-noctigon-dm11.h index 5f3cb80..cd6bc9d 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-dm11.h +++ b/spaghetti-monster/anduril/cfg-noctigon-dm11.h @@ -4,7 +4,7 @@ #pragma once #define MODEL_NUMBER "0271" -#include "hwdef-Noctigon_DM11.h" +#include "hwdef-noctigon-dm11.h" #include "hank-cfg.h" // ATTINY: 1634 @@ -17,29 +17,24 @@ #undef USE_INDICATOR_LED_WHILE_RAMPING #endif +#define RAMP_SIZE 150 // power channels: // - linear: 5A? // - FET: DD -#define RAMP_LENGTH 150 -#define USE_DYN_PWM // maxreg at 130, dynamic PWM: level_calc.py 5.01 2 149 7135 1 0.3 1740 FET 1 10 3190 --pwm dyn:64:16384:255 // (plus one extra level at the beginning for moon) -#define PWM1_LEVELS 0,1,1,2,2,3,4,5,6,7,8,9,11,12,14,16,17,19,22,24,26,29,31,34,37,40,43,46,49,53,56,60,63,67,71,74,78,82,86,89,93,96,99,103,105,108,110,112,114,115,116,116,115,114,112,109,106,101,95,89,81,71,60,48,34,19,20,21,22,23,24,26,27,28,30,31,32,34,36,37,39,41,43,45,47,49,51,53,56,58,61,63,66,69,72,75,78,81,84,88,91,95,99,103,107,111,115,119,124,129,133,138,143,149,154,159,165,171,177,183,189,196,203,210,217,224,231,239,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,20,30,41,52,63,75,87,99,112,125,138,151,165,179,194,208,224,239,255 -#define PWM_TOPS 16383,16383,11750,14690,9183,12439,13615,13955,13877,13560,13093,12529,13291,12513,12756,12769,11893,11747,12085,11725,11329,11316,10851,10713,10518,10282,10016,9729,9428,9298,8971,8794,8459,8257,8043,7715,7497,7275,7052,6753,6538,6260,5994,5798,5501,5271,5006,4758,4525,4268,4030,3775,3508,3263,3010,2752,2517,2256,1998,1763,1512,1249,994,749,497,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#define PWM1_LEVELS 0,1,1,2,2,3,4,5,6,7,8,9,11,12,14,16,17,19,22,24,26,29,31,34,37,40,43,46,49,53,56,60,63,67,71,74,78,82,86,89,93,96,99,103,105,108,110,112,114,115,116,116,115,114,112,109,106,101,95,89,81,71,60,48,34,19,20,21,22,23,24,26,27,28,30,31,32,34,36,37,39,41,43,45,47,49,51,53,56,58,61,63,66,69,72,75,78,81,84,88,91,95,99,103,107,111,115,119,124,129,133,138,143,149,154,159,165,171,177,183,189,196,203,210,217,224,231,239,247,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,20,30,41,52,63,75,87,99,112,125,138,151,165,179,194,208,224,239,255 +#define PWM_TOPS 16383,16383,11750,14690,9183,12439,13615,13955,13877,13560,13093,12529,13291,12513,12756,12769,11893,11747,12085,11725,11329,11316,10851,10713,10518,10282,10016,9729,9428,9298,8971,8794,8459,8257,8043,7715,7497,7275,7052,6753,6538,6260,5994,5798,5501,5271,5006,4758,4525,4268,4030,3775,3508,3263,3010,2752,2517,2256,1998,1763,1512,1249,994,749,497,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#define MIN_THERM_STEPDOWN 66 // should be above highest dyn_pwm level -#define DEFAULT_LEVEL 70 #define MAX_1x7135 130 +#define DEFAULT_LEVEL 70 #define HALFSPEED_LEVEL 12 #define QUARTERSPEED_LEVEL 4 -// don't blink halfway up -#ifdef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_MIDDLE -#endif - #define RAMP_SMOOTH_FLOOR 10 // low levels may be unreliable #define RAMP_SMOOTH_CEIL 130 // 10, 30, 50, [70], 90, 110, 130 @@ -52,27 +47,42 @@ #define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL #define SIMPLE_UI_STEPS 5 -// make candle mode wobble more -#define CANDLE_AMPLITUDE 30 - // stop panicking at ~70% power or ~600 lm #define THERM_FASTER_LEVEL 130 -#define MIN_THERM_STEPDOWN 66 // must be > end of dynamic PWM range - -//#define THERM_RESPONSE_MAGNITUDE 32 // smaller adjustments, this host changes temperature slowly -//#define THERM_NEXT_WARNING_THRESHOLD 32 // more error tolerance before adjusting - -// slow down party strobe; this driver can't pulse for 1ms or less -// (only needed on no-FET build) -//#define PARTY_STROBE_ONTIME 2 #define THERM_CAL_OFFSET 5 + // the power regulator is a bit slow, so push it harder for a quick response from off #define DEFAULT_JUMP_START_LEVEL 21 #define BLINK_BRIGHTNESS 50 #define BLINK_ONCE_TIME 12 +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// there is usually no lighted button, so +// blink numbers on the main LEDs by default (but allow user to change it) +#define DEFAULT_BLINK_CHANNEL CM_MAIN + +// slow down party strobe; this driver can't pulse for 1ms or less +// (only needed on no-FET build) +//#define PARTY_STROBE_ONTIME 2 + +// use aux red + aux blue for police strobe +#define USE_POLICE_COLOR_STROBE_MODE +#define POLICE_STROBE_USES_AUX +#define POLICE_COLOR_STROBE_CH1 CM_AUXRED +#define POLICE_COLOR_STROBE_CH2 CM_AUXBLU + +// make candle mode wobble more +#define CANDLE_AMPLITUDE 30 + +// don't blink while ramping +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + // added for convenience #define USE_SOFT_FACTORY_RESET diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4.h b/spaghetti-monster/anduril/cfg-noctigon-kr4.h index 7a8ea5a..5b24ef5 100644 --- a/spaghetti-monster/anduril/cfg-noctigon-kr4.h +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4.h @@ -33,7 +33,6 @@ #define MAX_1x7135 130 #define DEFAULT_LEVEL 50 -//#define MIN_THERM_STEPDOWN 66 // should be above highest dyn_pwm level #define HALFSPEED_LEVEL 12 #define QUARTERSPEED_LEVEL 4 @@ -63,8 +62,8 @@ // show each channel while it scroll by in the menu #define USE_CONFIG_COLORS -// there is usually no lighted button, -// so blink numbers on the main LEDs by default (but allow user to change it) +// there is usually no lighted button, so +// blink numbers on the main LEDs by default (but allow user to change it) #define DEFAULT_BLINK_CHANNEL CM_MAIN // slow down party strobe; this driver can't pulse for 1ms or less -- cgit v1.2.3 From 9f5be1da4a3f01c4891f1f1b1372a603638da37b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 23 Jul 2023 12:04:56 -0600 Subject: converted BLF GT to multi-channel --- hwdef-BLF_GT.h | 61 -------------------- hwdef-blf-gt.h | 102 +++++++++++++++++++++++++++++++++ hwdef-emisar-d4.h | 4 +- spaghetti-monster/anduril/cfg-blf-gt.h | 28 ++++++--- 4 files changed, 123 insertions(+), 72 deletions(-) delete mode 100644 hwdef-BLF_GT.h create mode 100644 hwdef-blf-gt.h diff --git a/hwdef-BLF_GT.h b/hwdef-BLF_GT.h deleted file mode 100644 index 94d510c..0000000 --- a/hwdef-BLF_GT.h +++ /dev/null @@ -1,61 +0,0 @@ -// BLF GT driver layout -// Copyright (C) 2018-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * ---- - * Reset -|1 8|- VCC (unused) - * eswitch -|2 7|- Voltage divider - * AUX LED -|3 6|- Current control (buck level) - * GND -|4 5|- PWM (buck output on/off) - * ---- - */ - -#define PWM_CHANNELS 2 - -#ifndef AUXLED_PIN -#define AUXLED_PIN PB4 // pin 3 -#endif - -#ifndef SWITCH_PIN -#define SWITCH_PIN PB3 // pin 2 -#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt -#endif - -#ifndef PWM1_PIN -#define PWM1_PIN PB0 // pin 5, 1x7135 PWM -#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 -#endif -#ifndef PWM2_PIN -#define PWM2_PIN PB1 // pin 6, FET PWM -#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 -#endif - -#define USE_VOLTAGE_DIVIDER // use a voltage divider on pin 7, not VCC -#ifndef VOLTAGE_PIN -#define VOLTAGE_PIN PB2 // pin 7, voltage ADC -#define VOLTAGE_CHANNEL 0x01 // MUX 01 corresponds with PB2 -#define VOLTAGE_ADC ADC1D // Digital input disable bit corresponding with PB2 -// inherited from tk-attiny.h -//#define VOLTAGE_ADC_DIDR DIDR0 // DIDR for ADC1 -// 1.1V reference, left-adjust, ADC1/PB2 -//#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | (1 << ADLAR) | VOLTAGE_CHANNEL) -// 1.1V reference, no left-adjust, ADC1/PB2 -#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | VOLTAGE_CHANNEL) -#endif -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V (in-between, we assume values form a straight line) -#ifndef ADC_44 -#define ADC_44 (184*4) -#endif -#ifndef ADC_22 -#define ADC_22 (92*4) -#endif - -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels - -#define LAYOUT_DEFINED - diff --git a/hwdef-blf-gt.h b/hwdef-blf-gt.h new file mode 100644 index 0000000..fdb0cb6 --- /dev/null +++ b/hwdef-blf-gt.h @@ -0,0 +1,102 @@ +// BLF GT driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * ---- + * Reset -|1 8|- VCC (unused) + * eswitch -|2 7|- Voltage divider + * AUX LED -|3 6|- Current control (buck level) + * GND -|4 5|- PWM (buck output on/off) + * ---- + * + * On high modes, the buck regulator's current level is adjusted by pin 6. + * On low modes, the buck is set to ~10% power + * and its output gets PWM'd by pin 5. + */ + +#define ATTINY 85 +#include + +#define HWDEF_C_FILE hwdef-emisar-d4.c + +// channel modes +// * 0. main LEDs +#define NUM_CHANNEL_MODES 1 +enum CHANNEL_MODES { + CM_MAIN = 0, +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00000001 + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 8 // attiny85 only supports up to 8 bits +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define PWM_DATATYPE2 uint16_t +#define PWM1_DATATYPE uint8_t // low modes (PWM with buck at 10% power) +#define PWM2_DATATYPE uint8_t // high modes (adjustable constant current) + +#define PWM_TOP_INIT 255 // highest value used in top half of ramp + +// low modes (PWM turns regulator on/off) +#define CH1_PIN PB0 // pin 5 +#define CH1_PWM OCR0A // OCR0A is the output compare register for PB0 + +// high modes (control voltage sets regulator's level) +#define CH2_PIN PB1 // pin 6 +#define CH2_PWM OCR0B // OCR0B is the output compare register for PB1 + +#define AUXLED_PIN PB4 // pin 3 + +// e-switch +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt + +// VCC is regulated, so measure battery on pin 7 instead +#define USE_VOLTAGE_DIVIDER // use a voltage divider on pin 7, not VCC +#define VOLTAGE_PIN PB2 // pin 7, voltage ADC +#define VOLTAGE_CHANNEL 0x01 // MUX 01 corresponds with PB2 +#define VOLTAGE_ADC ADC1D // Digital input disable bit corresponding with PB2 +// inherited from tk-attiny.h +//#define VOLTAGE_ADC_DIDR DIDR0 // DIDR for ADC1 +// 1.1V reference, left-adjust, ADC1/PB2 +//#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | (1 << ADLAR) | VOLTAGE_CHANNEL) +// 1.1V reference, no left-adjust, ADC1/PB2 +#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | VOLTAGE_CHANNEL) +#define ADC_PRSCL 0x07 // clk/128 + +// Raw ADC readings at 4.4V and 2.2V (in-between, we assume values form a straight line) +#ifndef ADC_44 +#define ADC_44 (184*4) +#endif +#ifndef ADC_22 +#define ADC_22 (92*4) +#endif + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + + +inline void hwdef_setup() { + // configure PWM channels + DDRB = (1 << CH1_PIN) + | (1 << CH2_PIN); + + TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) + TCCR0A = PHASE; + + // configure e-switch + PORTB = (1 << SWITCH_PIN); // e-switch is the only input + PCMSK = (1 << SWITCH_PIN); // pin change interrupt uses this pin +} + + +#define LAYOUT_DEFINED + diff --git a/hwdef-emisar-d4.h b/hwdef-emisar-d4.h index b3a7500..7be700a 100644 --- a/hwdef-emisar-d4.h +++ b/hwdef-emisar-d4.h @@ -51,8 +51,6 @@ enum CHANNEL_MODES { #define PWM_TOP_INIT 255 // highest value used in top half of ramp -//#define AUXLED_PIN PB4 // pin 3 - // 1x7135 channel #ifndef CH1_PIN #define CH1_PIN PB0 // pin 5, 1x7135 PWM @@ -65,6 +63,8 @@ enum CHANNEL_MODES { #define CH2_PWM OCR0B // OCR0B is the output compare register for PB1 #endif +//#define AUXLED_PIN PB4 // pin 3 + // e-switch #ifndef SWITCH_PIN #define SWITCH_PIN PB3 // pin 2 diff --git a/spaghetti-monster/anduril/cfg-blf-gt.h b/spaghetti-monster/anduril/cfg-blf-gt.h index 425ecdc..580318a 100644 --- a/spaghetti-monster/anduril/cfg-blf-gt.h +++ b/spaghetti-monster/anduril/cfg-blf-gt.h @@ -4,21 +4,16 @@ #pragma once #define MODEL_NUMBER "0321" -#include "hwdef-BLF_GT.h" +#include "hwdef-blf-gt.h" +// ATTINY: 85 // the button lights up #define USE_INDICATOR_LED // the button is visible while main LEDs are on #define USE_INDICATOR_LED_WHILE_RAMPING -// don't blink during ramp, it's irrelevant and annoying on this light -#undef BLINK_AT_RAMP_CEIL -#undef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_FLOOR +#define RAMP_SIZE 150 -//#undef USE_SET_LEVEL_GRADUALLY - -#define RAMP_LENGTH 150 // First 60 values: level_calc.py 1 60 7135 4 5.0 255 // Remainder: all 255 (buck driver at 100% duty cycle) #define PWM1_LEVELS 4,5,6,6,7,8,9,11,12,13,15,16,18,19,21,23,25,27,30,32,34,37,40,43,46,49,52,55,59,63,66,70,75,79,83,88,93,98,103,108,114,119,125,131,137,144,150,157,164,171,179,186,194,202,210,219,228,236,246,255, \ @@ -29,6 +24,7 @@ 26,27,28,29,30,31,32,33,35,36,37,38,40,41,42,44,45,47,48,50,51,53,54,56,58,59,61,63,65,67,69,70,72,74,76,79,81,83,85,87,89,92,94,96,99,101,104,106,109,112,114,117,120,123,125,128,131,134,137,140,143,147,150,153,156,160,163,167,170,174,177,181,184,188,192,196,200,204,208,212,216,220,224,228,233,237,241,246,250,255 #define POWER_80PX 138 // 2.0 Amps out of maximum 2.5 Amps #define MAX_1x7135 60 // where it switches from PWM to current control +#define DEFAULT_LEVEL 69 // nice #define HALFSPEED_LEVEL 17 #define QUARTERSPEED_LEVEL 6 @@ -36,6 +32,7 @@ // start both ramps at the bottom; even moon throws a long way on the GT #define RAMP_SMOOTH_FLOOR 1 #define RAMP_SMOOTH_CEIL POWER_80PX +// 1 23 46 [69] 92 115 138 #define RAMP_DISCRETE_FLOOR 1 #define RAMP_DISCRETE_CEIL POWER_80PX #define RAMP_DISCRETE_STEPS 7 @@ -45,8 +42,21 @@ #define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL #define SIMPLE_UI_STEPS 5 +// smoother, more wobbly candle +#define CANDLE_AMPLITUDE 33 + +// turbo (i.e. "giggles" mode), low, tactical strobe +#define TACTICAL_LEVELS 150,30,(RAMP_SIZE+2) + // stop panicking at 80% power, this light has plenty of thermal mass #define THERM_FASTER_LEVEL POWER_80PX // throttle back faster when high +// don't blink during ramp, it's irrelevant and annoying on this light +#undef BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_FLOOR + // too big, turn off extra features -#undef USE_TACTICAL_MODE +//#undef USE_TACTICAL_MODE +#undef USE_SOS_MODE + -- cgit v1.2.3 From bcaa751aa1b29cb3b4c76df2075feb1941d043fe Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 3 Aug 2023 19:15:34 -0600 Subject: converted all K9.3 builds and D4Sv2-tintramp-fet (now emisar-2ch-fet) to multi-channel, and removed old K9.3 builds which aren't relevant any more, and old D4Sv2-tintramp builds --- hwdef-Emisar_D4Sv2-tintramp.h | 189 ------------------ hwdef-Noctigon_K9.3.h | 164 --------------- hwdef-emisar-2ch-fet.c | 220 +++++++++++++++++++++ hwdef-emisar-2ch-fet.h | 209 ++++++++++++++++++++ hwdef-emisar-2ch.h | 28 ++- spaghetti-monster/anduril/MODELS | 10 +- spaghetti-monster/anduril/cfg-emisar-2ch-fet.h | 113 +++++++++++ spaghetti-monster/anduril/cfg-emisar-2ch.h | 30 ++- spaghetti-monster/anduril/cfg-noctigon-k9.3-219.h | 9 +- .../anduril/cfg-noctigon-k9.3-nofet.h | 52 +---- .../anduril/cfg-noctigon-k9.3-tintramp-219.h | 14 -- .../anduril/cfg-noctigon-k9.3-tintramp-fet.h | 67 ------- .../anduril/cfg-noctigon-k9.3-tintramp-nofet.h | 85 -------- spaghetti-monster/anduril/cfg-noctigon-k9.3.h | 107 ++++++---- spaghetti-monster/fsm-ramping.h | 6 + 15 files changed, 656 insertions(+), 647 deletions(-) delete mode 100644 hwdef-Emisar_D4Sv2-tintramp.h delete mode 100644 hwdef-Noctigon_K9.3.h create mode 100644 hwdef-emisar-2ch-fet.c create mode 100644 hwdef-emisar-2ch-fet.h create mode 100644 spaghetti-monster/anduril/cfg-emisar-2ch-fet.h delete mode 100644 spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-219.h delete mode 100644 spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-fet.h delete mode 100644 spaghetti-monster/anduril/cfg-noctigon-k9.3-tintramp-nofet.h diff --git a/hwdef-Emisar_D4Sv2-tintramp.h b/hwdef-Emisar_D4Sv2-tintramp.h deleted file mode 100644 index 2709bc4..0000000 --- a/hwdef-Emisar_D4Sv2-tintramp.h +++ /dev/null @@ -1,189 +0,0 @@ -// Emisar D4Sv2 w/ tint ramping -// Copyright (C) 2021-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * (based on the Noctigon K9.3 driver layout (attiny1634)) - * - * Pin / Name / Function - * 1 PA6 2nd LED PWM (linear) (PWM1B) - * 2 PA5 R: red aux LED (PWM0B) - * 3 PA4 G: green aux LED - * 4 PA3 B: blue aux LED - * 5 PA2 button LED - * 6 PA1 Opamp 2 enable (2nd LEDs) - * 7 PA0 Opamp 1 enable (main LEDs) - * 8 GND GND - * 9 VCC VCC - * 10 PC5 (none) - * 11 PC4 (none) - * 12 PC3 RESET - * 13 PC2 (none) - * 14 PC1 SCK - * 15 PC0 main LED PWM (FET) (PWM0A) (unused on some models because tint ramping) - * 16 PB3 main LED PWM (linear) (PWM1A) - * 17 PB2 MISO - * 18 PB1 MOSI / battery voltage (ADC6) - * 19 PB0 (none) - * 20 PA7 e-switch (PCINT7) - * ADC12 thermal sensor - * - * Main LED power uses one pin to turn the Opamp on/off, - * and one pin to control Opamp power level. - * Main brightness control uses the power level pin, with 4 kHz 10-bit PWM. - * The on/off pin is only used to turn the main LED on and off, - * not to change brightness. - */ - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1634 -#include - -#define PWM_CHANNELS 1 // 1 virtual channel (1 for main LEDs + 1 for 2nd LEDs) -#define PWM_BITS 14 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz -#define PWM_TOP 511 -// dynamic PWM with tint ramping -#define USE_DYN_PWM // dynamic frequency and speed -#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 - -#ifndef SWITCH_PIN -#define SWITCH_PIN PA7 // pin 20 -#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt -#define SWITCH_PCIE PCIE0 // PCIE1 is for PCINT[7:0] -#define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] -#define SWITCH_PORT PINA // PINA or PINB or PINC -#define SWITCH_PUE PUEA // pullup group A -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] -#endif - -// usually PWM1_LVL would be a hardware register, but we need to abstract -// it out to a soft brightness value, in order to handle tint ramping -// (this allows smooth thermal regulation to work, and makes things -// otherwise simpler and easier) -uint16_t PWM1_LVL; -#define PWM1_PIN PB3 // pin 16, Opamp reference -#define TINT1_LVL OCR1A // OCR1A is the output compare register for PB3 -#define PWM1_CNT TCNT1 // for dynamic PWM, reset phase -#define PWM1_PHASE_RESET_OFF // force reset while shutting off -#define PWM1_PHASE_RESET_ON // force reset while turning on -#define PWM1_PHASE_SYNC // manual sync while changing level - -// gah, this driver is weird... -// two linear channels are treated as one, -// while there's also a FET on one channel for turbo on half the LEDs -// so the FET needs to be "PWM2" but the second linear is "TINT2" -#define PWM3_PIN PA6 // pin 1, 2nd LED Opamp reference -#define TINT2_LVL OCR1B // OCR1B is the output compare register for PA6 - -#define PWM2_PIN PC0 // pin 15, DD FET PWM -#define PWM2_LVL OCR0A // OCR0A is the output compare register for PC0 - -// PWM parameters of both channels are tied together because they share a counter -#define PWM1_TOP ICR1 // holds the TOP value for for variable-resolution PWM - -#define LED_ENABLE_PIN PA0 // pin 7, Opamp power -#define LED_ENABLE_PORT PORTA // control port for PA0 - -#define LED2_ENABLE_PIN PA1 // pin 6, Opamp power -#define LED2_ENABLE_PORT PORTA // control port for PA1 - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -#define BUTTON_LED_PIN PA2 // pin 5 -#define BUTTON_LED_PORT PORTA // for all "PA" pins -#define BUTTON_LED_DDR DDRA // for all "PA" pins -#define BUTTON_LED_PUE PUEA // for all "PA" pins - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - // enable output ports - DDRC = (1 << PWM2_PIN); - DDRB = (1 << PWM1_PIN); - DDRA = (1 << PWM3_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - | (1 << BUTTON_LED_PIN) - | (1 << LED_ENABLE_PIN) - | (1 << LED2_ENABLE_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // Linear opamp PWM for both main and 2nd LEDs (10-bit) - // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) - TCCR1A = (1< - -#define PWM_CHANNELS 3 // 2 for main LEDs, 1 for 2nd LEDs -#define PWM_BITS 10 // 0 to 1023 at 4 kHz, not 0 to 255 at 16 kHz -#define PWM_TOP 1023 - -#define SWITCH_PIN PA7 // pin 20 -#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt -#define SWITCH_PCIE PCIE0 // PCIE1 is for PCINT[7:0] -#define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] -#define SWITCH_PORT PINA // PINA or PINB or PINC -#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] - -#define PWM1_PIN PB3 // pin 16, Opamp reference -#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 - -#define PWM2_PIN PC0 // pin 15, DD FET PWM -#define PWM2_LVL OCR0A // OCR0A is the output compare register for PC0 - -#define PWM3_PIN PA6 // pin 1, 2nd LED Opamp reference -#define PWM3_LVL OCR1B // OCR1B is the output compare register for PA6 - -#define LED_ENABLE_PIN PA0 // pin 7, Opamp power -#define LED_ENABLE_PORT PORTA // control port for PA0 - -#define LED2_ENABLE_PIN PA1 // pin 6, Opamp power -#define LED2_ENABLE_PORT PORTA // control port for PA1 - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -#define BUTTON_LED_PIN PA2 // pin 5 -#define BUTTON_LED_PORT PORTA // for all "PA" pins -#define BUTTON_LED_DDR DDRA // for all "PA" pins -#define BUTTON_LED_PUE PUEA // for all "PA" pins - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - // enable output ports - DDRC = (1 << PWM2_PIN); - DDRB = (1 << PWM1_PIN); - DDRA = (1 << PWM3_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - | (1 << BUTTON_LED_PIN) - | (1 << LED_ENABLE_PIN) - | (1 << LED2_ENABLE_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // Linear opamp PWM for both main and 2nd LEDs (10-bit) - // WGM1[3:0]: 0,0,1,1: PWM, Phase Correct, 10-bit (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) - TCCR1A = (1<0) | (CH2_PWM>0) | (CH3_PWM>0); + bool now_on = (ch1_pwm>0) | (ch2_pwm>0) | (ch3_pwm>0); + + if (! now_on) { + CH1_PWM = 0; // linear + CH2_PWM = 0; // linear + CH3_PWM = 0; // DD FET + PWM_TOP = PWM_TOP_INIT; + PWM_CNT = 0; + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp + CH2_ENABLE_PORT &= ~(1 << CH2_ENABLE_PIN); // disable opamp + return; + } + + if (ch1_pwm) + CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable opamp + else + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp + + if (ch2_pwm) + CH2_ENABLE_PORT |= (1 << CH2_ENABLE_PIN); // enable opamp + else + CH2_ENABLE_PORT &= ~(1 << CH2_ENABLE_PIN); // disable opamp + + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; + CH3_PWM = ch3_pwm; + + // manual phase sync when changing level while already on + if (was_on && now_on) while(PWM_CNT > (top - 32)) {} + + PWM_TOP = top; + + // reset phase when turning on or off + //if ((! was_on) | (! now_on)) PWM_CNT = 0; + if (! was_on) PWM_CNT = 0; +} + +void set_level_ch1(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, 0, PWM_TOP_INIT); + + level --; + uint8_t pwm1 = PWM_GET8 (pwm1_levels, level); + uint8_t pwm3 = PWM_GET8 (pwm2_levels, level); + uint16_t top = PWM_GET16(pwm3_levels, level); + set_pwms(pwm1, 0, pwm3, top); +} + +void set_level_ch2(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, 0, PWM_TOP_INIT); + + level --; + uint8_t pwm2 = PWM_GET8 (pwm4_levels, level); + uint16_t top = PWM_GET16(pwm5_levels, level); + set_pwms(0, pwm2, 0, top); +} + +void set_level_both(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, 0, PWM_TOP_INIT); + + level --; + uint8_t pwm1 = PWM_GET8 (pwm1_levels, level); + uint8_t pwm3 = PWM_GET8 (pwm2_levels, level); + uint16_t top = PWM_GET16(pwm3_levels, level); + set_pwms(pwm1, pwm1, pwm3, top); +} + +void set_level_blend(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, 0, PWM_TOP_INIT); + + level --; + uint16_t pwm1, pwm2; + uint8_t pwm3 = PWM_GET8 (pwm2_levels, level); // DD FET + //uint16_t brightness = PWM_GET8 (pwm1_levels, level) << 1; + uint16_t brightness = PWM_GET8 (pwm1_levels, level) + pwm3; + uint16_t top = PWM_GET16(pwm3_levels, level); + uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + + calc_2ch_blend(&pwm1, &pwm2, brightness, top, blend); + + set_pwms(pwm1, pwm2, pwm3, top); +} + +void set_level_auto(uint8_t level) { + if (0 == level) + return set_pwms(0, 0, 0, PWM_TOP_INIT); + + level --; + uint16_t pwm1, pwm2; + uint8_t brightness = PWM_GET8 (pwm4_levels, level); + uint16_t top = PWM_GET16(pwm5_levels, level); + uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; + if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + blend = 255 - blend; + + calc_2ch_blend(&pwm1, &pwm2, brightness, top, blend); + + set_pwms(pwm1, pwm2, 0, top); +} + + +///// bump each channel toward a target value ///// +bool gradual_adjust(uint8_t ch1_pwm, uint8_t ch2_pwm, uint8_t ch3_pwm) { + GRADUAL_ADJUST_STACKED(ch1_pwm, CH1_PWM, PWM_TOP_INIT); + GRADUAL_ADJUST_STACKED(ch2_pwm, CH2_PWM, PWM_TOP_INIT); + GRADUAL_ADJUST_SIMPLE (ch3_pwm, CH3_PWM); + + // check for completion + if ((ch1_pwm == CH1_PWM) + && (ch2_pwm == CH2_PWM) + && (ch3_pwm == CH3_PWM)) { + return true; // done + } + return false; // not done yet +} + +bool gradual_tick_ch1(uint8_t gt) { + uint8_t pwm1 = PWM_GET8(pwm1_levels, gt); + uint8_t pwm3 = PWM_GET8(pwm2_levels, gt); + return gradual_adjust(pwm1, 0, pwm3); +} + +bool gradual_tick_ch2(uint8_t gt) { + uint8_t pwm2 = PWM_GET8(pwm4_levels, gt); + return gradual_adjust(0, pwm2, 0); +} + +bool gradual_tick_both(uint8_t gt) { + uint8_t pwm1 = PWM_GET8(pwm1_levels, gt); + uint8_t pwm3 = PWM_GET8(pwm2_levels, gt); + return gradual_adjust(pwm1, pwm1, pwm3); +} + +bool gradual_tick_blend(uint8_t level) { + uint16_t pwm1, pwm2; + uint8_t pwm3 = PWM_GET8 (pwm2_levels, level); // DD FET + //uint16_t brightness = PWM_GET8 (pwm1_levels, level) << 1; + uint16_t brightness = PWM_GET8 (pwm1_levels, level) + pwm3; + uint16_t top = PWM_GET16(pwm3_levels, level); + uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + + calc_2ch_blend(&pwm1, &pwm2, brightness, top, blend); + + return gradual_adjust(pwm1, pwm2, pwm3); +} + +bool gradual_tick_auto(uint8_t level) { + uint16_t pwm1, pwm2; + uint8_t brightness = PWM_GET8 (pwm4_levels, level); + uint16_t top = PWM_GET16(pwm5_levels, level); + uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; + if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + blend = 255 - blend; + + calc_2ch_blend(&pwm1, &pwm2, brightness, top, blend); + + return gradual_adjust(pwm1, pwm2, 0); +} + + diff --git a/hwdef-emisar-2ch-fet.h b/hwdef-emisar-2ch-fet.h new file mode 100644 index 0000000..451cdfc --- /dev/null +++ b/hwdef-emisar-2ch-fet.h @@ -0,0 +1,209 @@ +// Emisar 2-channel generic w/ tint ramping + DD FET +// Copyright (C) 2021-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * Pin / Name / Function + * 1 PA6 ch2 LED PWM (linear) (PWM1B) + * 2 PA5 R: red aux LED (PWM0B) + * 3 PA4 G: green aux LED + * 4 PA3 B: blue aux LED + * 5 PA2 button LED + * 6 PA1 Opamp 2 enable (channel 2 LEDs) + * 7 PA0 Opamp 1 enable (channel 1 LEDs) + * 8 GND GND + * 9 VCC VCC + * 10 PC5 (none) + * 11 PC4 (none) + * 12 PC3 RESET + * 13 PC2 (none) + * 14 PC1 SCK + * 15 PC0 ch1 LED PWM (FET) (PWM0A, 8-bit) + * 16 PB3 ch1 LED PWM (linear) (PWM1A) + * 17 PB2 MISO + * 18 PB1 MOSI / battery voltage (ADC6) + * 19 PB0 (none) + * 20 PA7 e-switch (PCINT7) + * ADC12 thermal sensor + * + * Both sets of LEDs use one pin to turn the Opamp on/off, + * and one pin to control the Opamp power level. + * The first channel also has a direct-drive FET for turbo. + */ + +#define ATTINY 1634 +#include + +#define HWDEF_C_FILE hwdef-emisar-2ch-fet.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +// channel modes: +// * 0. channel 1 only (linear + DD FET) +// * 1. channel 2 only (linear) +// * 2. both channels, tied together (linear tied + DD FET at top of ramp) +// * 3. both channels, manual blend, max 200% power + DD FET at top of ramp +// * 4. both channels, auto blend, reversible (linear only) +#define NUM_CHANNEL_MODES (5 + NUM_RGB_AUX_CHANNEL_MODES) +enum channel_modes_e { + CM_CH1 = 0, + CM_CH2, + CM_BOTH, + CM_BLEND, + CM_AUTO, + RGB_AUX_ENUMS +}; + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000011111 +#define USE_CHANNEL_MODE_ARGS +// _, _, _, 128=middle CCT, 0=warm-to-cool +#define CHANNEL_MODE_ARGS 0,0,0,128,0,RGB_AUX_CM_ARGS + +// can use some of the common handlers +#define USE_CALC_2CH_BLEND + + +#define PWM_CHANNELS 3 // old, remove this + +#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // linear part of linear+FET ramp +#define PWM2_DATATYPE uint8_t // DD FET part of linear+FET ramp +#define PWM3_DATATYPE uint16_t // linear+FET ramp tops +#define PWM4_DATATYPE uint8_t // linear-only ramp +#define PWM5_DATATYPE uint16_t // linear-only ramp tops + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 255 // highest value used in top half of ramp +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +// main LEDs, linear +#define CH1_PIN PB3 // pin 16, Opamp reference +#define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 +#define CH1_ENABLE_PIN PA0 // pin 7, Opamp power +#define CH1_ENABLE_PORT PORTA // control port for PA0 + +// 2nd LEDs, linear +#define CH2_PIN PA6 // pin 1, 2nd LED Opamp reference +#define CH2_PWM OCR1B // OCR1B is the output compare register for PA6 +#define CH2_ENABLE_PIN PA1 // pin 6, Opamp power +#define CH2_ENABLE_PORT PORTA // control port for PA1 + +// main LEDs, DD FET +#define CH3_PIN PC0 // pin 15, DD FET PWM +#define CH3_PWM OCR0A // OCR0A is the output compare register for PC0 + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PA7 // pin 20 +#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt +#define SWITCH_PCIE PCIE0 // PCIE1 is for PCINT[7:0] +#define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] +#define SWITCH_PORT PINA // PINA or PINB or PINC +#define SWITCH_PUE PUEA // pullup group A +#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#endif + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 +// pin to ADC mappings are in DS table 19-4 +#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 +// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 +#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D +// DS tables 19-3, 19-4 +// Bit 7 6 5 4 3 2 1 0 +// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 +// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 +// divided by ... +// REFS[1:0] = 1, 0 for internal 1.1V reference +// other bits reserved +#define ADMUX_VOLTAGE_DIVIDER 0b10000110 +#define ADC_PRSCL 0x07 // clk/128 + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// D1, R1, R2 = 0, 330, 100 +#ifndef ADC_44 +//#define ADC_44 981 // raw value at 4.40V +#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 +#endif +#ifndef ADC_22 +//#define ADC_22 489 // raw value at 2.20V +#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 +#endif + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + +#define BUTTON_LED_PIN PA2 // pin 5 +#define BUTTON_LED_PORT PORTA // for all "PA" pins +#define BUTTON_LED_DDR DDRA // for all "PA" pins +#define BUTTON_LED_PUE PUEA // for all "PA" pins + + +inline void hwdef_setup() { + // enable output ports + DDRC = (1 << CH3_PIN); + DDRB = (1 << CH1_PIN); + DDRA = (1 << CH2_PIN) + | (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + | (1 << BUTTON_LED_PIN) + | (1 << CH1_ENABLE_PIN) + | (1 << CH2_ENABLE_PIN) + ; + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // Linear opamp PWM for both main and 2nd LEDs (10-bit) + // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) + TCCR1A = (1< RAMP_SIZE) { - cfg.strobe_type = (lvl - RAMP_SIZE - 1) % strobe_mode_END; + current_strobe_type = (lvl - RAMP_SIZE - 1) % strobe_mode_END; } } } -- cgit v1.2.3 From 04a48e44b25d1c42dc26f837586a7503bb74b749 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 24 Aug 2023 17:08:01 -0600 Subject: added channel mode per strobe mode, and made FSM channel mode more flexible, and fixed issue in tactical mode where strobes wouldn't stop on button release --- hwdef-emisar-2ch-fet.c | 8 +++---- hwdef-emisar-2ch.c | 8 +++---- hwdef-noctigon-m44.c | 8 +++---- hwdef-sofirn-lt1s-pro.c | 12 +++++----- spaghetti-monster/anduril/channel-modes.c | 19 ++++++++-------- spaghetti-monster/anduril/config-mode.c | 5 +++-- spaghetti-monster/anduril/load-save-config-fsm.h | 3 +++ spaghetti-monster/anduril/load-save-config.h | 6 +++++ spaghetti-monster/anduril/off-mode.c | 4 ++++ spaghetti-monster/anduril/ramp-mode.c | 12 ++++++---- spaghetti-monster/anduril/strobe-modes-fsm.h | 28 ++++++++++++++++++++++++ spaghetti-monster/anduril/strobe-modes.c | 22 ++++++++++++++++--- spaghetti-monster/anduril/strobe-modes.h | 27 ++--------------------- spaghetti-monster/anduril/tactical-mode.c | 5 +++++ spaghetti-monster/fsm-channels.c | 2 +- spaghetti-monster/fsm-channels.h | 11 ++-------- spaghetti-monster/fsm-misc.c | 6 ++--- spaghetti-monster/fsm-ramping.c | 4 ++-- 18 files changed, 114 insertions(+), 76 deletions(-) diff --git a/hwdef-emisar-2ch-fet.c b/hwdef-emisar-2ch-fet.c index ea4f5e6..7cf48d3 100644 --- a/hwdef-emisar-2ch-fet.c +++ b/hwdef-emisar-2ch-fet.c @@ -134,7 +134,7 @@ void set_level_blend(uint8_t level) { //uint16_t brightness = PWM_GET8 (pwm1_levels, level) << 1; uint16_t brightness = PWM_GET8 (pwm1_levels, level) + pwm3; uint16_t top = PWM_GET16(pwm3_levels, level); - uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + uint8_t blend = cfg.channel_mode_args[channel_mode]; calc_2ch_blend(&pwm1, &pwm2, brightness, top, blend); @@ -150,7 +150,7 @@ void set_level_auto(uint8_t level) { uint8_t brightness = PWM_GET8 (pwm4_levels, level); uint16_t top = PWM_GET16(pwm5_levels, level); uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; - if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + if (cfg.channel_mode_args[channel_mode] & 0b01000000) blend = 255 - blend; calc_2ch_blend(&pwm1, &pwm2, brightness, top, blend); @@ -197,7 +197,7 @@ bool gradual_tick_blend(uint8_t level) { //uint16_t brightness = PWM_GET8 (pwm1_levels, level) << 1; uint16_t brightness = PWM_GET8 (pwm1_levels, level) + pwm3; uint16_t top = PWM_GET16(pwm3_levels, level); - uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + uint8_t blend = cfg.channel_mode_args[channel_mode]; calc_2ch_blend(&pwm1, &pwm2, brightness, top, blend); @@ -209,7 +209,7 @@ bool gradual_tick_auto(uint8_t level) { uint8_t brightness = PWM_GET8 (pwm4_levels, level); uint16_t top = PWM_GET16(pwm5_levels, level); uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; - if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + if (cfg.channel_mode_args[channel_mode] & 0b01000000) blend = 255 - blend; calc_2ch_blend(&pwm1, &pwm2, brightness, top, blend); diff --git a/hwdef-emisar-2ch.c b/hwdef-emisar-2ch.c index 793e9bc..7955cf6 100644 --- a/hwdef-emisar-2ch.c +++ b/hwdef-emisar-2ch.c @@ -128,7 +128,7 @@ void set_level_blend(uint8_t level) { PWM_DATATYPE ch1_pwm, ch2_pwm; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); PWM_DATATYPE top = PWM_GET(pwm_tops, level); - uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + uint8_t blend = cfg.channel_mode_args[channel_mode]; calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); @@ -144,7 +144,7 @@ void set_level_auto(uint8_t level) { PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); PWM_DATATYPE top = PWM_GET(pwm_tops, level); uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; - if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + if (cfg.channel_mode_args[channel_mode] & 0b01000000) blend = 255 - blend; calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); @@ -185,7 +185,7 @@ bool gradual_tick_blend(uint8_t gt) { PWM_DATATYPE ch1_pwm, ch2_pwm; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); PWM_DATATYPE top = PWM_GET(pwm_tops, gt); - uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + uint8_t blend = cfg.channel_mode_args[channel_mode]; calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); @@ -197,7 +197,7 @@ bool gradual_tick_auto(uint8_t gt) { PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); PWM_DATATYPE top = PWM_GET(pwm_tops, gt); uint8_t blend = 255 * (uint16_t)gt / RAMP_SIZE; - if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + if (cfg.channel_mode_args[channel_mode] & 0b01000000) blend = 255 - blend; calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); diff --git a/hwdef-noctigon-m44.c b/hwdef-noctigon-m44.c index 3fc6abe..0c73005 100644 --- a/hwdef-noctigon-m44.c +++ b/hwdef-noctigon-m44.c @@ -128,7 +128,7 @@ void set_level_blend(uint8_t level) { PWM_DATATYPE ch1_pwm, ch2_pwm; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); PWM_DATATYPE top = PWM_GET(pwm_tops, level); - uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + uint8_t blend = cfg.channel_mode_args[channel_mode]; calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); @@ -148,7 +148,7 @@ void set_level_auto(uint8_t level) { PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); PWM_DATATYPE top = PWM_GET(pwm_tops, level); uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; - if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + if (cfg.channel_mode_args[channel_mode] & 0b01000000) blend = 255 - blend; calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); @@ -189,7 +189,7 @@ bool gradual_tick_blend(uint8_t gt) { PWM_DATATYPE ch1_pwm, ch2_pwm; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); PWM_DATATYPE top = PWM_GET(pwm_tops, gt); - uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + uint8_t blend = cfg.channel_mode_args[channel_mode]; calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); @@ -201,7 +201,7 @@ bool gradual_tick_auto(uint8_t gt) { PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); PWM_DATATYPE top = PWM_GET(pwm_tops, gt); uint8_t blend = 255 * (uint16_t)gt / RAMP_SIZE; - if (cfg.channel_mode_args[cfg.channel_mode] & 0b01000000) + if (cfg.channel_mode_args[channel_mode] & 0b01000000) blend = 255 - blend; calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); diff --git a/hwdef-sofirn-lt1s-pro.c b/hwdef-sofirn-lt1s-pro.c index 6fe0fef..1359c29 100644 --- a/hwdef-sofirn-lt1s-pro.c +++ b/hwdef-sofirn-lt1s-pro.c @@ -107,7 +107,7 @@ void set_level_white_blend(uint8_t level) { PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); PWM_DATATYPE top = PWM_GET(pwm_tops, level); - uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + uint8_t blend = cfg.channel_mode_args[channel_mode]; calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); @@ -172,9 +172,9 @@ void set_level_auto_3ch_blend(uint8_t level) { // "white + red" channel mode void set_level_red_white_blend(uint8_t level) { // set the warm+cool white LEDs first - cfg.channel_mode = CM_WHITE; + channel_mode = CM_WHITE; set_level_white_blend(level); - cfg.channel_mode = CM_WHITE_RED; + channel_mode = CM_WHITE_RED; if (level == 0) { RED_PWM_LVL = 0; @@ -188,7 +188,7 @@ void set_level_red_white_blend(uint8_t level) { // set the red LED as a ratio of the white output level // 0 = no red // 255 = red at 100% of white channel PWM - uint8_t ratio = cfg.channel_mode_args[cfg.channel_mode]; + uint8_t ratio = cfg.channel_mode_args[channel_mode]; RED_PWM_LVL = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)vpwm) + 127) / 255; if (! actual_level) PWM_CNT = 0; // reset phase @@ -223,7 +223,7 @@ bool gradual_tick_white_blend(uint8_t gt) { PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); PWM_DATATYPE top = PWM_GET(pwm_tops, gt); - uint8_t blend = cfg.channel_mode_args[cfg.channel_mode]; + uint8_t blend = cfg.channel_mode_args[channel_mode]; calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); @@ -259,7 +259,7 @@ bool gradual_tick_red_white_blend(uint8_t gt) { PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); PWM_DATATYPE top = PWM_GET(pwm_tops, gt); uint8_t blend = cfg.channel_mode_args[CM_WHITE]; - uint8_t ratio = cfg.channel_mode_args[cfg.channel_mode]; + uint8_t ratio = cfg.channel_mode_args[channel_mode]; red = (((PWM_DATATYPE2)ratio * (PWM_DATATYPE2)brightness) + 127) / 255; calc_2ch_blend(&warm, &cool, brightness, top, blend); diff --git a/spaghetti-monster/anduril/channel-modes.c b/spaghetti-monster/anduril/channel-modes.c index cecf0bf..f7e90bd 100644 --- a/spaghetti-monster/anduril/channel-modes.c +++ b/spaghetti-monster/anduril/channel-modes.c @@ -17,7 +17,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { // in addition to changing state... so ignore any tint-ramp events which // don't look like they were meant to be here static uint8_t active = 0; - uint8_t tint = cfg.channel_mode_args[cfg.channel_mode]; + uint8_t tint = cfg.channel_mode_args[channel_mode]; #endif // it's possible that a light may need 3H but not 3C, @@ -25,7 +25,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { #if NUM_CHANNEL_MODES > 1 // 3 clicks: next channel mode if (event == EV_3clicks) { - uint8_t next = cfg.channel_mode; + uint8_t next = channel_mode; // go to next channel mode until we find one which is enabled // (and don't do any infinite loops if the user disabled them all) uint8_t count = 0; @@ -36,15 +36,16 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { //} while ((! channel_modes_enabled[next]) && count < NUM_CHANNEL_MODES); // undo change if infinite loop detected (redundant?) - //if (NUM_CHANNEL_MODES == count) next = cfg.channel_mode; + //if (NUM_CHANNEL_MODES == count) next = channel_mode; // if mode hasn't changed, abort - if (cfg.channel_mode == next) + if (channel_mode == next) return EVENT_NOT_HANDLED; set_channel_mode(next); // remember after battery changes + cfg.channel_mode = channel_mode; save_config(); return EVENT_HANDLED; } else @@ -52,9 +53,9 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { #ifdef USE_CUSTOM_CHANNEL_3H_MODES // defer to mode-specific function if defined - if (tint_ramp_modes[cfg.channel_mode]) { - StatePtr tint_func = channel_3H_modes[cfg.channel_mode]; - return tint_func(cfg.channel_mode); + if (tint_ramp_modes[channel_mode]) { + StatePtr tint_func = channel_3H_modes[channel_mode]; + return tint_func(channel_mode); } else #endif #ifdef USE_CHANNEL_MODE_ARGS @@ -95,7 +96,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { past_edge_counter = 1; } prev_tint = tint; - cfg.channel_mode_args[cfg.channel_mode] = tint; + cfg.channel_mode_args[channel_mode] = tint; set_level(actual_level); return EVENT_HANDLED; } @@ -108,7 +109,7 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { if (0 == tint) tint_ramp_direction = 1; else if (255 == tint) tint_ramp_direction = -1; // remember tint after battery change - cfg.channel_mode_args[cfg.channel_mode] = tint; + cfg.channel_mode_args[channel_mode] = tint; save_config(); // bug?: for some reason, brightness can seemingly change // from 1/150 to 2/150 without this next line... not sure why diff --git a/spaghetti-monster/anduril/config-mode.c b/spaghetti-monster/anduril/config-mode.c index d379cd9..71b0d69 100644 --- a/spaghetti-monster/anduril/config-mode.c +++ b/spaghetti-monster/anduril/config-mode.c @@ -13,8 +13,9 @@ volatile uint8_t number_entry_value; #if defined(USE_CONFIG_COLORS) && (NUM_CHANNEL_MODES > 1) +// TODO: promote this to fsm-channels.c ? void set_chan_if(bool cond, uint8_t chan) { - if ((cond) && (chan != cfg.channel_mode)) + if ((cond) && (chan != channel_mode)) set_channel_mode(chan); } #endif @@ -41,7 +42,7 @@ uint8_t config_state_base( #endif if (event == EV_enter_state) { #if defined(USE_CONFIG_COLORS) && (NUM_CHANNEL_MODES > 1) - orig_channel = cfg.channel_mode; + orig_channel = channel_mode; #endif config_step = 0; set_level(0); diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h index 462b41c..7bf87f4 100644 --- a/spaghetti-monster/anduril/load-save-config-fsm.h +++ b/spaghetti-monster/anduril/load-save-config-fsm.h @@ -70,6 +70,9 @@ typedef struct Config { ///// strobe / blinky mode settings #ifdef USE_STROBE_STATE uint8_t strobe_type; + #if NUM_CHANNEL_MODES > 1 + uint8_t strobe_channels[NUM_STROBES]; + #endif #endif #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) uint8_t strobe_delays[2]; diff --git a/spaghetti-monster/anduril/load-save-config.h b/spaghetti-monster/anduril/load-save-config.h index 8ae9d96..2dfa8c9 100644 --- a/spaghetti-monster/anduril/load-save-config.h +++ b/spaghetti-monster/anduril/load-save-config.h @@ -98,6 +98,12 @@ Config cfg = { #ifdef USE_STROBE_STATE .strobe_type = DEFAULT_STROBE, + #if NUM_CHANNEL_MODES > 1 + // channel mode saved per strobe-group mode + #ifdef DEFAULT_STROBE_CHANNELS + .strobe_channels = { DEFAULT_STROBE_CHANNELS }, + #endif + #endif #endif #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) // party / tactical strobe timing diff --git a/spaghetti-monster/anduril/off-mode.c b/spaghetti-monster/anduril/off-mode.c index ab67d96..a484f06 100644 --- a/spaghetti-monster/anduril/off-mode.c +++ b/spaghetti-monster/anduril/off-mode.c @@ -16,6 +16,10 @@ uint8_t off_state(Event event, uint16_t arg) { if (event == EV_enter_state) { set_level(0); ticks_since_on = 0; + #if NUM_CHANNEL_MODES > 1 + // reset to ramp mode's channel when light turns off + channel_mode = cfg.channel_mode; + #endif #ifdef USE_INDICATOR_LED // redundant, sleep tick does the same thing //indicator_led_update(cfg.indicator_led_mode & 0x03, 0); diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index 4fef2c2..f21f599 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -19,6 +19,10 @@ uint8_t steady_state(Event event, uint16_t arg) { static uint8_t level_before_off = 0; #endif + #if NUM_CHANNEL_MODES > 1 + channel_mode = cfg.channel_mode; + #endif + // make sure ramp globals are correct... // ... but they already are; no need to do it here //ramp_update_config(); @@ -417,7 +421,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_CHANNEL_MODE_ARGS // ramp tint if tint exists in this mode if ((event == EV_click3_hold) - && (channel_has_args(cfg.channel_mode))) + && (channel_has_args(channel_mode))) return EVENT_NOT_HANDLED; #endif if (! arg) { // first frame only, to allow thermal regulation to work @@ -438,7 +442,7 @@ uint8_t steady_state(Event event, uint16_t arg) { #ifdef USE_CHANNEL_MODE_ARGS // ramp tint if tint exists in this mode if ((event == EV_click3_hold_release) - && (channel_has_args(cfg.channel_mode))) + && (channel_has_args(channel_mode))) return EVENT_NOT_HANDLED; #endif set_level_and_therm_target(memorized_level); @@ -665,7 +669,7 @@ void set_level_and_therm_target(uint8_t level) { void manual_memory_restore() { memorized_level = cfg.manual_memory; #if NUM_CHANNEL_MODES > 1 - cfg.channel_mode = cfg.manual_memory_channel_mode; + channel_mode = cfg.channel_mode = cfg.manual_memory_channel_mode; #endif #ifdef USE_CHANNEL_MODE_ARGS for (uint8_t i=0; i 1 - cfg.manual_memory_channel_mode = cfg.channel_mode; + cfg.manual_memory_channel_mode = channel_mode; #endif #ifdef USE_CHANNEL_MODE_ARGS for (uint8_t i=0; i 1 + // 3 clicks: rotate through channel modes for the current strobe + else if (event == EV_3clicks) { + // TODO: maybe skip aux modes? + set_channel_mode((channel_mode + 1) % NUM_CHANNEL_MODES); + cfg.strobe_channels[st] = channel_mode; + save_config(); + return EVENT_HANDLED; + } + #endif // 4 clicks: rotate backward through strobe/flasher modes else if (event == EV_4clicks) { current_strobe_type = cfg.strobe_type = (st - 1 + NUM_STROBES) % NUM_STROBES; @@ -157,6 +167,11 @@ uint8_t strobe_state(Event event, uint16_t arg) { inline void strobe_state_iter() { uint8_t st = current_strobe_type; // can't use switch() on an enum + #if NUM_CHANNEL_MODES > 1 + // remember channel mode for each strobe + channel_mode = cfg.strobe_channels[st]; + #endif + switch(st) { #if defined(USE_PARTY_STROBE_MODE) || defined(USE_TACTICAL_STROBE_MODE) #ifdef USE_PARTY_STROBE_MODE @@ -223,7 +238,7 @@ inline void police_color_strobe_iter() { uint8_t del = 66; // TODO: make police strobe brightness configurable uint8_t bright = memorized_level; - uint8_t channel = cfg.channel_mode; + //uint8_t channel = channel_mode; for (uint8_t i=0; i<10; i++) { if (0 == i) set_channel_mode(POLICE_COLOR_STROBE_CH1); @@ -234,8 +249,9 @@ inline void police_color_strobe_iter() { nice_delay_ms(del); } - // restore this when done - set_channel_mode(channel); + // restore the channel when done + //set_channel_mode(channel); + channel_mode = cfg.channel_mode; } #endif diff --git a/spaghetti-monster/anduril/strobe-modes.h b/spaghetti-monster/anduril/strobe-modes.h index 127966b..7dc1df4 100644 --- a/spaghetti-monster/anduril/strobe-modes.h +++ b/spaghetti-monster/anduril/strobe-modes.h @@ -4,31 +4,7 @@ #pragma once -// internal numbering for strobe modes #ifdef USE_STROBE_STATE -typedef enum { - #ifdef USE_PARTY_STROBE_MODE - party_strobe_e, - #endif - #ifdef USE_TACTICAL_STROBE_MODE - tactical_strobe_e, - #endif - #ifdef USE_POLICE_COLOR_STROBE_MODE - police_color_strobe_e, - #endif - #ifdef USE_LIGHTNING_MODE - lightning_storm_e, - #endif - #ifdef USE_CANDLE_MODE - candle_mode_e, - #endif - #ifdef USE_BIKE_FLASHER_MODE - bike_flasher_e, - #endif - strobe_mode_END -} strobe_mode_te; - -const int NUM_STROBES = strobe_mode_END; strobe_mode_te current_strobe_type; @@ -38,7 +14,8 @@ strobe_mode_te current_strobe_type; #else #define DEFAULT_STROBE 0 #endif -#endif + +#endif // ifdef USE_STROBE_STATE // full FET strobe can be a bit much... use max regulated level instead, diff --git a/spaghetti-monster/anduril/tactical-mode.c b/spaghetti-monster/anduril/tactical-mode.c index 0bcaaca..0035496 100644 --- a/spaghetti-monster/anduril/tactical-mode.c +++ b/spaghetti-monster/anduril/tactical-mode.c @@ -28,6 +28,10 @@ uint8_t tactical_state(Event event, uint16_t arg) { if ((1 <= lvl) && (lvl <= RAMP_SIZE)) { // steady output memorized_level = lvl; momentary_mode = 0; + #if NUM_CHANNEL_MODES > 1 + // use ramp mode's channel + channel_mode = cfg.channel_mode; + #endif } else { // momentary strobe mode momentary_mode = 1; if (lvl > RAMP_SIZE) { @@ -40,6 +44,7 @@ uint8_t tactical_state(Event event, uint16_t arg) { else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) { momentary_active = 0; set_level(0); + interrupt_nice_delays(); // stop animations in progress } // delegate to momentary mode while button is pressed diff --git a/spaghetti-monster/fsm-channels.c b/spaghetti-monster/fsm-channels.c index 3b30b58..944bdcb 100644 --- a/spaghetti-monster/fsm-channels.c +++ b/spaghetti-monster/fsm-channels.c @@ -13,7 +13,7 @@ void set_channel_mode(uint8_t mode) { set_level(0); // change the channel - CH_MODE = mode; + channel_mode = mode; // update the LEDs set_level(cur_level); diff --git a/spaghetti-monster/fsm-channels.h b/spaghetti-monster/fsm-channels.h index ba2d3fa..55fc826 100644 --- a/spaghetti-monster/fsm-channels.h +++ b/spaghetti-monster/fsm-channels.h @@ -38,17 +38,10 @@ Channel channels[]; // values are defined in the hwdef-*.c // TODO: size-optimize the case with only 1 channel mode? // (the arrays and stuff shouldn't be needed) -#if defined(USE_CFG) && (NUM_CHANNEL_MODES > 1) - #define CH_MODE cfg.channel_mode -#else +#if NUM_CHANNEL_MODES > 1 + #define USE_CHANNEL_MODES // current multi-channel mode uint8_t channel_mode = DEFAULT_CHANNEL_MODE; - #define CH_MODE channel_mode -#endif - -// FIXME: remove this? -#if NUM_CHANNEL_MODES > 1 -#define USE_CHANNEL_MODES #endif #ifdef USE_CUSTOM_CHANNEL_3H_MODES diff --git a/spaghetti-monster/fsm-misc.c b/spaghetti-monster/fsm-misc.c index 0aeb7c3..bc10ea1 100644 --- a/spaghetti-monster/fsm-misc.c +++ b/spaghetti-monster/fsm-misc.c @@ -35,7 +35,7 @@ uint8_t blink_digit(uint8_t num) { #ifdef BLINK_CHANNEL // channel is set per blink, to prevent issues // if another mode interrupts us (like a config menu) - uint8_t old_channel = CH_MODE; + uint8_t old_channel = channel_mode; #endif for (; num>0; num--) { @@ -45,7 +45,7 @@ uint8_t blink_digit(uint8_t num) { #endif set_level(BLINK_BRIGHTNESS); #ifdef BLINK_CHANNEL - CH_MODE = old_channel; + channel_mode = old_channel; #endif nice_delay_ms(ontime); @@ -54,7 +54,7 @@ uint8_t blink_digit(uint8_t num) { #endif set_level(0); #ifdef BLINK_CHANNEL - CH_MODE = old_channel; + channel_mode = old_channel; #endif nice_delay_ms(BLINK_SPEED * 3 / 12); } diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c index 6419bfd..a970f0e 100644 --- a/spaghetti-monster/fsm-ramping.c +++ b/spaghetti-monster/fsm-ramping.c @@ -59,7 +59,7 @@ void set_level(uint8_t level) { #endif // call the relevant hardware-specific set_level_*() - SetLevelFuncPtr set_level_func = channels[CH_MODE].set_level; + SetLevelFuncPtr set_level_func = channels[channel_mode].set_level; set_level_func(level); if (actual_level != level) prev_level = actual_level; @@ -217,7 +217,7 @@ void gradual_tick() { gt --; // call the relevant hardware-specific function - GradualTickFuncPtr gradual_tick_func = channels[CH_MODE].gradual_tick; + GradualTickFuncPtr gradual_tick_func = channels[channel_mode].gradual_tick; bool done = gradual_tick_func(gt); if (done) { -- cgit v1.2.3 From 2196969167efc5298277f53f0ce7103ee6630dad Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 24 Aug 2023 17:12:49 -0600 Subject: added emisar-d4k-3ch build --- hwdef-emisar-d4k-3ch.c | 421 +++++++++++++++++++++++++ hwdef-emisar-d4k-3ch.h | 230 ++++++++++++++ spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h | 106 +++++++ 3 files changed, 757 insertions(+) create mode 100644 hwdef-emisar-d4k-3ch.c create mode 100644 hwdef-emisar-d4k-3ch.h create mode 100644 spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h diff --git a/hwdef-emisar-d4k-3ch.c b/hwdef-emisar-d4k-3ch.c new file mode 100644 index 0000000..1042d9e --- /dev/null +++ b/hwdef-emisar-d4k-3ch.c @@ -0,0 +1,421 @@ +// Emisar D4K 3-channel hwdef +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "chan-rgbaux.c" + + +void set_level_main2(uint8_t level); +void set_level_led3(uint8_t level); +void set_level_led4(uint8_t level); +void set_level_all(uint8_t level); +void set_level_led34a_blend(uint8_t level); +void set_level_led34b_blend(uint8_t level); +void set_level_hsv(uint8_t level); +void set_level_auto3(uint8_t level); + +bool gradual_tick_main2(uint8_t gt); +bool gradual_tick_led3(uint8_t gt); +bool gradual_tick_led4(uint8_t gt); +bool gradual_tick_all(uint8_t gt); +bool gradual_tick_led34a_blend(uint8_t gt); +bool gradual_tick_led34b_blend(uint8_t gt); +bool gradual_tick_hsv(uint8_t gt); +bool gradual_tick_auto3(uint8_t gt); + + +Channel channels[] = { + { // main 2 LEDs only + .set_level = set_level_main2, + .gradual_tick = gradual_tick_main2, + .has_args = 0 + }, + { // 3rd LED only + .set_level = set_level_led3, + .gradual_tick = gradual_tick_led3, + .has_args = 0 + }, + { // 4th LED only + .set_level = set_level_led4, + .gradual_tick = gradual_tick_led4, + .has_args = 0 + }, + { // all channels, tied together (equal amounts, max power) + .set_level = set_level_all, + .gradual_tick = gradual_tick_all, + .has_args = 0 + }, + { // 3rd + 4th LEDs, manual blend (max "100%" power) (8/16/16) + .set_level = set_level_led34a_blend, + .gradual_tick = gradual_tick_led34a_blend, + .has_args = 1 + }, + { // 3rd + 4th LEDs, manual blend (max "100%" power) (16/16/8) + .set_level = set_level_led34b_blend, + .gradual_tick = gradual_tick_led34b_blend, + .has_args = 1 + }, + { // 3ch blend (HSV style) + .set_level = set_level_hsv, + .gradual_tick = gradual_tick_hsv, + .has_args = 1 + }, + { // 3ch auto blend (red-warm-cool style, led4-led3-main2) + .set_level = set_level_auto3, + .gradual_tick = gradual_tick_auto3, + .has_args = 0 + }, + RGB_AUX_CHANNELS +}; + + +// LEDs 1+2 are 8-bit +// this 8-bit channel may be LEDs 1+2 or LED 4, depending on wiring +void set_level_main2(uint8_t level) { + if (level == 0) { + MAIN2_PWM_LVL = 0; + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp + LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp + } else { + level --; + MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); + MAIN2_PWM_LVL = PWM_GET8(pwm1_levels, level); + } +} + +// LED 3 is 16-bit +void set_level_led3(uint8_t level) { + if (level == 0) { + LED3_PWM_LVL = 0; + PWM_CNT = 0; + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp + LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp + } else { + level --; + LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN); + LED3_PWM_LVL = PWM_GET16(pwm2_levels, level); + uint16_t top = PWM_GET16(pwm_tops, level); + while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; + } +} + +// this 16-bit channel may be LED 4 or LEDs 1+2, depending on wiring +void set_level_led4(uint8_t level) { + if (level == 0) { + LED4_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp + LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp + } else { + level --; // PWM array index = level - 1 + // gotta turn on the opamp before light can come out + LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN); + LED4_PWM_LVL = PWM_GET16(pwm2_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET16(pwm_tops, level); + // wait to sync the counter and avoid flashes + while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; + } +} + +void set_level_all(uint8_t level) { + if (level == 0) { + MAIN2_PWM_LVL = 0; + LED3_PWM_LVL = 0; + LED4_PWM_LVL = 0; + PWM_CNT = 0; + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp + LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp + return; + } + + level --; + + MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); + LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN ); + LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN ); + // FIXME? It might be better to calculate the 8-bit value from the + // 16-bit tables instead of using the 8-bit ramp + // 8bit = max(1, 16bit * 255 / top) + MAIN2_PWM_LVL = PWM_GET8 (pwm1_levels, level); + LED3_PWM_LVL = PWM_GET16(pwm2_levels, level); + LED4_PWM_LVL = PWM_GET16(pwm2_levels, level); + uint16_t top = PWM_GET16(pwm_tops, level); + while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; +} + +// 8/16/16 wiring, mix 16+16 +void set_level_led34a_blend(uint8_t level) { + if (level == 0) { + LED3_PWM_LVL = 0; + LED4_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp + LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp + return; + } + + level --; // PWM array index = level - 1 + + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET16(pwm2_levels, level); + PWM_DATATYPE top = PWM_GET16(pwm_tops, level); + uint8_t blend = cfg.channel_mode_args[channel_mode]; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + + if (warm_PWM > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN); + if (cool_PWM > 0) LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN); + LED3_PWM_LVL = warm_PWM; + LED4_PWM_LVL = cool_PWM; + while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; +} + +// 16/16/8 wiring, mix 16+8 +void set_level_led34b_blend(uint8_t level) { + if (level == 0) { + LED3_PWM_LVL = 0; + LED4_PWM_LVL = 0; + PWM_CNT = 0; // reset phase + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp + LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp + return; + } + + level --; + + const uint16_t top = 2047; + uint16_t warm_PWM, cool_PWM; // 11 bits, 8 bits + uint8_t blend = cfg.channel_mode_args[channel_mode]; + uint16_t brightness = PWM_GET8(pwm1_levels, level); + + if (0 == brightness) brightness = 1; + brightness = brightness << 3; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + + // adjust to halfway between 8-bit steps + warm_PWM -= 4; + if (warm_PWM > top) warm_PWM = 0; + + if (cool_PWM > 0) MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); + if (warm_PWM > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN); + MAIN2_PWM_LVL = (uint8_t)(cool_PWM >> 3); + LED3_PWM_LVL = warm_PWM; + //while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; +} + +void set_level_hsv(uint8_t level) { + // TODO: implement a custom 3H handler which wraps around 0 to 255 + if (level == 0) { + MAIN2_PWM_LVL = 0; + LED3_PWM_LVL = 0; + LED4_PWM_LVL = 0; + PWM_CNT = 0; + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp + LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp + return; + } + + level --; + + RGB_t color; + uint8_t h = cfg.channel_mode_args[channel_mode]; + uint8_t s = 255; // TODO: drop saturation at brightest levels + uint8_t v = PWM_GET8(pwm1_levels, level); + color = hsv2rgb(h, s, v); + + if (color.r > 0) MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); + if (color.g > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN ); + if (color.b > 0) LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN ); + MAIN2_PWM_LVL = color.r; + LED3_PWM_LVL = color.g; + LED4_PWM_LVL = color.b; + //while(actual_level && (PWM_CNT > (255 - 32))) {} + PWM_TOP = 255; + if (! actual_level) PWM_CNT = 0; +} + +// calculate a 3-channel "auto tint" blend +// (like red -> warm white -> cool white) +// results are placed in *a, *b, and *c vars +// level : ramp level to convert into 3 channel levels +// (assumes ramp table is "pwm1_levels") +void calc_auto_3ch_blend( + uint16_t *a, // red + uint16_t *b, // warm + uint8_t *c, // cool + uint8_t level) { + + // led4=red, led3=warm + uint16_t vpwm = PWM_GET16(pwm2_levels, level); + // main2=white, 8-bit + uint8_t vpwm8 = PWM_GET8 (pwm1_levels, level); + + // tint goes from 0 (red) to 127 (warm white) to 255 (cool white) + uint8_t mytint; + mytint = 255 * (uint16_t)level / RAMP_SIZE; + + // TODO: make "a" drop to zero sooner, and "c" start ramping up later + // red is high at 0, low at 255 (linear) + *a = (((PWM_DATATYPE2)(255 - mytint) + * (PWM_DATATYPE2)vpwm) + 127) / 255; + // warm white is low at 0 and 255, high at 127 (linear triangle) + *b = (((PWM_DATATYPE2)triangle_wave(mytint) + * (PWM_DATATYPE2)vpwm) + 127) / 255; + // cool white is low at 0, high at 255 (linear) + *c = (uint8_t)( + (((PWM_DATATYPE2)mytint + * (PWM_DATATYPE2)vpwm8) + 127) / 255 + ); + +} + +// 3-channel "auto tint" channel mode +void set_level_auto3(uint8_t level) { + if (level == 0) { + MAIN2_PWM_LVL = 0; + LED3_PWM_LVL = 0; + LED4_PWM_LVL = 0; + PWM_CNT = 0; + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp + LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp + return; + } + + level --; + + uint16_t a, b; + uint8_t c; + calc_auto_3ch_blend(&a, &b, &c, level); + + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET(pwm_tops, level); + + if (a > 0) LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN ); + else LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); + if (b > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN ); + else LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); + if (c > 0) MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); + else MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); + + LED4_PWM_LVL = a; // red + LED3_PWM_LVL = b; // warm + MAIN2_PWM_LVL = c; // cool + + while(actual_level && (PWM_CNT > (255 - 32))) {} + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; +} + +///// "gradual tick" functions for smooth thermal regulation ///// + +bool gradual_adjust(uint8_t main2, uint16_t led3, uint16_t led4) { + GRADUAL_ADJUST_SIMPLE(main2, MAIN2_PWM_LVL); + GRADUAL_ADJUST_SIMPLE(led3, LED3_PWM_LVL ); + GRADUAL_ADJUST_SIMPLE(led4, LED4_PWM_LVL ); + + if ((main2 == MAIN2_PWM_LVL) + && (led3 == LED3_PWM_LVL ) + && (led4 == LED4_PWM_LVL )) { + return true; // done + } + return false; // not done yet +} + +bool gradual_tick_main2(uint8_t gt) { + uint8_t main2 = PWM_GET8(pwm1_levels, gt); + return gradual_adjust(main2, 0, 0); +} + +bool gradual_tick_led3(uint8_t gt) { + uint16_t led3 = PWM_GET16(pwm2_levels, gt); + return gradual_adjust(0, led3, 0); +} + +bool gradual_tick_led4(uint8_t gt) { + uint16_t led4 = PWM_GET16(pwm2_levels, gt); + return gradual_adjust(0, 0, led4); +} + +bool gradual_tick_all(uint8_t gt) { + uint8_t main2 = PWM_GET8 (pwm1_levels, gt); + uint16_t led3 = PWM_GET16(pwm2_levels, gt); + uint16_t led4 = PWM_GET16(pwm2_levels, gt); + return gradual_adjust(main2, led3, led4); +} + +// 8/16/16 wiring, mix 16+16 +bool gradual_tick_led34a_blend(uint8_t gt) { + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET16(pwm2_levels, gt); + PWM_DATATYPE top = PWM_GET16(pwm_tops, gt); + uint8_t blend = cfg.channel_mode_args[channel_mode]; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + + return gradual_adjust(0, warm_PWM, cool_PWM); +} + +// 16/16/8 wiring, mix 16+8 +bool gradual_tick_led34b_blend(uint8_t gt) { + const uint16_t top = 2047; + uint16_t warm_PWM, cool_PWM; // 11 bits, 8 bits + uint8_t blend = cfg.channel_mode_args[channel_mode]; + uint16_t brightness = PWM_GET8(pwm1_levels, gt); + + if (0 == brightness) brightness = 1; + brightness = brightness << 3; + + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + + // adjust to halfway between 8-bit steps + warm_PWM -= 4; + if (warm_PWM > top) warm_PWM = 0; + + // convert to 8-bit + cool_PWM = (uint8_t)(cool_PWM >> 3); + + return gradual_adjust(cool_PWM, warm_PWM, 0); +} + +bool gradual_tick_hsv(uint8_t gt) { + // figure out what exact PWM levels we're aiming for + RGB_t color; + uint8_t h = cfg.channel_mode_args[channel_mode]; + uint8_t s = 255; // TODO: drop saturation at brightest levels + uint8_t v = PWM_GET8(pwm1_levels, gt); + color = hsv2rgb(h, s, v); + + return gradual_adjust(color.r, color.g, color.b); +} + +bool gradual_tick_auto3(uint8_t gt) { + // figure out what exact PWM levels we're aiming for + uint16_t red, warm; + uint8_t cool; + calc_auto_3ch_blend(&red, &warm, &cool, gt); + return gradual_adjust(cool, warm, red); +} + diff --git a/hwdef-emisar-d4k-3ch.h b/hwdef-emisar-d4k-3ch.h new file mode 100644 index 0000000..4a3134e --- /dev/null +++ b/hwdef-emisar-d4k-3ch.h @@ -0,0 +1,230 @@ +// Emisar D4K 3-channel hwdef +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * Pin / Name / Function + * 1 PA6 LED 4 PWM (linear) (PWM1B) + * 2 PA5 R: red aux LED (PWM0B) + * 3 PA4 G: green aux LED + * 4 PA3 B: blue aux LED + * 5 PA2 button LED + * 6 PA1 3rd LED opamp enable + * 7 PA0 4th LED opamp enable + * 8 GND GND + * 9 VCC VCC + * 10 PC5 (none) + * 11 PC4 (none) + * 12 PC3 RESET + * 13 PC2 (none) + * 14 PC1 SCK + * 15 PC0 main 2 LEDs PWM (linear) (PWM0A) (8-bit only) + * 16 PB3 3rd LED PWM (linear) (PWM1A) + * 17 PB2 MISO + * 18 PB1 MOSI / battery voltage (ADC6) + * 19 PB0 main 2 LEDs opamp enable + * 20 PA7 e-switch (PCINT7) + * ADC12 thermal sensor + * + * All 3 channels share a single Opamp enable pin, + * but have individual PWM controls. + * PWM speed + resolution is dynamic on 2 channels, + * and 8-bit 16 kHz on 1 channel. + * + * Note: Some hardware might swap the wires at build time! + * It might be wired 8/16/16 (8-bit LEDs 1+2) or 16/16/8 (8-bit LED 4). + * So this code should support both wire layouts. + */ + +#define ATTINY 1634 +#include + +#define HWDEF_C_FILE hwdef-emisar-d4k-3ch.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +// channel modes: +// - 1. main 2 LEDs only (8/16/16 wiring) or LED 4 only (16/16/8) +// - 2. 3rd LED only +// - 3. 4th LED only (8/16/16 wiring) or main 2 LEDs only (16/16/8) +// - 4. all 3 channels (equal amounts) +// - 5. 2ch blend (3rd + 4th LEDs, 8/16/16 wiring) +// - 6. 2ch blend (3rd + 4th LEDs, 16/16/8 wiring) +// - 7. 3ch blend (HSV style) +// - 8. 3ch auto blend (red-warm-cool style, led4-led3-main2) +// - 9+. RGB aux (hidden) +#define NUM_CHANNEL_MODES (8 + NUM_RGB_AUX_CHANNEL_MODES) +enum channel_modes_e { + CM_MAIN2 = 0, + CM_LED3, + CM_LED4, + CM_ALL, + CM_BLEND34A, // 8 / [16+16] + CM_BLEND34B, // 16 / [16+8] + CM_HSV, + CM_AUTO3, + RGB_AUX_ENUMS +}; + +#define CHANNEL_MODES_ENABLED 0b0000000000011111 +#define USE_CHANNEL_MODE_ARGS +// _, _, _, _, 128=middle CCT, 128=middle CCT, 213=purple, _ +#define CHANNEL_MODE_ARGS 0,0,0,0,128,128,213,0,RGB_AUX_CM_ARGS + +// can use some of the common handlers +#define USE_CALC_2CH_BLEND +#define USE_HSV2RGB + + +#define PWM_CHANNELS 1 // old, remove this + +#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // 8-bit PWM on main2 +#define PWM2_DATATYPE uint16_t // dynamic PWM on led3 + led4 + +// dynamic PWM +#define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 511 // highest value used in top half of ramp +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +// main 2 LEDs / 1st channel (2 LEDs) +#define MAIN2_PWM_PIN PC0 +#define MAIN2_PWM_LVL OCR0A // OCR0A is the output compare register for PC0 +#define MAIN2_ENABLE_PIN PB0 // Opamp power +#define MAIN2_ENABLE_PORT PORTB // control port for PB0 + +// LED 3 / 2nd channel (1 LED) +#define LED3_PWM_PIN PB3 +#define LED3_PWM_LVL OCR1A // OCR1A is the output compare register for PB3 +#define LED3_ENABLE_PIN PA1 // Opamp power +#define LED3_ENABLE_PORT PORTA // control port for PA1 + +// LED 4 / 3rd channel (1 LED) +// 8-bit PWM only on OCR0A :( +#define LED4_PWM_PIN PA6 +#define LED4_PWM_LVL OCR1B // OCR1B is the output compare register for PA6 +#define LED4_ENABLE_PIN PA0 // Opamp power +#define LED4_ENABLE_PORT PORTA // control port for PA0 + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PA7 // pin 20 +#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt +#define SWITCH_PCIE PCIE0 // PCIE1 is for PCINT[7:0] +#define SWITCH_PCMSK PCMSK0 // PCMSK1 is for PCINT[7:0] +#define SWITCH_PORT PINA // PINA or PINB or PINC +#define SWITCH_PUE PUEA // pullup group A +#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] +#endif + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 +// pin to ADC mappings are in DS table 19-4 +#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 +// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 +#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D +// DS tables 19-3, 19-4 +// Bit 7 6 5 4 3 2 1 0 +// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 +// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 +// divided by ... +// REFS[1:0] = 1, 0 for internal 1.1V reference +// other bits reserved +#define ADMUX_VOLTAGE_DIVIDER 0b10000110 +#define ADC_PRSCL 0x07 // clk/128 + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// D1, R1, R2 = 0, 330, 100 +#ifndef ADC_44 +//#define ADC_44 981 // raw value at 4.40V +#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 +#endif +#ifndef ADC_22 +//#define ADC_22 489 // raw value at 2.20V +#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 +#endif + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + +#define BUTTON_LED_PIN PA2 // pin 5 +#define BUTTON_LED_PORT PORTA // for all "PA" pins +#define BUTTON_LED_DDR DDRA // for all "PA" pins +#define BUTTON_LED_PUE PUEA // for all "PA" pins + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS +// the aux LEDs are front-facing, so turn them off while main LEDs are on +// it also has an independent LED in the button +#define USE_BUTTON_LED + + +inline void hwdef_setup() { + // enable output ports + DDRC = (1 << MAIN2_PWM_PIN); + DDRB = (1 << LED3_PWM_PIN) + | (1 << MAIN2_ENABLE_PIN) + ; + DDRA = (1 << LED4_PWM_PIN) + | (1 << LED4_ENABLE_PIN) + | (1 << LED3_ENABLE_PIN) + | (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + | (1 << BUTTON_LED_PIN) + ; + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // Linear opamp PWM for both 16-bit channels + // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) + // WGM1[3:0]: 1,1,1,0: PWM, Fast, adjustable (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) + TCCR1A = (1< strobe on channel 2, 1 might not get turned off) --- hwdef-emisar-d4k-3ch.c | 33 +++++++++++++------- hwdef-emisar-d4k-3ch.h | 2 ++ spaghetti-monster/anduril/channel-modes.c | 51 +++++++++++++++++++++++++++++-- spaghetti-monster/anduril/channel-modes.h | 8 +++++ spaghetti-monster/fsm-channels.c | 11 +++++-- 5 files changed, 88 insertions(+), 17 deletions(-) diff --git a/hwdef-emisar-d4k-3ch.c b/hwdef-emisar-d4k-3ch.c index 1042d9e..1955b59 100644 --- a/hwdef-emisar-d4k-3ch.c +++ b/hwdef-emisar-d4k-3ch.c @@ -3,6 +3,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once +#include "spaghetti-monster/anduril/channel-modes.h" //for circular_tint_3h() #include "chan-rgbaux.c" @@ -69,15 +70,21 @@ Channel channels[] = { RGB_AUX_CHANNELS }; +// HSV mode needs a different 3H handler +StatePtr channel_3H_modes[NUM_CHANNEL_MODES] = { + NULL, NULL, NULL, NULL, + NULL, NULL, circular_tint_3h, NULL, +}; // LEDs 1+2 are 8-bit // this 8-bit channel may be LEDs 1+2 or LED 4, depending on wiring void set_level_main2(uint8_t level) { + LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off unused LEDs + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs + if (level == 0) { MAIN2_PWM_LVL = 0; MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp - LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp - LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp } else { level --; MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); @@ -87,12 +94,13 @@ void set_level_main2(uint8_t level) { // LED 3 is 16-bit void set_level_led3(uint8_t level) { + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs + if (level == 0) { LED3_PWM_LVL = 0; PWM_CNT = 0; - MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp - LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp } else { level --; LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN); @@ -106,11 +114,12 @@ void set_level_led3(uint8_t level) { // this 16-bit channel may be LED 4 or LEDs 1+2, depending on wiring void set_level_led4(uint8_t level) { + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs + LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off unused LEDs + if (level == 0) { LED4_PWM_LVL = 0; PWM_CNT = 0; // reset phase - MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp - LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp } else { level --; // PWM array index = level - 1 @@ -159,11 +168,12 @@ void set_level_all(uint8_t level) { // 8/16/16 wiring, mix 16+16 void set_level_led34a_blend(uint8_t level) { + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs + if (level == 0) { LED3_PWM_LVL = 0; LED4_PWM_LVL = 0; PWM_CNT = 0; // reset phase - MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp return; @@ -189,13 +199,14 @@ void set_level_led34a_blend(uint8_t level) { // 16/16/8 wiring, mix 16+8 void set_level_led34b_blend(uint8_t level) { + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs + if (level == 0) { - LED3_PWM_LVL = 0; - LED4_PWM_LVL = 0; - PWM_CNT = 0; // reset phase + MAIN2_PWM_LVL = 0; + LED3_PWM_LVL = 0; + PWM_CNT = 0; // reset phase MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp - LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp return; } diff --git a/hwdef-emisar-d4k-3ch.h b/hwdef-emisar-d4k-3ch.h index 4a3134e..538e3f6 100644 --- a/hwdef-emisar-d4k-3ch.h +++ b/hwdef-emisar-d4k-3ch.h @@ -72,6 +72,8 @@ enum channel_modes_e { #define USE_CHANNEL_MODE_ARGS // _, _, _, _, 128=middle CCT, 128=middle CCT, 213=purple, _ #define CHANNEL_MODE_ARGS 0,0,0,0,128,128,213,0,RGB_AUX_CM_ARGS +#define USE_CUSTOM_CHANNEL_3H_MODES +#define USE_CIRCULAR_TINT_3H // can use some of the common handlers #define USE_CALC_2CH_BLEND diff --git a/spaghetti-monster/anduril/channel-modes.c b/spaghetti-monster/anduril/channel-modes.c index f7e90bd..b2fc8d1 100644 --- a/spaghetti-monster/anduril/channel-modes.c +++ b/spaghetti-monster/anduril/channel-modes.c @@ -53,10 +53,12 @@ uint8_t channel_mode_state(Event event, uint16_t arg) { #ifdef USE_CUSTOM_CHANNEL_3H_MODES // defer to mode-specific function if defined - if (tint_ramp_modes[channel_mode]) { + if (channel_3H_modes[channel_mode]) { StatePtr tint_func = channel_3H_modes[channel_mode]; - return tint_func(channel_mode); - } else + uint8_t err = tint_func(event, arg); + if (EVENT_HANDLED == err) return EVENT_HANDLED; + // else let the default handler run + } #endif #ifdef USE_CHANNEL_MODE_ARGS #ifndef DONT_USE_DEFAULT_CHANNEL_ARG_MODE @@ -190,3 +192,46 @@ uint8_t nearest_tint_value(const int16_t target) { } #endif +#ifdef USE_CIRCULAR_TINT_3H +uint8_t circular_tint_3h(Event event, uint16_t arg) { + static int8_t tint_ramp_direction = 1; + // bugfix: click-click-hold from off to strobes would invoke tint ramping + // in addition to changing state... so ignore any tint-ramp events which + // don't look like they were meant to be here + static uint8_t active = 0; + uint8_t tint = cfg.channel_mode_args[channel_mode]; + + // click, click, hold: change the current channel's arg (like tint) + if (event == EV_click3_hold) { + ///// adjust value from 0 to 255 in a circle + // reset at beginning of movement + if (! arg) { + active = 1; // first frame means this is for us + } + // ignore event if we weren't the ones who handled the first frame + if (! active) return EVENT_NOT_HANDLED; + + // smooth tint ramping only + tint += tint_ramp_direction; + + cfg.channel_mode_args[channel_mode] = tint; + set_level(actual_level); + return EVENT_HANDLED; + } + + // click, click, hold, release: reverse direction for next ramp + else if (event == EV_click3_hold_release) { + active = 0; // ignore next hold if it wasn't meant for us + // reverse + tint_ramp_direction = -tint_ramp_direction; + // remember tint after battery change + save_config(); + // bug?: for some reason, brightness can seemingly change + // from 1/150 to 2/150 without this next line... not sure why + set_level(actual_level); + return EVENT_HANDLED; + } + + return EVENT_NOT_HANDLED; +} +#endif diff --git a/spaghetti-monster/anduril/channel-modes.h b/spaghetti-monster/anduril/channel-modes.h index 4c16281..b51721d 100644 --- a/spaghetti-monster/anduril/channel-modes.h +++ b/spaghetti-monster/anduril/channel-modes.h @@ -16,3 +16,11 @@ uint8_t channel_mode_config_state(Event event, uint16_t arg); uint8_t nearest_tint_value(const int16_t target); #endif +#ifdef USE_CUSTOM_CHANNEL_3H_MODES +StatePtr channel_3H_modes[NUM_CHANNEL_MODES]; +#endif + +#ifdef USE_CIRCULAR_TINT_3H +uint8_t circular_tint_3h(Event event, uint16_t arg); +#endif + diff --git a/spaghetti-monster/fsm-channels.c b/spaghetti-monster/fsm-channels.c index 944bdcb..69add93 100644 --- a/spaghetti-monster/fsm-channels.c +++ b/spaghetti-monster/fsm-channels.c @@ -86,21 +86,26 @@ void calc_2ch_blend( RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v) { RGB_t color; - uint16_t region, fpart, high, low, rising, falling; - if (s == 0) { // grey color.r = color.g = color.b = v; return color; } - // make hue 0-5 + uint8_t region; + uint16_t fpart; + uint16_t high, low, rising, falling; + + // hue has 6 segments, 0-5 region = ((uint16_t)h * 6) >> 8; // find remainder part, make it from 0-255 fpart = ((uint16_t)h * 6) - (region << 8); // calculate graph segments, doing integer multiplication + // TODO: calculate 16-bit results, not 8-bit high = v; low = (v * (255 - s)) >> 8; + // TODO: use a cosine crossfade instead of linear + // (because it looks better and feels more natural) falling = (v * (255 - ((s * fpart) >> 8))) >> 8; rising = (v * (255 - ((s * (255 - fpart)) >> 8))) >> 8; -- cgit v1.2.3 From 9e5f2dacebf880f61671974ddd8f604cf1782f37 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 25 Aug 2023 17:27:43 -0600 Subject: started splitting set_level(0) into its own set_level_zero(), and made USE_AUX_RGB_LEDS_WHILE_ON work more like the old indicator LEDs, where it gets set automatically with set_level() Using set_level_zero() reduces space used by channel modes, and simplifies code for each mode's set_level_*() functions. I measured about 220 bytes less in the emisar-d4k-3ch build this way, while also reducing the chance of bugs. --- hwdef-emisar-d4k-3ch.c | 132 ++++++------------------- spaghetti-monster/anduril/anduril.c | 2 +- spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h | 2 +- spaghetti-monster/fsm-ramping.c | 33 ++++++- spaghetti-monster/fsm-ramping.h | 1 + 5 files changed, 64 insertions(+), 106 deletions(-) diff --git a/hwdef-emisar-d4k-3ch.c b/hwdef-emisar-d4k-3ch.c index 1955b59..ac9c597 100644 --- a/hwdef-emisar-d4k-3ch.c +++ b/hwdef-emisar-d4k-3ch.c @@ -76,20 +76,26 @@ StatePtr channel_3H_modes[NUM_CHANNEL_MODES] = { NULL, NULL, circular_tint_3h, NULL, }; +void set_level_zero() { + // turn off all LEDs + MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); + LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); + LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); + MAIN2_PWM_LVL = 0; + LED3_PWM_LVL = 0; + LED4_PWM_LVL = 0; + PWM_CNT = 0; + PWM_TOP = PWM_TOP_INIT; +} + // LEDs 1+2 are 8-bit // this 8-bit channel may be LEDs 1+2 or LED 4, depending on wiring void set_level_main2(uint8_t level) { LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off unused LEDs LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs - if (level == 0) { - MAIN2_PWM_LVL = 0; - MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp - } else { - level --; - MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); - MAIN2_PWM_LVL = PWM_GET8(pwm1_levels, level); - } + MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); + MAIN2_PWM_LVL = PWM_GET8(pwm1_levels, level); } // LED 3 is 16-bit @@ -97,19 +103,12 @@ void set_level_led3(uint8_t level) { MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs - if (level == 0) { - LED3_PWM_LVL = 0; - PWM_CNT = 0; - LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp - } else { - level --; - LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN); - LED3_PWM_LVL = PWM_GET16(pwm2_levels, level); - uint16_t top = PWM_GET16(pwm_tops, level); - while(actual_level && (PWM_CNT > (top - 32))) {} - PWM_TOP = top; - if (! actual_level) PWM_CNT = 0; - } + LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN); + LED3_PWM_LVL = PWM_GET16(pwm2_levels, level); + uint16_t top = PWM_GET16(pwm_tops, level); + while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + if (! actual_level) PWM_CNT = 0; } // this 16-bit channel may be LED 4 or LEDs 1+2, depending on wiring @@ -117,40 +116,20 @@ void set_level_led4(uint8_t level) { MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off unused LEDs - if (level == 0) { - LED4_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp - } else { - level --; // PWM array index = level - 1 - // gotta turn on the opamp before light can come out - LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN); - LED4_PWM_LVL = PWM_GET16(pwm2_levels, level); - // pulse frequency modulation, a.k.a. dynamic PWM - uint16_t top = PWM_GET16(pwm_tops, level); - // wait to sync the counter and avoid flashes - while(actual_level && (PWM_CNT > (top - 32))) {} - PWM_TOP = top; - // force reset phase when turning on from zero - // (because otherwise the initial response is inconsistent) - if (! actual_level) PWM_CNT = 0; - } + // gotta turn on the opamp before light can come out + LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN); + LED4_PWM_LVL = PWM_GET16(pwm2_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET16(pwm_tops, level); + // wait to sync the counter and avoid flashes + while(actual_level && (PWM_CNT > (top - 32))) {} + PWM_TOP = top; + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; } void set_level_all(uint8_t level) { - if (level == 0) { - MAIN2_PWM_LVL = 0; - LED3_PWM_LVL = 0; - LED4_PWM_LVL = 0; - PWM_CNT = 0; - MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp - LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp - LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp - return; - } - - level --; - MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN ); LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN ); @@ -170,17 +149,6 @@ void set_level_all(uint8_t level) { void set_level_led34a_blend(uint8_t level) { MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs - if (level == 0) { - LED3_PWM_LVL = 0; - LED4_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp - LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp - return; - } - - level --; // PWM array index = level - 1 - PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE brightness = PWM_GET16(pwm2_levels, level); PWM_DATATYPE top = PWM_GET16(pwm_tops, level); @@ -201,17 +169,6 @@ void set_level_led34a_blend(uint8_t level) { void set_level_led34b_blend(uint8_t level) { LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs - if (level == 0) { - MAIN2_PWM_LVL = 0; - LED3_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp - LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp - return; - } - - level --; - const uint16_t top = 2047; uint16_t warm_PWM, cool_PWM; // 11 bits, 8 bits uint8_t blend = cfg.channel_mode_args[channel_mode]; @@ -236,20 +193,6 @@ void set_level_led34b_blend(uint8_t level) { } void set_level_hsv(uint8_t level) { - // TODO: implement a custom 3H handler which wraps around 0 to 255 - if (level == 0) { - MAIN2_PWM_LVL = 0; - LED3_PWM_LVL = 0; - LED4_PWM_LVL = 0; - PWM_CNT = 0; - MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp - LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp - LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp - return; - } - - level --; - RGB_t color; uint8_t h = cfg.channel_mode_args[channel_mode]; uint8_t s = 255; // TODO: drop saturation at brightest levels @@ -304,19 +247,6 @@ void calc_auto_3ch_blend( // 3-channel "auto tint" channel mode void set_level_auto3(uint8_t level) { - if (level == 0) { - MAIN2_PWM_LVL = 0; - LED3_PWM_LVL = 0; - LED4_PWM_LVL = 0; - PWM_CNT = 0; - MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off opamp - LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off opamp - LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off opamp - return; - } - - level --; - uint16_t a, b; uint8_t c; calc_auto_3ch_blend(&a, &b, &c, level); diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index ab43df6..6399ef6 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -267,7 +267,7 @@ void loop() { #ifdef USE_AUX_RGB_LEDS_WHILE_ON // display battery charge on RGB button during use - if (! setting_rgb_mode_now) + if (state == steady_state) rgb_led_voltage_readout(actual_level > USE_AUX_RGB_LEDS_WHILE_ON); #endif diff --git a/spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h b/spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h index 46d5796..c015295 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h @@ -13,7 +13,7 @@ // turn on the aux LEDs while main LEDs are on // (in case there's a RGB button) -#define USE_AUX_RGB_LEDS_WHILE_ON 20 +#define USE_AUX_RGB_LEDS_WHILE_ON 25 #define USE_INDICATOR_LED_WHILE_RAMPING // channel modes... diff --git a/spaghetti-monster/fsm-ramping.c b/spaghetti-monster/fsm-ramping.c index a970f0e..89f540b 100644 --- a/spaghetti-monster/fsm-ramping.c +++ b/spaghetti-monster/fsm-ramping.c @@ -36,6 +36,25 @@ inline void set_level_aux_leds(uint8_t level) { } #endif // ifdef HAS_AUX_LEDS +#ifdef USE_AUX_RGB_LEDS_WHILE_ON +// TODO: maybe move this stuff into FSM +#include "anduril/aux-leds.h" // for rgb_led_voltage_readout() +inline void set_level_aux_rgb_leds(uint8_t level) { + if (! go_to_standby) { + if (level > 0) { + rgb_led_voltage_readout(level > USE_AUX_RGB_LEDS_WHILE_ON); + } else { + rgb_led_set(0); + } + // some drivers can be wired with RGB or single color to button + // ... so support both even though only one is connected + #ifdef USE_BUTTON_LED + button_led_set((level > 0) + (level > DEFAULT_LEVEL)); + #endif + } +} +#endif // ifdef USE_AUX_RGB_LEDS_WHILE_ON + void set_level(uint8_t level) { #ifdef USE_JUMP_START @@ -58,9 +77,17 @@ void set_level(uint8_t level) { set_level_aux_leds(level); #endif - // call the relevant hardware-specific set_level_*() - SetLevelFuncPtr set_level_func = channels[channel_mode].set_level; - set_level_func(level); + #ifdef USE_AUX_RGB_LEDS_WHILE_ON + set_level_aux_rgb_leds(level); + #endif + + if (0 == level) { + set_level_zero(); + } else { + // call the relevant hardware-specific set_level_*() + SetLevelFuncPtr set_level_func = channels[channel_mode].set_level; + set_level_func(level - 1); + } if (actual_level != level) prev_level = actual_level; actual_level = level; diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index cae9a4d..bfcc5fb 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -13,6 +13,7 @@ uint8_t prev_level = 0; void set_level(uint8_t level); //void set_level_smooth(uint8_t level); +void set_level_zero(); // implement this in a hwdef #ifdef USE_SET_LEVEL_GRADUALLY // adjust brightness very smoothly -- cgit v1.2.3 From 8dd48059dd52fce67e785f325fae6ad4f1a1e473 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 25 Aug 2023 17:38:30 -0600 Subject: fixed bug: post-off voltage used low brightness sometimes even when regular aux setting was high --- spaghetti-monster/anduril/aux-leds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/aux-leds.c b/spaghetti-monster/anduril/aux-leds.c index c784fd1..b8d6662 100644 --- a/spaghetti-monster/anduril/aux-leds.c +++ b/spaghetti-monster/anduril/aux-leds.c @@ -111,8 +111,8 @@ void rgb_led_update(uint8_t mode, uint16_t arg) { && (ticks_since_on < (cfg.post_off_voltage * SLEEP_TICKS_PER_SECOND)) && (ticks_since_on > 0) // don't blink red on 1st frame ) { - // use high mode unless prev_level was really low - pattern = 1 + (prev_level >= POST_OFF_VOLTAGE_BRIGHTNESS); + // use high mode if regular aux level is high or prev level was high + pattern = 1 + ((2 == pattern) | (prev_level >= POST_OFF_VOLTAGE_BRIGHTNESS)); // voltage mode color = RGB_LED_NUM_COLORS - 1; } -- cgit v1.2.3 From c9923487744502a7005cece782c55572418412fc Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 25 Aug 2023 18:41:39 -0600 Subject: emisar-d4k-3ch auto-tint mode: fixed issue with LEDs turning off at moon, and changed algorithm to two simple crossfades instead of one funky and probably incorrect crossfade with an extra triangle in the middle (but it may be best to convert to sine-shaped crossfades instead of linear) (I can't really test this one very will since I don't have D4K hardware with red+warm+cool LEDs, so I'm guessing based on my unbalanced RGB model with the LEDs in the wrong order) --- hwdef-emisar-d4k-3ch.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/hwdef-emisar-d4k-3ch.c b/hwdef-emisar-d4k-3ch.c index ac9c597..8c46003 100644 --- a/hwdef-emisar-d4k-3ch.c +++ b/hwdef-emisar-d4k-3ch.c @@ -228,18 +228,24 @@ void calc_auto_3ch_blend( // tint goes from 0 (red) to 127 (warm white) to 255 (cool white) uint8_t mytint; - mytint = 255 * (uint16_t)level / RAMP_SIZE; + mytint = 255 * (uint16_t)(level+1) / RAMP_SIZE; + + uint8_t falling=0, rising=0; + if (level < (RAMP_SIZE/2)) + falling = 255 - triangle_wave(mytint); + else + rising = 255 - triangle_wave(mytint); // TODO: make "a" drop to zero sooner, and "c" start ramping up later // red is high at 0, low at 255 (linear) - *a = (((PWM_DATATYPE2)(255 - mytint) + *a = (((PWM_DATATYPE2)falling * (PWM_DATATYPE2)vpwm) + 127) / 255; // warm white is low at 0 and 255, high at 127 (linear triangle) *b = (((PWM_DATATYPE2)triangle_wave(mytint) - * (PWM_DATATYPE2)vpwm) + 127) / 255; + * (PWM_DATATYPE2)vpwm) ) / 255; // cool white is low at 0, high at 255 (linear) *c = (uint8_t)( - (((PWM_DATATYPE2)mytint + (((PWM_DATATYPE2)rising * (PWM_DATATYPE2)vpwm8) + 127) / 255 ); @@ -254,7 +260,8 @@ void set_level_auto3(uint8_t level) { // pulse frequency modulation, a.k.a. dynamic PWM uint16_t top = PWM_GET(pwm_tops, level); - if (a > 0) LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN ); + if ((a > 0) || (0 == level)) // don't turn off at bottom level + LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN ); else LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); if (b > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN ); else LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); -- cgit v1.2.3 From 4ac24a31fc3a9091c712e2c81f9871512d86893d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 26 Aug 2023 19:09:00 -0600 Subject: updated wurkkos-ts25 to use set_level_zero() (mostly as a quick test, will do the rest of the builds later) --- hwdef-wurkkos-ts25.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/hwdef-wurkkos-ts25.c b/hwdef-wurkkos-ts25.c index 7ae7b28..3c98716 100644 --- a/hwdef-wurkkos-ts25.c +++ b/hwdef-wurkkos-ts25.c @@ -6,6 +6,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_main(uint8_t level); bool gradual_tick_main(uint8_t gt); @@ -19,16 +21,15 @@ Channel channels[] = { }; +void set_level_zero() { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; // reset phase + return; +} + // single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear void set_level_main(uint8_t level) { - if (level == 0) { - CH1_PWM = 0; - CH2_PWM = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); // pulse frequency modulation, a.k.a. dynamic PWM -- cgit v1.2.3 From 6cd2bb9953e2dcfd025b24a7f555996b04717cb0 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 26 Aug 2023 19:40:48 -0600 Subject: made bike strobe ontime configurable per build, and made it longer on emisar-d4k-3ch because some channels don't flash fast enough --- spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h | 2 ++ spaghetti-monster/anduril/strobe-modes.c | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h b/spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h index c015295..1943838 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h @@ -85,6 +85,8 @@ #define STROBE_BRIGHTNESS MAX_LEVEL // slow down party strobe; this driver can't pulse for 1ms or less #define PARTY_STROBE_ONTIME 2 +// bike strobe needs a longer pulse too +#define BIKE_STROBE_ONTIME 8 // the default of 26 looks a bit flat, so increase it #define CANDLE_AMPLITUDE 33 diff --git a/spaghetti-monster/anduril/strobe-modes.c b/spaghetti-monster/anduril/strobe-modes.c index 1e6f98c..31d2aad 100644 --- a/spaghetti-monster/anduril/strobe-modes.c +++ b/spaghetti-monster/anduril/strobe-modes.c @@ -303,13 +303,16 @@ inline void lightning_storm_iter() { #endif #ifdef USE_BIKE_FLASHER_MODE +#ifndef BIKE_STROBE_ONTIME +#define BIKE_STROBE_ONTIME 0 +#endif inline void bike_flasher_iter() { // one iteration of main loop() uint8_t burst = cfg.bike_flasher_brightness << 1; if (burst > MAX_LEVEL) burst = MAX_LEVEL; for(uint8_t i=0; i<4; i++) { set_level(burst); - nice_delay_ms(5); + nice_delay_ms(5 + BIKE_STROBE_ONTIME); set_level(cfg.bike_flasher_brightness); nice_delay_ms(65); } -- cgit v1.2.3 From f245a903db3ff4a693f2874957cd9a671c5e2331 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 26 Aug 2023 19:42:04 -0600 Subject: added "smooth steps" a.k.a. "soft start", to make brightness steps smoother (also made ramp extras config menu count its own steps) --- spaghetti-monster/anduril/anduril-manual.txt | 9 +++++ spaghetti-monster/anduril/anduril.c | 14 ++++++++ spaghetti-monster/anduril/config-default.h | 8 +++++ spaghetti-monster/anduril/load-save-config-fsm.h | 5 +++ spaghetti-monster/anduril/load-save-config.h | 5 +++ spaghetti-monster/anduril/off-mode.c | 30 +++++++++++++--- spaghetti-monster/anduril/ramp-mode.c | 44 +++++++++++++++++------ spaghetti-monster/anduril/ramp-mode.h | 21 ++++++++++- spaghetti-monster/anduril/smooth-steps.c | 45 ++++++++++++++++++++++++ spaghetti-monster/anduril/smooth-steps.h | 19 ++++++++++ 10 files changed, 184 insertions(+), 16 deletions(-) create mode 100644 spaghetti-monster/anduril/smooth-steps.c create mode 100644 spaghetti-monster/anduril/smooth-steps.h diff --git a/spaghetti-monster/anduril/anduril-manual.txt b/spaghetti-monster/anduril/anduril-manual.txt index 1d5bc46..d47cc57 100644 --- a/spaghetti-monster/anduril/anduril-manual.txt +++ b/spaghetti-monster/anduril/anduril-manual.txt @@ -222,6 +222,9 @@ While the light is on, a few actions are available: 2: Anduril 2 style. Ramp -> 2C goes to ceiling, or goes to full power if user ramped up to ceiling first. This value also affects momentary turbo in Ramp and Off modes. + - Item 5: Configure "smooth steps". + 0: Disable smooth steps. + 1: Enable smooth steps. Memory determines which brightness level the light goes to with 1 click from off. There are three types of brightness memory to choose from: @@ -252,6 +255,11 @@ To choose a memory style, set the configuration accordingly: manual on zero hybrid on non-zero +If "smooth steps" is enabled, the stepped ramp uses a smooth animation +between steps, and turning the light on/off has the edges smoothed off +too. With "smooth steps" turned off, these brightness changes are +immediate. + Sunset Timer ------------ @@ -904,6 +912,7 @@ Ramp Full 10H Ramp Extras config menu: 2: set manual mem timeout 3: ramp after moon or not 4: advanced UI turbo style + 5: smooth steps Multi-channel lights only: Any Any 3C Next channel mode (i.e. next color mode) diff --git a/spaghetti-monster/anduril/anduril.c b/spaghetti-monster/anduril/anduril.c index 6399ef6..e46eeaf 100644 --- a/spaghetti-monster/anduril/anduril.c +++ b/spaghetti-monster/anduril/anduril.c @@ -142,6 +142,10 @@ #include "sos-mode.h" #endif +#ifdef USE_SMOOTH_STEPS +#include "smooth-steps.h" +#endif + // this should be last, so other headers have a chance to declare values #include "load-save-config.h" @@ -205,6 +209,10 @@ #include "sos-mode.c" #endif +#ifdef USE_SMOOTH_STEPS +#include "smooth-steps.c" +#endif + // runs one time at boot, when power is connected void setup() { @@ -335,6 +343,12 @@ void loop() { } #endif + #ifdef USE_SMOOTH_STEPS + else if (cfg.smooth_steps_style && smooth_steps_in_progress) { + smooth_steps_iter(); + } + #endif + #ifdef USE_IDLE_MODE else { // doze until next clock tick diff --git a/spaghetti-monster/anduril/config-default.h b/spaghetti-monster/anduril/config-default.h index 8f07e47..b66a645 100644 --- a/spaghetti-monster/anduril/config-default.h +++ b/spaghetti-monster/anduril/config-default.h @@ -187,3 +187,11 @@ #define USE_STEPPED_TINT_RAMPING #define DEFAULT_TINT_RAMP_STYLE 0 // smooth +// Use "smooth steps" to soften on/off and step changes +// on MCUs with enough room for extra stuff like this +#if (ATTINY==1616) || (ATTINY==1634) +#define USE_SMOOTH_STEPS +#endif +// 0 = none, 1 = smooth, 2+ = undefined +#define DEFAULT_SMOOTH_STEPS_STYLE 1 + diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h index 7bf87f4..0a9cabd 100644 --- a/spaghetti-monster/anduril/load-save-config-fsm.h +++ b/spaghetti-monster/anduril/load-save-config-fsm.h @@ -67,6 +67,11 @@ typedef struct Config { #endif #endif + ///// Smooth animation between steps, and for on/off + #ifdef USE_SMOOTH_STEPS + uint8_t smooth_steps_style; + #endif + ///// strobe / blinky mode settings #ifdef USE_STROBE_STATE uint8_t strobe_type; diff --git a/spaghetti-monster/anduril/load-save-config.h b/spaghetti-monster/anduril/load-save-config.h index 2dfa8c9..c70bb2b 100644 --- a/spaghetti-monster/anduril/load-save-config.h +++ b/spaghetti-monster/anduril/load-save-config.h @@ -94,6 +94,11 @@ Config cfg = { #endif #endif + ///// Smooth animation between steps, and for on/off + #ifdef USE_SMOOTH_STEPS + .smooth_steps_style = DEFAULT_SMOOTH_STEPS_STYLE, + #endif + ///// strobe / blinky mode settings #ifdef USE_STROBE_STATE diff --git a/spaghetti-monster/anduril/off-mode.c b/spaghetti-monster/anduril/off-mode.c index a484f06..af09d70 100644 --- a/spaghetti-monster/anduril/off-mode.c +++ b/spaghetti-monster/anduril/off-mode.c @@ -14,6 +14,12 @@ uint8_t off_state(Event event, uint16_t arg) { // turn emitter off when entering state if (event == EV_enter_state) { + #ifdef USE_SMOOTH_STEPS + if (cfg.smooth_steps_style && actual_level) { + set_level_smooth(0, 8); + arg = 1; // don't go to sleep immediately + } else + #endif set_level(0); ticks_since_on = 0; #if NUM_CHANNEL_MODES > 1 @@ -24,7 +30,8 @@ uint8_t off_state(Event event, uint16_t arg) { // redundant, sleep tick does the same thing //indicator_led_update(cfg.indicator_led_mode & 0x03, 0); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(cfg.rgb_led_off_mode, 0); + // redundant, sleep tick does the same thing + //rgb_led_update(cfg.rgb_led_off_mode, 0); #endif #ifdef USE_SUNSET_TIMER sunset_timer = 0; // needs a reset in case previous timer was aborted @@ -37,13 +44,18 @@ uint8_t off_state(Event event, uint16_t arg) { // go back to sleep eventually if we got bumped but didn't leave "off" state else if (event == EV_tick) { - if (arg > HOLD_TIMEOUT) { + if (arg > HOLD_TIMEOUT + #ifdef USE_SMOOTH_STEPS + && (! smooth_steps_in_progress) + #endif + ) { go_to_standby = 1; #ifdef USE_INDICATOR_LED // redundant, sleep tick does the same thing //indicator_led_update(cfg.indicator_led_mode & 0x03, arg); #elif defined(USE_AUX_RGB_LEDS) - rgb_led_update(cfg.rgb_led_off_mode, arg); + // redundant, sleep tick does the same thing + //rgb_led_update(cfg.rgb_led_off_mode, arg); #endif } return EVENT_HANDLED; @@ -127,6 +139,11 @@ uint8_t off_state(Event event, uint16_t arg) { manual_memory_restore(); } #endif + #ifdef USE_SMOOTH_STEPS + if (cfg.smooth_steps_style) + set_level_smooth(nearest_level(memorized_level), 8); + else + #endif set_level(nearest_level(memorized_level)); return EVENT_HANDLED; } @@ -135,8 +152,7 @@ uint8_t off_state(Event event, uint16_t arg) { // 1 click: regular mode else if (event == EV_1click) { #if (B_TIMING_ON != B_TIMEOUT_T) - // brightness was already set; reuse previous value - set_state(steady_state, actual_level); + set_state(steady_state, memorized_level); #else // FIXME: B_TIMEOUT_T breaks manual_memory and manual_memory_timer // (need to duplicate manual mem logic here, probably) @@ -186,6 +202,10 @@ uint8_t off_state(Event event, uint16_t arg) { // 3 clicks (initial press): off, to prep for later events else if (event == EV_click3_press) { + #ifdef USE_SMOOTH_STEPS + // immediately cancel any animations in progress + smooth_steps_in_progress = 0; + #endif set_level(0); return EVENT_HANDLED; } diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index f21f599..c4c995f 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -10,6 +10,10 @@ #include "sunset-timer.h" #endif +#ifdef USE_SMOOTH_STEPS +#include "smooth-steps.h" +#endif + uint8_t steady_state(Event event, uint16_t arg) { static int8_t ramp_direction = 1; @@ -554,21 +558,25 @@ uint8_t simple_ui_config_state(Event event, uint16_t arg) { #ifdef USE_RAMP_EXTRAS_CONFIG void ramp_extras_config_save(uint8_t step, uint8_t value) { // item 1: disable manual memory, go back to automatic - if (1 == step) { cfg.manual_memory = 0; } + if (manual_memory_config_step == step) { + cfg.manual_memory = 0; + } #ifdef USE_MANUAL_MEMORY_TIMER // item 2: set manual memory timer duration // FIXME: should be limited to (65535 / SLEEP_TICKS_PER_MINUTE) // to avoid overflows or impossibly long timeouts // (by default, the effective limit is 145, but it allows up to 255) - else if (2 == step) { cfg.manual_memory_timer = value; } + else if (manual_memory_timer_config_step == step) { + cfg.manual_memory_timer = value; + } #endif #ifdef USE_RAMP_AFTER_MOON_CONFIG // item 3: ramp up after hold-from-off for moon? // 0 = yes, ramp after moon // 1+ = no, stay at moon - else if (3 == step) { + else if (dont_ramp_after_moon_config_step == step) { cfg.dont_ramp_after_moon = value; } #endif @@ -577,14 +585,22 @@ void ramp_extras_config_save(uint8_t step, uint8_t value) { // item 4: Anduril 1 2C turbo, or Anduril 2 2C ceiling? // 1 = Anduril 1, 2C turbo // 2+ = Anduril 2, 2C ceiling - else if (4 == step) { + else if (ramp_2c_style_config_step == step) { cfg.ramp_2c_style = value; } #endif + + #ifdef USE_SMOOTH_STEPS + else if (smooth_steps_style_config_step == step) { + cfg.smooth_steps_style = value; + } + #endif } uint8_t ramp_extras_config_state(Event event, uint16_t arg) { - return config_state_base(event, arg, 4, ramp_extras_config_save); + return config_state_base(event, arg, + ramp_extras_config_num_steps - 1, + ramp_extras_config_save); } #endif @@ -592,16 +608,17 @@ uint8_t ramp_extras_config_state(Event event, uint16_t arg) { void globals_config_save(uint8_t step, uint8_t value) { if (0) {} #if defined(USE_CHANNEL_MODE_ARGS) && defined(USE_STEPPED_TINT_RAMPING) - else if (step == 1+tint_style_config_step) { cfg.tint_ramp_style = value; } + else if (step == tint_style_config_step) { cfg.tint_ramp_style = value; } #endif #ifdef USE_JUMP_START - else if (step == 1+jump_start_config_step) { cfg.jump_start_level = value; } + else if (step == jump_start_config_step) { cfg.jump_start_level = value; } #endif } uint8_t globals_config_state(Event event, uint16_t arg) { - // TODO: set number of steps based on how many configurable options - return config_state_base(event, arg, globals_config_num_steps, globals_config_save); + return config_state_base(event, arg, + globals_config_num_steps - 1, + globals_config_save); } #endif @@ -657,9 +674,16 @@ void ramp_update_config() { ramp_ceil = cfg.ramp_ceils[which]; } -#ifdef USE_THERMAL_REGULATION +#if defined(USE_THERMAL_REGULATION) || defined(USE_SMOOTH_STEPS) void set_level_and_therm_target(uint8_t level) { + #ifdef USE_THERMAL_REGULATION target_level = level; + #endif + #ifdef USE_SMOOTH_STEPS + if (cfg.smooth_steps_style && cfg.ramp_style) + set_level_smooth(level, 4); + else + #endif set_level(level); } #else diff --git a/spaghetti-monster/anduril/ramp-mode.h b/spaghetti-monster/anduril/ramp-mode.h index 20986cc..21e2149 100644 --- a/spaghetti-monster/anduril/ramp-mode.h +++ b/spaghetti-monster/anduril/ramp-mode.h @@ -186,10 +186,29 @@ uint8_t sunset_timer_orig_level = 0; void reset_sunset_timer(); #endif +#ifdef USE_RAMP_EXTRAS_CONFIG +typedef enum { + manual_memory_config_step = 1, + #ifdef USE_MANUAL_MEMORY_TIMER + manual_memory_timer_config_step, + #endif + #ifdef USE_RAMP_AFTER_MOON_CONFIG + dont_ramp_after_moon_config_step, + #endif + #ifdef USE_2C_STYLE_CONFIG + ramp_2c_style_config_step, + #endif + #ifdef USE_SMOOTH_STEPS + smooth_steps_style_config_step, + #endif + ramp_extras_config_num_steps +} ramp_extras_config_steps_e; +#endif + #ifdef USE_GLOBALS_CONFIG typedef enum { #if defined(USE_CHANNEL_MODE_ARGS) && defined(USE_STEPPED_TINT_RAMPING) - tint_style_config_step, + tint_style_config_step = 1, #endif #ifdef USE_JUMP_START jump_start_config_step, diff --git a/spaghetti-monster/anduril/smooth-steps.c b/spaghetti-monster/anduril/smooth-steps.c new file mode 100644 index 0000000..9a09228 --- /dev/null +++ b/spaghetti-monster/anduril/smooth-steps.c @@ -0,0 +1,45 @@ +// smooth-steps.c: Smooth step adjustments for Anduril. +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "smooth-steps.h" + +#ifdef USE_SMOOTH_STEPS + +// one iteration of main loop() +void smooth_steps_iter() { + if (actual_level == smooth_steps_target) { + smooth_steps_in_progress = 0; + // restore prev_level when animation ends + prev_level = smooth_steps_start; + return; + } + + if (actual_level < smooth_steps_target) { + uint8_t diff = smooth_steps_target - actual_level; + uint8_t this = diff / smooth_steps_speed; + if (!this) this = 1; + set_level(actual_level + this); + } else if (actual_level > smooth_steps_target) { + uint8_t diff = actual_level - smooth_steps_target; + uint8_t this = diff / smooth_steps_speed; + if (!this) this = 1; + set_level(actual_level - this); + } + // TODO: maybe change the delay based on the speed var? + nice_delay_ms(10); +} + +void set_level_smooth(uint8_t level, uint8_t speed) { + smooth_steps_target = level; + // TODO: maybe speed should be a desired total time for the animation? + smooth_steps_speed = speed; + smooth_steps_in_progress = 1; + // for setting prev_level after animation ends + smooth_steps_start = actual_level; +} + +#endif + diff --git a/spaghetti-monster/anduril/smooth-steps.h b/spaghetti-monster/anduril/smooth-steps.h new file mode 100644 index 0000000..a553af2 --- /dev/null +++ b/spaghetti-monster/anduril/smooth-steps.h @@ -0,0 +1,19 @@ +// smooth-steps.h: Smooth step adjustments for Anduril. +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#ifdef USE_SMOOTH_STEPS + +uint8_t smooth_steps_start; +uint8_t smooth_steps_target; +uint8_t smooth_steps_in_progress; +uint8_t smooth_steps_speed; + +void smooth_steps_iter(); + +void set_level_smooth(uint8_t level, uint8_t speed); + +#endif + -- cgit v1.2.3 From d42a9ae7e04ec03ca3b89ace79812c4ea03d6e8a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 28 Aug 2023 14:52:49 -0600 Subject: made smooth steps look more natural (especially when turning off) by using different curves for ramp-up and ramp-down --- spaghetti-monster/anduril/smooth-steps.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/spaghetti-monster/anduril/smooth-steps.c b/spaghetti-monster/anduril/smooth-steps.c index 9a09228..b5ec0c4 100644 --- a/spaghetti-monster/anduril/smooth-steps.c +++ b/spaghetti-monster/anduril/smooth-steps.c @@ -14,28 +14,29 @@ void smooth_steps_iter() { smooth_steps_in_progress = 0; // restore prev_level when animation ends prev_level = smooth_steps_start; - return; } - - if (actual_level < smooth_steps_target) { + else if (smooth_steps_target > actual_level) { + // power-linear(ish) ascent + // (jump by ~20% of remaining distance on each frame) uint8_t diff = smooth_steps_target - actual_level; uint8_t this = diff / smooth_steps_speed; if (!this) this = 1; set_level(actual_level + this); - } else if (actual_level > smooth_steps_target) { - uint8_t diff = actual_level - smooth_steps_target; - uint8_t this = diff / smooth_steps_speed; - if (!this) this = 1; - set_level(actual_level - this); + nice_delay_ms(10); + } else { + // ramp-linear descent + // (jump by 1 on each frame, frame rate gives constant total time) + uint8_t diff = smooth_steps_start - smooth_steps_target; + uint16_t delay = 1 + (26 * smooth_steps_speed / diff); + set_level(actual_level - 1); + // TODO? if delay < one PWM cycle, this can look a little weird + nice_delay_ms(delay); } - // TODO: maybe change the delay based on the speed var? - nice_delay_ms(10); } void set_level_smooth(uint8_t level, uint8_t speed) { smooth_steps_target = level; - // TODO: maybe speed should be a desired total time for the animation? - smooth_steps_speed = speed; + smooth_steps_speed = speed; // higher = slower smooth_steps_in_progress = 1; // for setting prev_level after animation ends smooth_steps_start = actual_level; -- cgit v1.2.3 From 158ad8bc28a578874e0906c0f2416ef8e5fa8446 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 29 Aug 2023 12:55:27 -0600 Subject: renamed wurkkos-ts10-rgb to wurkkos-ts10-rgbaux (for consistency, and in case they ever make a full RGB version) (also, raised the post-off voltage brightness threshold, because these aux LEDs are pretty bright) (and updated the TS10 hwdef to the current API) --- hwdef-wurkkos-ts10.c | 16 ++-- spaghetti-monster/anduril/MODELS | 3 +- spaghetti-monster/anduril/cfg-wurkkos-ts10-rgb.h | 81 --------------------- .../anduril/cfg-wurkkos-ts10-rgbaux.h | 85 ++++++++++++++++++++++ 4 files changed, 95 insertions(+), 90 deletions(-) delete mode 100644 spaghetti-monster/anduril/cfg-wurkkos-ts10-rgb.h create mode 100644 spaghetti-monster/anduril/cfg-wurkkos-ts10-rgbaux.h diff --git a/hwdef-wurkkos-ts10.c b/hwdef-wurkkos-ts10.c index 44602c0..06f5bac 100644 --- a/hwdef-wurkkos-ts10.c +++ b/hwdef-wurkkos-ts10.c @@ -6,6 +6,8 @@ #include "chan-aux.c" +void set_level_zero(); + void set_level_main(uint8_t level); bool gradual_tick_main(uint8_t gt); @@ -22,16 +24,14 @@ Channel channels[] = { }; +void set_level_zero() { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; // reset phase +} + // single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear void set_level_main(uint8_t level) { - if (level == 0) { - CH1_PWM = 0; - CH2_PWM = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); // pulse frequency modulation, a.k.a. dynamic PWM diff --git a/spaghetti-monster/anduril/MODELS b/spaghetti-monster/anduril/MODELS index f46d2a3..97af879 100644 --- a/spaghetti-monster/anduril/MODELS +++ b/spaghetti-monster/anduril/MODELS @@ -21,6 +21,7 @@ Model Name MCU 0141 emisar-d18 attiny85 0142 emisar-d18-219 attiny85 0143 noctigon-m44 attiny1634 +0151 emisar-d4k-3ch attiny1634 0211 noctigon-kr4 attiny1634 0212 noctigon-kr4-nofet attiny1634 0213 noctigon-kr4-219 attiny1634 @@ -67,7 +68,7 @@ Model Name MCU 0623 sofirn-lt1s-pro attiny1616 0631 sofirn-sp10-pro attiny1616 0632 sofirn-sc21-pro attiny1616 -0713 wurkkos-ts10-rgb attiny1616 +0713 wurkkos-ts10-rgbaux attiny1616 0714 wurkkos-ts10 attiny1616 0715 wurkkos-ts25 attiny1616 0716 wurkkos-fc13 attiny1616 diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts10-rgb.h b/spaghetti-monster/anduril/cfg-wurkkos-ts10-rgb.h deleted file mode 100644 index b307491..0000000 --- a/spaghetti-monster/anduril/cfg-wurkkos-ts10-rgb.h +++ /dev/null @@ -1,81 +0,0 @@ -// Wurkkos TS10 (RGB aux version) config options for Anduril -// Copyright (C) 2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -// most things are the same as TS25 -#include "cfg-wurkkos-ts25.h" -#undef MODEL_NUMBER -#define MODEL_NUMBER "0713" -// ATTINY: 1616 - -///// apply some config from the TS10 ///// - -// use the TS10 ramp, not the TS25 ramp -#undef PWM1_LEVELS -#undef PWM2_LEVELS -#undef PWM_TOPS -#undef MAX_1x7135 -#undef MIN_THERM_STEPDOWN -#undef HALFSPEED_LEVEL -#undef QUARTERSPEED_LEVEL -#undef DEFAULT_LEVEL -#undef RAMP_SMOOTH_FLOOR -#undef RAMP_SMOOTH_CEIL -#undef RAMP_DISCRETE_FLOOR -#undef RAMP_DISCRETE_CEIL -#undef RAMP_DISCRETE_STEPS -#undef SIMPLE_UI_FLOOR -#undef SIMPLE_UI_CEIL -#undef SIMPLE_UI_STEPS -#undef THERM_FASTER_LEVEL - -// 7135 at 90/150 -// level_calc.py 5.7895 2 150 7135 0 0.1 125.25 FET 1 10 1200 --pwm dyn:61:4096:255:2.5 --clock 5:11:2.0 -// (with heavy manual tweaks up to ~15/150) -#define PWM1_LEVELS 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 8, 9, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 23, 24, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 35, 36, 37, 38, 40, 41, 43, 45, 47, 50, 53, 56, 60, 63, 67, 71, 75, 79, 84, 89, 94, 99,104,110,116,122,129,136,143,150,158,166,174,183,192,202,211,222,232,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 7, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 29, 31, 34, 37, 39, 42, 45, 48, 51, 54, 58, 61, 65, 68, 72, 76, 80, 84, 88, 93, 97,102,107,112,117,122,127,133,139,145,151,157,163,170,177,183,191,198,205,213,221,229,238,246,255 -#define PWM_TOPS 4095,2893,3917,2806,3252,2703,2684,2660,2640,2370,3000,2900,2630,2549,2246,2193,2030,1961,1889,1716,1642,1569,1497,1428,1290,1232,1176,1122,1070,976,932,890,849,779,745,685,656,605,579,536,514,476,457,424,407,379,364,340,327,314,302,291,280,276,266,262,257,253,253,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 -#define MAX_1x7135 90 -#define MIN_THERM_STEPDOWN 60 -#define HALFSPEED_LEVEL 11 -#define QUARTERSPEED_LEVEL 5 -#define DEFAULT_LEVEL 50 - -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 150 -// 20 38 56 [75] 93 111 130 -// 10 30 50 70 [90] 110 130 -#define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL 130 -#define RAMP_DISCRETE_STEPS 7 - -// at Wurkkos's request, reduce the Simple UI ceiling a little bit -// (i.e. not 150; original config had it at 144/150, or DD FET 204/255) -// 20 47 [75] 102 130 -// 10 30 50 70 [90] 110 130 -#define SIMPLE_UI_FLOOR 10 -#define SIMPLE_UI_CEIL 130 -#define SIMPLE_UI_STEPS 7 - -// stop panicking at ~50% power -#define THERM_FASTER_LEVEL 130 // throttle back faster when high - -// show each channel while it scroll by in the menu -#define USE_CONFIG_COLORS - -// blink numbers on the aux LEDs by default -#undef DEFAULT_BLINK_CHANNEL -#define DEFAULT_BLINK_CHANNEL CM_AUXWHT - -// the default of 26 looks a bit rough, so increase it to make it smoother -#define CANDLE_AMPLITUDE 33 - -// don't blink mid-ramp -#ifdef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_MIDDLE -#endif - -// enable factory reset on 13H without loosening tailcap (required) -#define USE_SOFT_FACTORY_RESET - diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts10-rgbaux.h b/spaghetti-monster/anduril/cfg-wurkkos-ts10-rgbaux.h new file mode 100644 index 0000000..4350828 --- /dev/null +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts10-rgbaux.h @@ -0,0 +1,85 @@ +// Wurkkos TS10 (RGB aux version) config options for Anduril +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// most things are the same as TS25 +#include "cfg-wurkkos-ts25.h" +#undef MODEL_NUMBER +#define MODEL_NUMBER "0713" +// ATTINY: 1616 + +///// apply some config from the TS10 ///// + +// use the TS10 ramp, not the TS25 ramp +#undef PWM1_LEVELS +#undef PWM2_LEVELS +#undef PWM_TOPS +#undef MAX_1x7135 +#undef MIN_THERM_STEPDOWN +#undef HALFSPEED_LEVEL +#undef QUARTERSPEED_LEVEL +#undef DEFAULT_LEVEL +#undef RAMP_SMOOTH_FLOOR +#undef RAMP_SMOOTH_CEIL +#undef RAMP_DISCRETE_FLOOR +#undef RAMP_DISCRETE_CEIL +#undef RAMP_DISCRETE_STEPS +#undef SIMPLE_UI_FLOOR +#undef SIMPLE_UI_CEIL +#undef SIMPLE_UI_STEPS +#undef THERM_FASTER_LEVEL + +// 7135 at 90/150 +// level_calc.py 5.7895 2 150 7135 0 0.1 125.25 FET 1 10 1200 --pwm dyn:61:4096:255:2.5 --clock 5:11:2.0 +// (with heavy manual tweaks up to ~15/150) +#define PWM1_LEVELS 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 8, 9, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 23, 24, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 35, 36, 37, 38, 40, 41, 43, 45, 47, 50, 53, 56, 60, 63, 67, 71, 75, 79, 84, 89, 94, 99,104,110,116,122,129,136,143,150,158,166,174,183,192,202,211,222,232,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 7, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 29, 31, 34, 37, 39, 42, 45, 48, 51, 54, 58, 61, 65, 68, 72, 76, 80, 84, 88, 93, 97,102,107,112,117,122,127,133,139,145,151,157,163,170,177,183,191,198,205,213,221,229,238,246,255 +#define PWM_TOPS 4095,2893,3917,2806,3252,2703,2684,2660,2640,2370,3000,2900,2630,2549,2246,2193,2030,1961,1889,1716,1642,1569,1497,1428,1290,1232,1176,1122,1070,976,932,890,849,779,745,685,656,605,579,536,514,476,457,424,407,379,364,340,327,314,302,291,280,276,266,262,257,253,253,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#define MAX_1x7135 90 +#define MIN_THERM_STEPDOWN 60 +#define HALFSPEED_LEVEL 11 +#define QUARTERSPEED_LEVEL 5 +#define DEFAULT_LEVEL 50 + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 150 +// 20 38 56 [75] 93 111 130 +// 10 30 50 70 [90] 110 130 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL 130 +#define RAMP_DISCRETE_STEPS 7 + +// at Wurkkos's request, reduce the Simple UI ceiling a little bit +// (i.e. not 150; original config had it at 144/150, or DD FET 204/255) +// 20 47 [75] 102 130 +// 10 30 50 70 [90] 110 130 +#define SIMPLE_UI_FLOOR 10 +#define SIMPLE_UI_CEIL 130 +#define SIMPLE_UI_STEPS 7 + +// stop panicking at ~50% power +#define THERM_FASTER_LEVEL 130 // throttle back faster when high + +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// blink numbers on the aux LEDs by default +#undef DEFAULT_BLINK_CHANNEL +#define DEFAULT_BLINK_CHANNEL CM_AUXWHT + +// the aux LEDs are pretty bright; set the high-mode threshold a bit higher +// (default is 15) +#define POST_OFF_VOLTAGE_BRIGHTNESS 25 + +// the default of 26 looks a bit rough, so increase it to make it smoother +#define CANDLE_AMPLITUDE 33 + +// don't blink mid-ramp +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + +// enable factory reset on 13H without loosening tailcap (required) +#define USE_SOFT_FACTORY_RESET + -- cgit v1.2.3 From 5de8ed98098d47647b403d9c78e217490922b3a7 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 8 Sep 2023 18:28:52 -0600 Subject: fixed soft start animation when using smooth ramp on turbo (it would jump up the last few levels before, instead of being smooth) --- spaghetti-monster/anduril/ramp-mode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index c4c995f..87bfe63 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -680,7 +680,8 @@ void set_level_and_therm_target(uint8_t level) { target_level = level; #endif #ifdef USE_SMOOTH_STEPS - if (cfg.smooth_steps_style && cfg.ramp_style) + if (smooth_steps_in_progress + || (cfg.smooth_steps_style && cfg.ramp_style)) set_level_smooth(level, 4); else #endif -- cgit v1.2.3 From de7f6f7719a2ef4c4bd07bf93938bf2ed92a7aee Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 17 Sep 2023 04:30:35 -0600 Subject: fixed bug: smooth steps could sometimes turn off entirely when bottom step was too low (stepped ramp floor 1/150 or 2/150), instead of just stepping down (this also seemed to affect 1C from Off, when at stepped ramp floor) (but it didn't affect the smooth ramp) --- spaghetti-monster/anduril/smooth-steps.c | 1 + 1 file changed, 1 insertion(+) diff --git a/spaghetti-monster/anduril/smooth-steps.c b/spaghetti-monster/anduril/smooth-steps.c index b5ec0c4..d907bc1 100644 --- a/spaghetti-monster/anduril/smooth-steps.c +++ b/spaghetti-monster/anduril/smooth-steps.c @@ -11,6 +11,7 @@ // one iteration of main loop() void smooth_steps_iter() { if (actual_level == smooth_steps_target) { + set_level(smooth_steps_target); smooth_steps_in_progress = 0; // restore prev_level when animation ends prev_level = smooth_steps_start; -- cgit v1.2.3 From d34d0e7acb1f1e49d21af7cf1c9e08161ce95dd4 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 17 Sep 2023 04:37:25 -0600 Subject: fixed builds which weren't using set_level_zero() yet... - emisar-d4 - emisar-d4v2 - emisar-d4v2-nofet - emisar-d4sv2 - emisar-2ch - emisar-2ch-fet - noctigon-dm11-boost - noctigon-k1 - noctigon-kr4 - noctigon-kr4-nofet - sofirn-lt1s-pro ... and removed old build targets for d4sv2-tintramp, because it was replaced by emisar-2ch a while ago. --- hwdef-emisar-2ch-fet.c | 26 ++----- hwdef-emisar-2ch.c | 26 ++----- hwdef-emisar-d4.c | 14 ++-- hwdef-emisar-d4sv2.c | 18 ++--- hwdef-emisar-d4v2-nofet.c | 14 ++-- hwdef-emisar-d4v2.c | 16 ++-- hwdef-noctigon-dm11-boost.c | 18 ++--- hwdef-noctigon-k1.c | 20 ++--- hwdef-noctigon-kr4-nofet.c | 18 ++--- hwdef-noctigon-kr4.c | 18 ++--- hwdef-sofirn-lt1s-pro.c | 62 ++++----------- .../anduril/cfg-emisar-d4sv2-tintramp-fet.h | 74 ------------------ .../anduril/cfg-emisar-d4sv2-tintramp.h | 88 ---------------------- spaghetti-monster/fsm-channels.c | 2 + spaghetti-monster/fsm-channels.h | 4 + 15 files changed, 101 insertions(+), 317 deletions(-) delete mode 100644 spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp-fet.h delete mode 100644 spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h diff --git a/hwdef-emisar-2ch-fet.c b/hwdef-emisar-2ch-fet.c index 7cf48d3..caf579d 100644 --- a/hwdef-emisar-2ch-fet.c +++ b/hwdef-emisar-2ch-fet.c @@ -7,6 +7,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_ch1(uint8_t level); void set_level_ch2(uint8_t level); void set_level_both(uint8_t level); @@ -92,11 +94,11 @@ void set_pwms(uint8_t ch1_pwm, uint8_t ch2_pwm, uint8_t ch3_pwm, uint16_t top) { if (! was_on) PWM_CNT = 0; } -void set_level_ch1(uint8_t level) { - if (0 == level) - return set_pwms(0, 0, 0, PWM_TOP_INIT); +void set_level_zero() { + return set_pwms(0, 0, 0, PWM_TOP_INIT); +} - level --; +void set_level_ch1(uint8_t level) { uint8_t pwm1 = PWM_GET8 (pwm1_levels, level); uint8_t pwm3 = PWM_GET8 (pwm2_levels, level); uint16_t top = PWM_GET16(pwm3_levels, level); @@ -104,20 +106,12 @@ void set_level_ch1(uint8_t level) { } void set_level_ch2(uint8_t level) { - if (0 == level) - return set_pwms(0, 0, 0, PWM_TOP_INIT); - - level --; uint8_t pwm2 = PWM_GET8 (pwm4_levels, level); uint16_t top = PWM_GET16(pwm5_levels, level); set_pwms(0, pwm2, 0, top); } void set_level_both(uint8_t level) { - if (0 == level) - return set_pwms(0, 0, 0, PWM_TOP_INIT); - - level --; uint8_t pwm1 = PWM_GET8 (pwm1_levels, level); uint8_t pwm3 = PWM_GET8 (pwm2_levels, level); uint16_t top = PWM_GET16(pwm3_levels, level); @@ -125,10 +119,6 @@ void set_level_both(uint8_t level) { } void set_level_blend(uint8_t level) { - if (0 == level) - return set_pwms(0, 0, 0, PWM_TOP_INIT); - - level --; uint16_t pwm1, pwm2; uint8_t pwm3 = PWM_GET8 (pwm2_levels, level); // DD FET //uint16_t brightness = PWM_GET8 (pwm1_levels, level) << 1; @@ -142,10 +132,6 @@ void set_level_blend(uint8_t level) { } void set_level_auto(uint8_t level) { - if (0 == level) - return set_pwms(0, 0, 0, PWM_TOP_INIT); - - level --; uint16_t pwm1, pwm2; uint8_t brightness = PWM_GET8 (pwm4_levels, level); uint16_t top = PWM_GET16(pwm5_levels, level); diff --git a/hwdef-emisar-2ch.c b/hwdef-emisar-2ch.c index 7955cf6..31d27af 100644 --- a/hwdef-emisar-2ch.c +++ b/hwdef-emisar-2ch.c @@ -7,6 +7,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_ch1(uint8_t level); void set_level_ch2(uint8_t level); void set_level_both(uint8_t level); @@ -90,41 +92,29 @@ void set_pwms(uint16_t ch1_pwm, uint16_t ch2_pwm, uint16_t top) { if (! was_on) PWM_CNT = 0; } -void set_level_ch1(uint8_t level) { - if (0 == level) - return set_pwms(0, 0, PWM_TOP_INIT); +void set_level_zero() { + return set_pwms(0, 0, PWM_TOP_INIT); +} - level --; +void set_level_ch1(uint8_t level) { uint16_t pwm = PWM_GET(pwm1_levels, level); uint16_t top = PWM_GET(pwm_tops, level); set_pwms(pwm, 0, top); } void set_level_ch2(uint8_t level) { - if (0 == level) - return set_pwms(0, 0, PWM_TOP_INIT); - - level --; uint16_t pwm = PWM_GET(pwm1_levels, level); uint16_t top = PWM_GET(pwm_tops, level); set_pwms(0, pwm, top); } void set_level_both(uint8_t level) { - if (0 == level) - return set_pwms(0, 0, PWM_TOP_INIT); - - level --; uint16_t pwm = PWM_GET(pwm1_levels, level); uint16_t top = PWM_GET(pwm_tops, level); set_pwms(pwm, pwm, top); } void set_level_blend(uint8_t level) { - if (0 == level) - return set_pwms(0, 0, PWM_TOP_INIT); - - level --; PWM_DATATYPE ch1_pwm, ch2_pwm; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); PWM_DATATYPE top = PWM_GET(pwm_tops, level); @@ -136,10 +126,6 @@ void set_level_blend(uint8_t level) { } void set_level_auto(uint8_t level) { - if (0 == level) - return set_pwms(0, 0, PWM_TOP_INIT); - - level --; PWM_DATATYPE ch1_pwm, ch2_pwm; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); PWM_DATATYPE top = PWM_GET(pwm_tops, level); diff --git a/hwdef-emisar-d4.c b/hwdef-emisar-d4.c index 6069530..972f682 100644 --- a/hwdef-emisar-d4.c +++ b/hwdef-emisar-d4.c @@ -11,6 +11,8 @@ #define AUX_CHANNELS #endif +void set_level_zero(); + void set_level_main(uint8_t level); bool gradual_tick_main(uint8_t gt); @@ -24,17 +26,15 @@ Channel channels[] = { }; +void set_level_zero() { + CH1_PWM = 0; + CH2_PWM = 0; +} + // TODO: implement delta-sigma modulation for better low modes // single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear void set_level_main(uint8_t level) { - if (level == 0) { - CH1_PWM = 0; - CH2_PWM = 0; - return; - } - - level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); diff --git a/hwdef-emisar-d4sv2.c b/hwdef-emisar-d4sv2.c index c19054e..6399fb8 100644 --- a/hwdef-emisar-d4sv2.c +++ b/hwdef-emisar-d4sv2.c @@ -6,6 +6,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_main(uint8_t level); bool gradual_tick_main(uint8_t gt); @@ -19,17 +21,15 @@ Channel channels[] = { }; +void set_level_zero() { + CH1_PWM = 0; + CH2_PWM = 0; + CH3_PWM = 0; + PWM_CNT = 0; // reset phase +} + // single set of LEDs with 3 stacked power channels, DDFET+3+1 void set_level_main(uint8_t level) { - if (level == 0) { - CH1_PWM = 0; - CH2_PWM = 0; - CH3_PWM = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); PWM_DATATYPE ch3_pwm = PWM_GET(pwm3_levels, level); diff --git a/hwdef-emisar-d4v2-nofet.c b/hwdef-emisar-d4v2-nofet.c index 60d80ea..24477a7 100644 --- a/hwdef-emisar-d4v2-nofet.c +++ b/hwdef-emisar-d4v2-nofet.c @@ -6,6 +6,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_main(uint8_t level); bool gradual_tick_main(uint8_t gt); @@ -19,15 +21,13 @@ Channel channels[] = { }; +void set_level_zero() { + CH1_PWM = 0; + PWM_CNT = 0; // reset phase +} + // single set of LEDs with just a 1x7135 chip, max 350 mA or ~130 lm void set_level_main(uint8_t level) { - if (level == 0) { - CH1_PWM = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); // pulse frequency modulation, a.k.a. dynamic PWM uint16_t top = PWM_GET16(pwm_tops, level); diff --git a/hwdef-emisar-d4v2.c b/hwdef-emisar-d4v2.c index ada4eb8..026b30d 100644 --- a/hwdef-emisar-d4v2.c +++ b/hwdef-emisar-d4v2.c @@ -6,6 +6,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_main(uint8_t level); bool gradual_tick_main(uint8_t gt); @@ -19,16 +21,14 @@ Channel channels[] = { }; +void set_level_zero() { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; // reset phase +} + // single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear void set_level_main(uint8_t level) { - if (level == 0) { - CH1_PWM = 0; - CH2_PWM = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); // pulse frequency modulation, a.k.a. dynamic PWM diff --git a/hwdef-noctigon-dm11-boost.c b/hwdef-noctigon-dm11-boost.c index 006cbf8..08e2798 100644 --- a/hwdef-noctigon-dm11-boost.c +++ b/hwdef-noctigon-dm11-boost.c @@ -6,6 +6,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_main(uint8_t level); bool gradual_tick_main(uint8_t gt); @@ -19,20 +21,18 @@ Channel channels[] = { }; +void set_level_zero() { + CH1_PWM = 0; + PWM_CNT = 0; // reset phase + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN ); // disable opamp + CH1_ENABLE_PORT2 &= ~(1 << CH1_ENABLE_PIN2); // disable PMIC +} + // single set of LEDs with single power channel, boost void set_level_main(uint8_t level) { - if (level == 0) { - CH1_PWM = 0; - PWM_CNT = 0; // reset phase - CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN ); // disable opamp - CH1_ENABLE_PORT2 &= ~(1 << CH1_ENABLE_PIN2); // disable PMIC - return; - } - CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN ); // enable opamp CH1_ENABLE_PORT2 |= (1 << CH1_ENABLE_PIN2); // enable PMIC - level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); // pulse frequency modulation, a.k.a. dynamic PWM uint16_t top = PWM_GET16(pwm_tops, level); diff --git a/hwdef-noctigon-k1.c b/hwdef-noctigon-k1.c index 5063fd5..5d61860 100644 --- a/hwdef-noctigon-k1.c +++ b/hwdef-noctigon-k1.c @@ -6,6 +6,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_main(uint8_t level); bool gradual_tick_main(uint8_t gt); @@ -19,19 +21,17 @@ Channel channels[] = { }; -// single set of LEDs with 2 stacked power channels, linear + DD FET -void set_level_main(uint8_t level) { - if (level == 0) { - CH1_PWM = 0; - //CH2_PWM = 0; - //PWM_CNT = 0; // reset phase - CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp - return; - } +void set_level_zero() { + CH1_PWM = 0; + //CH2_PWM = 0; + //PWM_CNT = 0; // reset phase + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp +} +// single LED with 1 power channels, linear +void set_level_main(uint8_t level) { CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable opamp - level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); //PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); // pulse frequency modulation, a.k.a. dynamic PWM diff --git a/hwdef-noctigon-kr4-nofet.c b/hwdef-noctigon-kr4-nofet.c index 8ce9525..0492def 100644 --- a/hwdef-noctigon-kr4-nofet.c +++ b/hwdef-noctigon-kr4-nofet.c @@ -6,6 +6,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_main(uint8_t level); bool gradual_tick_main(uint8_t gt); @@ -19,19 +21,17 @@ Channel channels[] = { }; +void set_level_zero() { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; // reset phase + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp +} + // single set of LEDs with linear power channel void set_level_main(uint8_t level) { - if (level == 0) { - CH1_PWM = 0; - CH2_PWM = 0; - PWM_CNT = 0; // reset phase - CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp - return; - } - CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable opamp - level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); // pulse frequency modulation, a.k.a. dynamic PWM uint16_t top = PWM_GET16(pwm_tops, level); diff --git a/hwdef-noctigon-kr4.c b/hwdef-noctigon-kr4.c index e49ff69..b721bdc 100644 --- a/hwdef-noctigon-kr4.c +++ b/hwdef-noctigon-kr4.c @@ -6,6 +6,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_main(uint8_t level); bool gradual_tick_main(uint8_t gt); @@ -19,19 +21,17 @@ Channel channels[] = { }; +void set_level_zero() { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; // reset phase + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp +} + // single set of LEDs with 2 stacked power channels, linear + DD FET void set_level_main(uint8_t level) { - if (level == 0) { - CH1_PWM = 0; - CH2_PWM = 0; - PWM_CNT = 0; // reset phase - CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp - return; - } - CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable opamp - level --; // PWM array index = level - 1 PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); // pulse frequency modulation, a.k.a. dynamic PWM diff --git a/hwdef-sofirn-lt1s-pro.c b/hwdef-sofirn-lt1s-pro.c index 1359c29..90c2c07 100644 --- a/hwdef-sofirn-lt1s-pro.c +++ b/hwdef-sofirn-lt1s-pro.c @@ -4,6 +4,8 @@ #pragma once +void set_level_zero(); + void set_level_red(uint8_t level); void set_level_white_blend(uint8_t level); void set_level_auto_2ch_blend(uint8_t level); @@ -76,34 +78,26 @@ void calc_auto_3ch_blend( } +void set_level_zero() { + WARM_PWM_LVL = 0; + COOL_PWM_LVL = 0; + RED_PWM_LVL = 0; + PWM_CNT = 0; // reset phase +} + // single set of LEDs with 1 power channel and dynamic PWM void set_level_red(uint8_t level) { - if (level == 0) { - RED_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - } else { - level --; // PWM array index = level - 1 - RED_PWM_LVL = PWM_GET(pwm1_levels, level); - // pulse frequency modulation, a.k.a. dynamic PWM - PWM_TOP = PWM_GET(pwm_tops, level); - // force reset phase when turning on from zero - // (because otherwise the initial response is inconsistent) - if (! actual_level) PWM_CNT = 0; - } + RED_PWM_LVL = PWM_GET(pwm1_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + PWM_TOP = PWM_GET(pwm_tops, level); + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; } // warm + cool blend w/ dynamic PWM void set_level_white_blend(uint8_t level) { - if (level == 0) { - WARM_PWM_LVL = 0; - COOL_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 - PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); PWM_DATATYPE top = PWM_GET(pwm_tops, level); @@ -120,15 +114,6 @@ void set_level_white_blend(uint8_t level) { // same as white blend, but tint is calculated from the ramp level void set_level_auto_2ch_blend(uint8_t level) { - if (level == 0) { - WARM_PWM_LVL = 0; - COOL_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 - PWM_DATATYPE warm_PWM, cool_PWM; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); PWM_DATATYPE top = PWM_GET(pwm_tops, level); @@ -145,16 +130,6 @@ void set_level_auto_2ch_blend(uint8_t level) { // "auto tint" channel mode with dynamic PWM void set_level_auto_3ch_blend(uint8_t level) { - if (level == 0) { - WARM_PWM_LVL = 0; - COOL_PWM_LVL = 0; - RED_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 - PWM_DATATYPE a, b, c; calc_auto_3ch_blend(&a, &b, &c, level); @@ -176,13 +151,6 @@ void set_level_red_white_blend(uint8_t level) { set_level_white_blend(level); channel_mode = CM_WHITE_RED; - if (level == 0) { - RED_PWM_LVL = 0; - PWM_CNT = 0; // reset phase - return; - } - - level --; // PWM array index = level - 1 PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level); // set the red LED as a ratio of the white output level diff --git a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp-fet.h b/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp-fet.h deleted file mode 100644 index 437387c..0000000 --- a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp-fet.h +++ /dev/null @@ -1,74 +0,0 @@ -// Emisar D4S V2 tint-ramping (plus FET) config options for Anduril (based on Noctigon K9.3) -// Copyright (C) 2021-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -#include "cfg-emisar-d4sv2-tintramp.h" -#undef MODEL_NUMBER -#define MODEL_NUMBER "0136" -// ATTINY: 1634 - -// enable the FET channel, even though it's ... kinda funky -#undef PWM_CHANNELS -#define PWM_CHANNELS 2 - -// main LEDs -// output: unknown, 2000 lm? -// FET: unknown, 3000 lm? -// 2nd LEDs -// output: unknown, 2000 lm? -#define RAMP_LENGTH 150 -///// copy non-FET ramp, but add FET to the top 10 levels from 141 to 150 -/* old -// level_calc.py 5.01 1 140 7135 1 0.2 2000 --pwm dyn:69:16383:511 -// plus a FET segment -// abstract ramp (power is split between both sets of LEDs) -// level_calc.py 2 1 10 7135 5 50.0 3000 --pwm 255 -// append: ,500,482,456,420,374,318,252,178,94,0 -*/ -/* also old -// level_calc.py 3 1 11 7135 511 2000 5000 --pwm 1022 -// append: 549,589,633,679,728,780,836,894,957,1022 -//#undef PWM1_LEVELS -//#define PWM1_LEVELS 1,1,1,2,2,3,3,4,5,5,6,7,8,9,10,12,13,14,16,18,19,21,23,25,27,30,32,35,37,40,43,45,48,51,54,58,61,64,67,70,74,77,80,83,86,89,92,95,97,99,101,103,105,106,106,107,106,106,104,102,100,96,92,87,81,73,65,56,45,33,35,37,39,41,43,45,47,49,52,54,57,59,62,65,68,71,74,78,81,85,89,92,96,100,105,109,114,118,123,128,133,139,144,150,156,162,168,175,181,188,195,202,210,217,225,233,242,250,259,268,278,287,297,307,318,328,339,351,362,374,386,399,412,425,438,452,466,481,496,511,549,589,633,679,728,780,836,894,957,1022 -// append: ,511,511,511,511,511,511,511,511,511,511 -//#undef PWM_TOPS -//#define PWM_TOPS 16383,13469,10296,14694,10845,14620,11496,13507,14400,11954,12507,12676,12605,12376,12036,12805,12240,11650,11882,11933,11243,11155,10988,10763,10497,10569,10223,10164,9781,9646,9475,9071,8870,8652,8422,8330,8077,7823,7569,7318,7169,6919,6676,6439,6209,5986,5770,5561,5305,5063,4834,4618,4413,4180,3925,3723,3468,3264,3016,2787,2576,2333,2111,1885,1658,1412,1189,968,734,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511 -*/ - -// prepend: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,14,27,45,68,96,129,166,208,255 -#undef DEFAULT_LEVEL -#define DEFAULT_LEVEL 70 -#undef MAX_1x7135 -#define MAX_1x7135 130 - -#undef RAMP_SMOOTH_FLOOR -#define RAMP_SMOOTH_FLOOR 10 // level 1 is unreliable (?) -#undef RAMP_SMOOTH_CEIL -#define RAMP_SMOOTH_CEIL 130 -// 10, 30, 50, [70], 90, 110, [130] -#undef RAMP_DISCRETE_FLOOR -#define RAMP_DISCRETE_FLOOR 10 -#undef RAMP_DISCRETE_CEIL -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#undef RAMP_DISCRETE_STEPS -#define RAMP_DISCRETE_STEPS 7 - -// safe limit highest regulated power (no FET or turbo) -#undef SIMPLE_UI_FLOOR -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#undef SIMPLE_UI_CEIL -#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL -#undef SIMPLE_UI_STEPS -#define SIMPLE_UI_STEPS 5 - -// stop panicking at ~2000 lm -#undef THERM_FASTER_LEVEL -#define THERM_FASTER_LEVEL 130 -#undef MIN_THERM_STEPDOWN -#define MIN_THERM_STEPDOWN 65 // should be above highest dyn_pwm level - -// speed up party strobe; the FET is really fast -#undef PARTY_STROBE_ONTIME - diff --git a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h b/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h deleted file mode 100644 index c9a0b4f..0000000 --- a/spaghetti-monster/anduril/cfg-emisar-d4sv2-tintramp.h +++ /dev/null @@ -1,88 +0,0 @@ -// Emisar D4S V2 tint-ramping config options for Anduril (based on Noctigon K9.3) -// Copyright (C) 2021-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -#define MODEL_NUMBER "0135" -#include "hwdef-Emisar_D4Sv2-tintramp.h" -#include "hank-cfg.h" -// ATTINY: 1634 - -// this light has three aux LED channels: R, G, B -#define USE_AUX_RGB_LEDS -// the aux LEDs are front-facing, so turn them off while main LEDs are on -// it also has an independent LED in the button -#define USE_BUTTON_LED -// TODO: the whole "indicator LED" thing needs to be refactored into -// "aux LED(s)" and "button LED(s)" since they work a bit differently -// enabling this option breaks the button LED on D4v2.5 -#ifdef USE_INDICATOR_LED_WHILE_RAMPING -#undef USE_INDICATOR_LED_WHILE_RAMPING -#endif - -// has two channels of independent LEDs -#define USE_TINT_RAMPING -// how much to increase total brightness at middle tint -// (0 = 100% brightness, 64 = 200% brightness) -#define TINT_RAMPING_CORRECTION 0 // none, linear regulator doesn't need it - -// main LEDs -// output: unknown, 2000 lm? -// FET: absent / unused? -// 2nd LEDs -// output: unknown, 2000 lm? -#define RAMP_LENGTH 150 -// abstract ramp (power is split between both sets of LEDs) -// 1-130: 0 to 100% power -// level_calc.py 5.01 1 130 7135 2 0.2 2000 --pwm dyn:64:16383:511 -// 131 to 150: 101% to 200% power -// level_calc.py 6.44 1 150 7135 1 0.2 2000 --pwm dyn:74:16383:1022 -#define PWM1_LEVELS 2,2,2,3,3,4,4,5,6,7,8,9,10,11,13,14,16,17,19,21,23,25,28,30,33,35,38,41,44,47,50,54,57,60,64,67,71,74,78,81,84,88,91,94,97,99,101,103,105,106,107,107,107,106,105,102,99,95,90,84,77,68,58,47,34,36,38,40,42,44,47,49,52,54,57,60,63,66,69,73,76,80,83,87,91,96,100,104,109,114,119,124,130,135,141,147,153,160,166,173,180,187,195,203,211,219,228,236,245,255,264,274,285,295,306,317,329,340,353,365,378,391,405,419,433,448,463,479,495,511,530,550,570,591,612,634,657,680,705,730,755,782,809,837,865,895,925,957,989,1022 -#define PWM_TOPS 16383,13234,9781,13826,9593,13434,9973,12021,12900,13193,13150,12899,12508,12023,12666,11982,12181,11422,11393,11247,11018,10731,10826,10434,10365,9927,9767,9565,9332,9076,8806,8693,8395,8096,7928,7626,7439,7143,6948,6665,6393,6203,5946,5700,5465,5187,4926,4681,4451,4195,3957,3700,3463,3213,2983,2718,2476,2231,1986,1742,1501,1245,997,756,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511,511 -#define DEFAULT_LEVEL 70 -#define MAX_1x7135 150 -#define HALFSPEED_LEVEL 10 -#define QUARTERSPEED_LEVEL 2 - -#define USE_MANUAL_MEMORY_TIMER_FOR_TINT -//#define DEFAULT_MANUAL_MEMORY DEFAULT_LEVEL -//#define DEFAULT_MANUAL_MEMORY_TIMER 10 - -#define RAMP_SMOOTH_FLOOR 10 // level 1 is unreliable (?) -#define RAMP_SMOOTH_CEIL 130 -// 10, 30, 50, [70], 90, 110, [130] -#define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 7 - -// safe limit highest regulated power (no FET or turbo) -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL -#define SIMPLE_UI_STEPS 5 - -// stop panicking at ~1500 lm -#define THERM_FASTER_LEVEL 130 -#define MIN_THERM_STEPDOWN 65 // should be above highest dyn_pwm level - -// use the brightest setting for strobe -#define STROBE_BRIGHTNESS MAX_LEVEL -// slow down party strobe; this driver can't pulse for 1ms or less -#define PARTY_STROBE_ONTIME 2 - -// the default of 26 looks a bit flat, so increase it -#define CANDLE_AMPLITUDE 33 - -// the power regulator is a bit slow, so push it harder for a quick response from off -#define DEFAULT_JUMP_START_LEVEL 21 -#define BLINK_BRIGHTNESS DEFAULT_LEVEL -#define BLINK_ONCE_TIME 12 // longer blink, since main LEDs are slow - -#define THERM_CAL_OFFSET 5 - -#ifdef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_MIDDLE -#endif - -// for consistency with KR4 (not otherwise necessary though) -#define USE_SOFT_FACTORY_RESET - diff --git a/spaghetti-monster/fsm-channels.c b/spaghetti-monster/fsm-channels.c index 69add93..62b608c 100644 --- a/spaghetti-monster/fsm-channels.c +++ b/spaghetti-monster/fsm-channels.c @@ -7,6 +7,7 @@ #include "fsm-ramping.h" +#if NUM_CHANNEL_MODES > 1 void set_channel_mode(uint8_t mode) { uint8_t cur_level = actual_level; // turn off old LEDs before changing channel @@ -18,6 +19,7 @@ void set_channel_mode(uint8_t mode) { // update the LEDs set_level(cur_level); } +#endif // if NUM_CHANNEL_MODES > 1 #ifdef USE_CALC_2CH_BLEND diff --git a/spaghetti-monster/fsm-channels.h b/spaghetti-monster/fsm-channels.h index 55fc826..113a85c 100644 --- a/spaghetti-monster/fsm-channels.h +++ b/spaghetti-monster/fsm-channels.h @@ -42,6 +42,8 @@ Channel channels[]; // values are defined in the hwdef-*.c #define USE_CHANNEL_MODES // current multi-channel mode uint8_t channel_mode = DEFAULT_CHANNEL_MODE; +#else + #define channel_mode 0 #endif #ifdef USE_CUSTOM_CHANNEL_3H_MODES @@ -79,7 +81,9 @@ StatePtr channel_3H_modes[NUM_CHANNEL_MODES]; #define channel_has_args(n) (channels[n].has_args) #endif +#if NUM_CHANNEL_MODES > 1 void set_channel_mode(uint8_t mode); +#endif #ifdef USE_CALC_2CH_BLEND void calc_2ch_blend( -- cgit v1.2.3 From 013174374f87a2c3f9a3427cc63f7211f5bf7fd5 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 17 Sep 2023 06:31:55 -0600 Subject: converted noctigon-m44 build, and greatly reduced flicker with a new ramp and some new hwdef algorithms --- hwdef-noctigon-m44.c | 84 ++++++++++++++-------------- hwdef-noctigon-m44.h | 4 +- spaghetti-monster/anduril/cfg-noctigon-m44.h | 12 ++-- 3 files changed, 51 insertions(+), 49 deletions(-) diff --git a/hwdef-noctigon-m44.c b/hwdef-noctigon-m44.c index 0c73005..776cb82 100644 --- a/hwdef-noctigon-m44.c +++ b/hwdef-noctigon-m44.c @@ -7,6 +7,8 @@ #include "chan-rgbaux.c" +void set_level_zero(); + void set_level_ch1(uint8_t level); void set_level_ch2(uint8_t level); void set_level_both(uint8_t level); @@ -53,26 +55,33 @@ Channel channels[] = { // set new values for both channels, // handling any possible combination // and any before/after state -void set_pwms(uint16_t ch1_pwm, uint16_t ch2_pwm, uint16_t top) { - bool was_on = (CH1_PWM>0) | (CH2_PWM>0); - bool now_on = (ch1_pwm>0) | (ch2_pwm>0); - - if (! now_on) { - CH1_PWM = 0; - CH2_PWM = 0; - PWM_TOP = PWM_TOP_INIT; - PWM_CNT = 0; - CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp - CH2_ENABLE_PORT &= ~(1 << CH2_ENABLE_PIN); // disable opamp - return; - } +void set_pwms(uint16_t ch1_pwm, uint16_t ch2_pwm, uint16_t top, + uint8_t ch1_on, uint8_t ch2_on) { + + bool was_on = (CH1_PWM>0) || (CH2_PWM>0) + || ( CH1_ENABLE_PORT & (1 << CH1_ENABLE_PIN) ) + || ( CH2_ENABLE_PORT & (1 << CH2_ENABLE_PIN) ); + bool now_on = (ch1_pwm>0) || (ch2_pwm>0) || ch1_on || ch2_on; + + // phase-correct PWM at zero (for flicker-free moon), + // fast PWM otherwise + if (ch1_pwm || ch2_pwm) + TCCR1B = (0< 0)) ch2_pwm = 1; - - set_pwms(ch1_pwm, ch2_pwm, top); + set_pwms(ch1_pwm, ch2_pwm, top, + blend < 255, blend > 0); } void set_level_auto(uint8_t level) { - if (0 == level) - return set_pwms(0, 0, PWM_TOP_INIT); - - level --; PWM_DATATYPE ch1_pwm, ch2_pwm; PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); PWM_DATATYPE top = PWM_GET(pwm_tops, level); @@ -153,7 +149,9 @@ void set_level_auto(uint8_t level) { calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); - set_pwms(ch1_pwm, ch2_pwm, top); + // don't turn off either emitter entirely + // (it blinks pretty bright when the regulator turns on mid-ramp) + set_pwms(ch1_pwm, ch2_pwm, top, 1, 1); } diff --git a/hwdef-noctigon-m44.h b/hwdef-noctigon-m44.h index f69fdd5..d02d8dd 100644 --- a/hwdef-noctigon-m44.h +++ b/hwdef-noctigon-m44.h @@ -163,6 +163,7 @@ inline void hwdef_setup() { // pre-scale for timer: N = 1 // Linear opamp PWM for both main and 2nd LEDs (10-bit) // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) + // WGM1[3:0]: 1,1,1,0: PWM, Fast, adjustable (DS table 12-5) // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) @@ -171,7 +172,8 @@ inline void hwdef_setup() { | (1< actual_level) gt = actual_level + 1; - gt --; // call the relevant hardware-specific function GradualTickFuncPtr gradual_tick_func = channels[channel_mode].gradual_tick; - bool done = gradual_tick_func(gt); + bool done = gradual_tick_func(gt - 1); if (done) { uint8_t orig = gradual_target; - set_level(gt + 1); + set_level(gt); gradual_target = orig; } } -- cgit v1.2.3 From 5e48926e99ffcc69dc681c1e87fd7912d1468ba3 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 3 Oct 2023 17:12:48 -0600 Subject: new light / driver: HDR boost driver by thefreeman (works well in a FW3A host) --- hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c | 90 +++++++++++ hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.h | 180 +++++++++++++++++++++ .../anduril/cfg-thefreeman-boost21-6a.h | 116 +++++++++++++ 3 files changed, 386 insertions(+) create mode 100644 hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c create mode 100644 hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.h create mode 100644 spaghetti-monster/anduril/cfg-thefreeman-boost21-6a.h diff --git a/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c b/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c new file mode 100644 index 0000000..555167e --- /dev/null +++ b/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c @@ -0,0 +1,90 @@ +// thefreeman boost driver 2.1 output helper functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "chan-rgbaux.c" + +void set_level_zero(); + +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // channel 1 only + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, + RGB_AUX_CHANNELS +}; + + +void set_level_zero() { + DAC_LVL = 0; // DAC off + DAC_VREF = V055; // low Vref + HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); // HDR off + + // prevent post-off flash + IN_NFET_ENABLE_PORT |= (1 << IN_NFET_ENABLE_PIN); + delay_4ms(IN_NFET_DELAY_TIME/4); + IN_NFET_ENABLE_PORT &= ~(1 << IN_NFET_ENABLE_PIN); + + // turn off boost last + BST_ENABLE_PORT &= ~(1 << BST_ENABLE_PIN); // BST off +} + +// single set of LEDs with 1 regulated power channel +// and low/high HDR plus low/high Vref as different "gears" +void set_level_main(uint8_t level) { + uint8_t noflash = 0; + + // when turning on from off, use IN_NFET to prevent a flash + if ((! actual_level) && (level < HDR_ENABLE_LEVEL_MIN)) { + noflash = 1; + IN_NFET_ENABLE_PORT |= (1 << IN_NFET_ENABLE_PIN); + } + + // BST on first, to give it a few extra microseconds to spin up + BST_ENABLE_PORT |= (1 << BST_ENABLE_PIN); + + // pre-load ramp data so it can be assigned faster later + PWM_DATATYPE dac_lvl = PWM_GET(pwm1_levels, level); + PWM_DATATYPE dac_vref = PWM_GET(pwm_tops, level); + + // enable HDR on top half of ramp + if (level >= (HDR_ENABLE_LEVEL_MIN-1)) + HDR_ENABLE_PORT |= (1 << HDR_ENABLE_PIN); + else + HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); + + // set these in successive clock cycles to avoid getting out of sync + // (minimizes ramp bumps when changing gears) + DAC_LVL = dac_lvl; + DAC_VREF = dac_vref; + + if (noflash) { + // wait for flash prevention to finish + delay_4ms(IN_NFET_DELAY_TIME/4); + IN_NFET_ENABLE_PORT &= ~(1 << IN_NFET_ENABLE_PIN); + } +} + +bool gradual_tick_main(uint8_t gt) { + // if HDR and Vref "engine gear" is the same, do a small adjustment... + // otherwise, simply jump to the next ramp level + // and let set_level() handle any gear changes + + PWM_DATATYPE dac_next = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE vref_next = PWM_GET(pwm_tops, gt); + + // different gear = full adjustment + if (vref_next != DAC_VREF) return true; // let parent set_level() for us + + // same gear = small adjustment + GRADUAL_ADJUST_SIMPLE(dac_next, DAC_LVL); + if (dac_next == DAC_LVL) return true; // done + + return false; // not done yet +} + diff --git a/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.h b/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.h new file mode 100644 index 0000000..cf9a443 --- /dev/null +++ b/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.h @@ -0,0 +1,180 @@ +// hwdef for thefreeman's boost driver 2.1 w/ MP3431, DAC, ARGB +// Copyright (C) 2023 TBD (thefreeman), Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* thefreeman’s Boost driver based on MP3431 and attiny1616 + * with high dynamic range and DAC control, AUX : RGB + button + * hardware version : 2.0+ + * compatible with BST20-FWxA v1.0 (no button LED A) + * + * Pin / Name / Function + * 1 PA2 + * 2 PA3 + * 3 GND GND + * 4 VCC VCC + * 5 PA4 + * 6 PA5 + * 7 PA6 DAC + * 8 PA7 + * 9 PB5 IN- NFET + * 10 PB4 HDR + * 11 PB3 B: blue aux LED + * 12 PB2 G: green aux LED + * 13 PB1 R: red aux LED + * 14 PB0 + * 15 PC0 boost enable + * 16 PC1 A: button LED + * 17 PC2 e-switch + * 18 PC3 + * 19 PA0 UDPI + * 20 PA1 + * + * BST EN enable the boost regulator and Op-Amp + * DAC sets the current, max current depends on Vset voltage divider and Rsense + * HDR FET switches between high value Rsense (low current range, pin low), + * and low value Rsense (high current range, pin high) + * IN- NFET : pull up after BST enable to eliminate startup flash, pull down otherwise + */ + +#define ATTINY 1616 +#include + +#define HWDEF_C_FILE hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +// channel modes: +// * 0. main LEDs +// * 1+. aux RGB +#define NUM_CHANNEL_MODES (1 + NUM_RGB_AUX_CHANNEL_MODES) +enum CHANNEL_MODES { + CM_MAIN = 0, + RGB_AUX_ENUMS +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 + + +#define PWM_CHANNELS 1 // old, remove this + +#define PWM_BITS 8 // 8-bit DAC +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // main LED ramp + +// main LED outputs +#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref +#define DAC_VREF VREF.CTRLA // 0.55V or 2.5V +#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) +// Vref values +#define V055 16 +#define V11 17 +#define V25 18 +#define V43 19 +#define V15 20 + +// BST enable +#define BST_ENABLE_PIN PIN0_bp +#define BST_ENABLE_PORT PORTC_OUT + +// HDR +// turns ON HDR FET for the high current range +#define HDR_ENABLE_PIN PIN4_bp +#define HDR_ENABLE_PORT PORTB_OUT + +// IN- NFET +// pull high to force output to zero to eliminate the startup flash +#define IN_NFET_DELAY_TIME 8 // (ms) +#define IN_NFET_ENABLE_PIN PIN5_bp +#define IN_NFET_ENABLE_PORT PORTB_OUT + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PIN2_bp +#define SWITCH_PORT VPORTC.IN +#define SWITCH_ISC_REG PORTC.PIN2CTRL +#define SWITCH_VECT PORTC_PORT_vect +#define SWITCH_INTFLG VPORTC.INTFLAGS +#define SWITCH_PCINT PCINT0 +#define PCINT_vect PCINT0_vect +#endif + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 0 // using a PFET so no appreciable drop +#endif + +// this driver allows for aux LEDs under the optic +#define AUXLED_R_PIN PIN1_bp +#define AUXLED_G_PIN PIN2_bp +#define AUXLED_B_PIN PIN3_bp +#define AUXLED_RGB_PORT PORTB // PORTA or PORTB or PORTC + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + +// A: button LED +#ifndef BUTTON_LED_PIN +#define BUTTON_LED_PIN PIN1_bp +#define BUTTON_LED_PORT PORTC +#endif + + +inline void hwdef_setup() { + + // TODO: for this DAC controlled-light, try to decrease the clock speed or use the ULP + // set up the system clock to run at 10 MHz to match other attiny1616 lights + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, + CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + + VPORTA.DIR = PIN6_bm; // DAC + VPORTB.DIR = PIN1_bm // R + | PIN2_bm // G + | PIN3_bm // B + | PIN4_bm // HDR + | PIN5_bm; // IN- NFET + VPORTC.DIR = PIN0_bm // BST EN + | PIN1_bm; // A + + // enable pullups on the input pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + PORTA.PIN1CTRL = PORT_PULLUPEN_bm; + PORTA.PIN2CTRL = PORT_PULLUPEN_bm; + PORTA.PIN3CTRL = PORT_PULLUPEN_bm; + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm; + //PORTA.PIN6CTRL = PORT_PULLUPEN_bm; // DAC + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + PORTB.PIN0CTRL = PORT_PULLUPEN_bm; + //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // R + //PORTB.PIN2CTRL = PORT_PULLUPEN_bm; // G + //PORTB.PIN3CTRL = PORT_PULLUPEN_bm; // B + //PORTB.PIN4CTRL = PORT_PULLUPEN_bm; // HDR + //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // IN- NFET + + //PORTC.PIN0CTRL = PORT_PULLUPEN_bm; // EN + //PORTC.PIN1CTRL = PORT_PULLUPEN_bm; // A + PORTC.PIN2CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // e-switch + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + + // set up the DAC + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf + // DAC ranges from 0V to (255 * Vref) / 256 + // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc + VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; + VREF.CTRLB |= VREF_DAC0REFEN_bm; + DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; + DAC0.DATA = 255; // set the output voltage + +} + + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/cfg-thefreeman-boost21-6a.h b/spaghetti-monster/anduril/cfg-thefreeman-boost21-6a.h new file mode 100644 index 0000000..76ea9ab --- /dev/null +++ b/spaghetti-monster/anduril/cfg-thefreeman-boost21-6a.h @@ -0,0 +1,116 @@ +// thefreeman's BST21 BST20-FWxA (no button LED) +// Copyright (C) 2023 TBD (thefreeman), Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#define MODEL_NUMBER "1631" +#include "hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.h" +// ATTINY: 1616 + +// HPRsense : 1.7+0.3+5 = 7mR (DMN22M5UFG+trace resistance+5mR) +// Vsense=42.46mV, R1= 191k +// LPRsense : 1R +// transition DAC level 8, ramp level 45 +// fifth power ramp 0.1mA to 6066mA + +#define RAMP_SIZE 150 + +// 4 ramp segments: +// - low 0.55V +// - low 2.5V +// - high 0.55V +// - high 2.5V +// PWM1: DAC Data +#define PWM1_LEVELS 2, 3, 4, 5, 7, 9, 11, 13, 16, 19, 23, 28, 33, 39, 45, 53, 61, 71, 81, 93,106,121,137,155,175,196,220,246, \ + 60, 67, 74, 82, 91,100,110,121,133,146,159,174,190,207,224,244, \ + 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 23, 24, 26, 27, 29, 31, 33, 35, 37, 40, 42, 45, 47, 50, 53, 56, 59, 62, 66, 69, 73, 77, 81, 85, 90, 94, 99,104,109,114,120,126,132,138,144,151,158,165,173,180,188,196,205,214,223,232,242,252, \ + 57, 60, 62, 65, 67, 70, 73, 76, 78, 82, 85, 88, 91, 95, 98,102,105,109,113,117,121,126,130,135,139,144,149,154,159,164,170,175,181,187,193,199,206,212,219,225,232,240,247,255 +// PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) +#define PWM_TOPS 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, \ + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 + +#define MAX_1x7135 44 +#define DEFAULT_LEVEL 44 +#define HDR_ENABLE_LEVEL_MIN 45 // when HDR FET turns ON + +// no PWM, so MCU clock speed can be slow +#define HALFSPEED_LEVEL 41 +#define QUARTERSPEED_LEVEL 40 // seems to run fine at 10kHz/4, try reducing more + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 130 // 50% / 3A / 1000 lm +// 1 22 [44] 65 87 108 130 +#define RAMP_DISCRETE_FLOOR 1 +#define RAMP_DISCRETE_CEIL 130 +#define RAMP_DISCRETE_STEPS 7 + +// 20 [45] 70 95 120 +#define SIMPLE_UI_FLOOR 20 +#define SIMPLE_UI_CEIL 120 // ~2.25A / ~750 lm +#define SIMPLE_UI_STEPS 5 + +// don't blink mid-ramp +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + +// thermal config + +// temperature limit +#define THERM_FASTER_LEVEL 130 // stop panicking at 50%/3A +#define MIN_THERM_STEPDOWN MAX_1x7135 + +//#define THERM_LOOKAHEAD 4 // 4 by default -> decrease for longer turbo +#define THERM_NEXT_WARNING_THRESHOLD 48 // 24 by default -> increase for fewer adjustments (more stable output on large time scale) +#define THERM_RESPONSE_MAGNITUDE 32 // 64 by default -> decrease for smaller adjustments (removes dip post turbo) +//#define THERM_WINDOW_SIZE 1 // 2 by default -> decrease for tighter temperature regulation + + +// UI + +//#define SIMPLE_UI_ACTIVE 1 // advanced UI by default + +// allow Aux Config and Strobe Modes in Simple UI +#define USE_EXTENDED_SIMPLE_UI + +// Allow 3C in Simple UI for switching between smooth and stepped ramping +#define USE_SIMPLE_UI_RAMPING_TOGGLE + +#define DEFAULT_2C_STYLE 1 // enable 2 click turbo + + +// AUX + +//#define USE_BUTTON_LED + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// blink numbers on the main LEDs by default +#define DEFAULT_BLINK_CHANNEL CM_MAIN + +// use aux red + aux blue for police strobe +#define USE_POLICE_COLOR_STROBE_MODE +#define POLICE_STROBE_USES_AUX +#define POLICE_COLOR_STROBE_CH1 CM_AUXRED +#define POLICE_COLOR_STROBE_CH2 CM_AUXBLU + +// the aux LEDs are front-facing, so turn them off while main LEDs are on +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif + + +// Misc + +#define PARTY_STROBE_ONTIME 1 // slow down party strobe +#define STROBE_OFF_LEVEL 1 // keep the regulator chip on between pulses + +// enable 13H factory reset so it can be used on tail e-switch lights +#define USE_SOFT_FACTORY_RESET + -- cgit v1.2.3 From 34c5e4dba130f04b36014d32e61a7ffc960bb79c Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 4 Oct 2023 12:05:50 -0600 Subject: added thefreeman-boost-fwaa build, and made aux RGB voltage work on AA/NiMH --- hwdef-thefreeman-boost-fwaa-mp3432-hdr-dac-rgb.h | 187 +++++++++++++++++++++ hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.h | 7 +- spaghetti-monster/anduril/aux-leds.c | 31 +++- spaghetti-monster/anduril/aux-leds.h | 15 +- .../anduril/cfg-thefreeman-boost-fwaa.h | 116 +++++++++++++ .../anduril/cfg-thefreeman-boost21-6a.h | 7 +- 6 files changed, 342 insertions(+), 21 deletions(-) create mode 100755 hwdef-thefreeman-boost-fwaa-mp3432-hdr-dac-rgb.h create mode 100755 spaghetti-monster/anduril/cfg-thefreeman-boost-fwaa.h diff --git a/hwdef-thefreeman-boost-fwaa-mp3432-hdr-dac-rgb.h b/hwdef-thefreeman-boost-fwaa-mp3432-hdr-dac-rgb.h new file mode 100755 index 0000000..efa3ca7 --- /dev/null +++ b/hwdef-thefreeman-boost-fwaa-mp3432-hdr-dac-rgb.h @@ -0,0 +1,187 @@ +// hwdef for thefreeman's boost FWAA driver 1.1 w/ MP3432, HDR DAC, RGB aux +// Copyright (C) 2023 TBD (thefreeman), Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* thefreeman’s FWAA AA/li-ion Boost driver based on MP3432 and attiny1616 + * with high dynamic range and DAC control, AUX : RGB + * hardware versions : 1.0, 1.1 + * + * Pin / Name / Function + * 1 PA2 BattLVL (ADC0 - AIN2) + * 2 PA3 + * 3 GND GND + * 4 VCC VCC + * 5 PA4 BST EN: boost enable + * 6 PA5 HDR + * 7 PA6 DAC + * 8 PA7 + * 9 PB5 B: blue aux LED + * 10 PB4 G: green aux LED + * 11 PB3 R: red aux LED + * 12 PB2 IN- NFET + * 13 PB1 + * 14 PB0 + * 15 PC0 + * 16 PC1 + * 17 PC2 + * 18 PC3 e-switch + * 19 PA0 UDPI + * 20 PA1 + * + * BST EN enable the boost regulator and Op-Amp + * DAC sets the current, max current depends on Vset voltage divider and Rsense + * HDR FET switches between high value Rsense (low current range, pin low), + * and low value Rsense (high current range, pin high) + * IN- NFET : pull up after BST enable to eliminate startup flash, pull down otherwise + */ + +#define ATTINY 1616 +#include + +#define HWDEF_C_FILE hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +// channel modes: +// * 0. main LEDs +// * 1+. aux RGB +#define NUM_CHANNEL_MODES (1 + NUM_RGB_AUX_CHANNEL_MODES) +enum CHANNEL_MODES { + CM_MAIN = 0, + RGB_AUX_ENUMS +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 + + +#define PWM_CHANNELS 1 // old, remove this + +#define PWM_BITS 8 // 8-bit DAC +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // main LED ramp + +// main LED outputs +#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref +#define DAC_VREF VREF.CTRLA // 0.55V or 2.5V +#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) +// Vref values +#define V055 16 +#define V11 17 +#define V25 18 +#define V43 19 +#define V15 20 + +// BST enable +#define BST_ENABLE_PIN PIN4_bp +#define BST_ENABLE_PORT PORTA_OUT + +// HDR +// turns on HDR FET for the high current range +#define HDR_ENABLE_PIN PIN5_bp +#define HDR_ENABLE_PORT PORTA_OUT + +// IN- NFET +// pull high to force output to zero to eliminate the startup flash +#define IN_NFET_DELAY_TIME 4 // (ms) +#define IN_NFET_ENABLE_PIN PIN2_bp +#define IN_NFET_ENABLE_PORT PORTB_OUT + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PIN3_bp +#define SWITCH_PORT VPORTC.IN +#define SWITCH_ISC_REG PORTC.PIN3CTRL +#define SWITCH_VECT PORTC_PORT_vect +#define SWITCH_INTFLG VPORTC.INTFLAGS +#define SWITCH_PCINT PCINT0 +#define PCINT_vect PCINT0_vect +#endif + +// Voltage divider battLVL +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated +#define DUAL_VOLTAGE_FLOOR 21 // for AA/14500 boost drivers, don't indicate low voltage if below this level +#define DUAL_VOLTAGE_LOW_LOW 7 // the lower voltage range's danger zone 0.7 volts (NiMH) +#define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN2_gc // which ADC channel to read + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// Resistors are 330k and 100k +#ifndef ADC_44 +#define ADC_44 951 // raw value at 4.40V +#endif +#ifndef ADC_22 +#define ADC_22 476 // raw value at 2.20V +#endif + +// this driver allows for aux LEDs under the optic +#define AUXLED_R_PIN PIN3_bp +#define AUXLED_G_PIN PIN4_bp +#define AUXLED_B_PIN PIN5_bp +#define AUXLED_RGB_PORT PORTB // PORTA or PORTB or PORTC + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + + +inline void hwdef_setup() { + + // TODO: for this DAC controlled-light, try to decrease the clock speed or use the ULP + // set up the system clock to run at 10 MHz to match other attiny1616 lights + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, + CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + + VPORTA.DIR = PIN4_bm // BST EN + | PIN5_bm // HDR + | PIN6_bm; // DAC + VPORTB.DIR = PIN2_bm // IN- NFET + | PIN3_bm // R + | PIN4_bm // G + | PIN5_bm; // B + //VPORTC.DIR = PIN0_bm | PIN1_bm; + + // enable pullups on the input pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + PORTA.PIN1CTRL = PORT_PULLUPEN_bm; + //PORTA.PIN2CTRL = PORT_PULLUPEN_bm; // BattLVL + PORTA.PIN3CTRL = PORT_PULLUPEN_bm; + //PORTA.PIN4CTRL = PORT_PULLUPEN_bm; // EN + //PORTA.PIN5CTRL = PORT_PULLUPEN_bm; // HDR + //PORTA.PIN6CTRL = PORT_PULLUPEN_bm; // DAC + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + PORTB.PIN0CTRL = PORT_PULLUPEN_bm; + PORTB.PIN1CTRL = PORT_PULLUPEN_bm; + //PORTB.PIN2CTRL = PORT_PULLUPEN_bm; // IN- NFET + //PORTB.PIN3CTRL = PORT_PULLUPEN_bm; // R + //PORTB.PIN4CTRL = PORT_PULLUPEN_bm; // G + //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // B + + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm + | PORT_ISC_BOTHEDGES_gc; // e-switch + + // set up the DAC + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf + // DAC ranges from 0V to (255 * Vref) / 256 + // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc + VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; + VREF.CTRLB |= VREF_DAC0REFEN_bm; + DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; + DAC0.DATA = 255; // set the output voltage + +} + + +#define LAYOUT_DEFINED + diff --git a/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.h b/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.h index cf9a443..1c35014 100644 --- a/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.h +++ b/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.h @@ -84,7 +84,7 @@ enum CHANNEL_MODES { #define BST_ENABLE_PORT PORTC_OUT // HDR -// turns ON HDR FET for the high current range +// turns on HDR FET for the high current range #define HDR_ENABLE_PIN PIN4_bp #define HDR_ENABLE_PORT PORTB_OUT @@ -161,13 +161,14 @@ inline void hwdef_setup() { //PORTC.PIN0CTRL = PORT_PULLUPEN_bm; // EN //PORTC.PIN1CTRL = PORT_PULLUPEN_bm; // A - PORTC.PIN2CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // e-switch + PORTC.PIN2CTRL = PORT_PULLUPEN_bm + | PORT_ISC_BOTHEDGES_gc; // e-switch PORTC.PIN3CTRL = PORT_PULLUPEN_bm; // set up the DAC // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf // DAC ranges from 0V to (255 * Vref) / 256 - // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc + // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; VREF.CTRLB |= VREF_DAC0REFEN_bm; DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; diff --git a/spaghetti-monster/anduril/aux-leds.c b/spaghetti-monster/anduril/aux-leds.c index b8d6662..097cf28 100644 --- a/spaghetti-monster/anduril/aux-leds.c +++ b/spaghetti-monster/anduril/aux-leds.c @@ -58,17 +58,30 @@ void indicator_led_update(uint8_t mode, uint8_t tick) { uint8_t voltage_to_rgb() { static const uint8_t levels[] = { // voltage, color - 0, 0, // 0, R - 33, 1, // 1, R+G - 35, 2, // 2, G - 37, 3, // 3, G+B - 39, 4, // 4, B - 41, 5, // 5, R + B - 44, 6, // 6, R+G+B // skip; looks too similar to G+B - 255, 6, // 7, R+G+B + 0, 0, // black + #ifdef DUAL_VOLTAGE_FLOOR + // AA / NiMH voltages + 9, 1, // R + 10, 2, // R+G + 11, 3, // G + 12, 4, // G+B + 13, 5, // B + 14, 6, // R + B + 15, 7, // R+G+B + 20, 0, // black + #endif + // li-ion voltages + 29, 1, // R + 33, 2, // R+G + 35, 3, // G + 37, 4, // G+B + 39, 5, // B + 41, 6, // R + B + 44, 7, // R+G+B // skip; looks too similar to G+B + 255, 7, // R+G+B }; uint8_t volts = voltage; - if (volts < VOLTAGE_LOW) return 0; + //if (volts < VOLTAGE_LOW) return 0; uint8_t i; for (i = 0; volts >= levels[i]; i += 2) {} diff --git a/spaghetti-monster/anduril/aux-leds.h b/spaghetti-monster/anduril/aux-leds.h index 8a79cfb..fa97e6b 100644 --- a/spaghetti-monster/anduril/aux-leds.h +++ b/spaghetti-monster/anduril/aux-leds.h @@ -22,13 +22,14 @@ void rgb_led_voltage_readout(uint8_t bright); * 8: voltage */ const PROGMEM uint8_t rgb_led_colors[] = { - 0b00000001, // 0: red - 0b00000101, // 1: yellow - 0b00000100, // 2: green - 0b00010100, // 3: cyan - 0b00010000, // 4: blue - 0b00010001, // 5: purple - 0b00010101, // 6: white + 0b00000000, // 0: black + 0b00000001, // 1: red + 0b00000101, // 2: yellow + 0b00000100, // 3: green + 0b00010100, // 4: cyan + 0b00010000, // 5: blue + 0b00010001, // 6: purple + 0b00010101, // 7: white }; // intentionally 1 higher than total modes, to make "voltage" easier to reach // (at Hank's request) diff --git a/spaghetti-monster/anduril/cfg-thefreeman-boost-fwaa.h b/spaghetti-monster/anduril/cfg-thefreeman-boost-fwaa.h new file mode 100755 index 0000000..460346e --- /dev/null +++ b/spaghetti-monster/anduril/cfg-thefreeman-boost-fwaa.h @@ -0,0 +1,116 @@ +// thefreeman's BCK-FWAA-MP3432 (li-ion / AA) +// Copyright (C) 2023 TBD (thefreeman), Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#define MODEL_NUMBER "1632" +#include "hwdef-thefreeman-boost-fwaa-mp3432-hdr-dac-rgb.h" +// ATTINY: 1616 + +// HPRsense : 4.2+0.3+20 = 24.5mR (DMN1004UFDF+trace resistance+20mR) +// R1=165k Vsense=49.02 Iout=2001mA +// LPRsense : 2R +// transition DAC lvl 14, ramp lvl 51 +// fifth power ramp 0.06mA to 2001mA + +#define RAMP_SIZE 150 + +// 4 ramp segments: +// - low 0.55V +// - low 2.5V +// - high 0.55V +// - high 2.5V +// PWM1: DAC Data +#define PWM1_LEVELS 2, 3, 4, 5, 6, 8, 9, 11, 14, 16, 19, 23, 26, 31, 35, 41, 47, 54, 61, 69, 78, 89,100,112,125,140,155,173,191,212,234, \ + 56, 62, 68, 74, 82, 89, 97,106,115,125,136,147,159,172,186,200,215,232,249, \ + 14, 15, 17, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 38, 40, 43, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81, 86, 90, 95, 99,104,109,114,120,126,131,138,144,150,157,164,171,179,187,195,203,212,221,230,239,249, \ + 57, 59, 61, 64, 66, 69, 72, 74, 77, 80, 83, 86, 90, 93, 96,100,103,107,111,115,119,123,127,132,136,141,145,150,155,160,166,171,176,182,188,194,200,206,213,219,226,233,240,247,255 +// PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) +#define PWM_TOPS 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, \ + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 + +#define MAX_1x7135 50 +#define DEFAULT_LEVEL 44 +#define HDR_ENABLE_LEVEL_MIN 51 // when HDR FET turns ON + +// no PWM, so MCU clock speed can be slow +#define HALFSPEED_LEVEL 46 +#define QUARTERSPEED_LEVEL 45 // seems to run fine at 10kHz/4, try reducing more + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 130 // ~50% power, ~??? mA / ??? lm +#define RAMP_DISCRETE_FLOOR 1 +#define RAMP_DISCRETE_CEIL 130 +#define RAMP_DISCRETE_STEPS 7 + +// 20 [45] 70 95 120 +#define SIMPLE_UI_FLOOR 20 +#define SIMPLE_UI_CEIL 120 // ~37% power, ~??? mA / ??? lm +#define SIMPLE_UI_STEPS 5 + +// don't blink mid-ramp +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + +// thermal config + +// temperature limit +#define THERM_FASTER_LEVEL 130 +#define MIN_THERM_STEPDOWN MAX_1x7135 + +//#define THERM_LOOKAHEAD 2 // 4 by default -> decrease for longer turbo +//#define THERM_NEXT_WARNING_THRESHOLD 48 // 24 by default -> increase for fewer adjustments (more stable output on large time scale) +//#define THERM_RESPONSE_MAGNITUDE 16 // 64 by default -> decrease for smaller adjustments (removes dip post turbo) +//#define THERM_WINDOW_SIZE 1 // 2 by default -> decrease for tighter temperature regulation + + +// UI + +//#define SIMPLE_UI_ACTIVE 0 // advanced UI by default + +// allow Aux Config and Strobe Modes in Simple UI +#define USE_EXTENDED_SIMPLE_UI + +// Allow 3C in Simple UI for switching between smooth and stepped ramping +#define USE_SIMPLE_UI_RAMPING_TOGGLE + +#define DEFAULT_2C_STYLE 1 // enable 2 click turbo + + +// AUX + +// this light has three aux LED channels: R, G, B +#define USE_AUX_RGB_LEDS + +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// blink numbers on the main LEDs by default +#define DEFAULT_BLINK_CHANNEL CM_MAIN + +// use aux red + aux blue for police strobe +#define USE_POLICE_COLOR_STROBE_MODE +#define POLICE_STROBE_USES_AUX +#define POLICE_COLOR_STROBE_CH1 CM_AUXRED +#define POLICE_COLOR_STROBE_CH2 CM_AUXBLU + +// the aux LEDs are front-facing, so turn them off while main LEDs are on +#ifdef USE_INDICATOR_LED_WHILE_RAMPING +#undef USE_INDICATOR_LED_WHILE_RAMPING +#endif + + +// Misc + +#define PARTY_STROBE_ONTIME 1 // slow down party strobe +#define STROBE_OFF_LEVEL 1 // keep the regulator chip on between pulses + +// smoother candle mode with bigger oscillations +#define CANDLE_AMPLITUDE 40 + +// enable 13H factory reset so it can be used on tail e-switch lights +#define USE_SOFT_FACTORY_RESET + diff --git a/spaghetti-monster/anduril/cfg-thefreeman-boost21-6a.h b/spaghetti-monster/anduril/cfg-thefreeman-boost21-6a.h index 76ea9ab..66cc2d0 100644 --- a/spaghetti-monster/anduril/cfg-thefreeman-boost21-6a.h +++ b/spaghetti-monster/anduril/cfg-thefreeman-boost21-6a.h @@ -70,7 +70,7 @@ // UI -//#define SIMPLE_UI_ACTIVE 1 // advanced UI by default +//#define SIMPLE_UI_ACTIVE 0 // advanced UI by default // allow Aux Config and Strobe Modes in Simple UI #define USE_EXTENDED_SIMPLE_UI @@ -108,9 +108,12 @@ // Misc -#define PARTY_STROBE_ONTIME 1 // slow down party strobe +#define PARTY_STROBE_ONTIME 1 // slow down party strobe #define STROBE_OFF_LEVEL 1 // keep the regulator chip on between pulses +// smoother candle mode with bigger oscillations +#define CANDLE_AMPLITUDE 40 + // enable 13H factory reset so it can be used on tail e-switch lights #define USE_SOFT_FACTORY_RESET -- cgit v1.2.3 From 67baddcbc8bf0abda618755654b30e2bd1b324f2 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 5 Oct 2023 10:28:24 -0600 Subject: fixed bug: globals menu missed a step when tint ramping wasn't compiled in --- spaghetti-monster/anduril/ramp-mode.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/ramp-mode.h b/spaghetti-monster/anduril/ramp-mode.h index 21e2149..615da87 100644 --- a/spaghetti-monster/anduril/ramp-mode.h +++ b/spaghetti-monster/anduril/ramp-mode.h @@ -188,7 +188,8 @@ void reset_sunset_timer(); #ifdef USE_RAMP_EXTRAS_CONFIG typedef enum { - manual_memory_config_step = 1, + ramp_extras_cfg_zero = 0, + manual_memory_config_step, #ifdef USE_MANUAL_MEMORY_TIMER manual_memory_timer_config_step, #endif @@ -207,8 +208,9 @@ typedef enum { #ifdef USE_GLOBALS_CONFIG typedef enum { + globals_cfg_zero = 0, #if defined(USE_CHANNEL_MODE_ARGS) && defined(USE_STEPPED_TINT_RAMPING) - tint_style_config_step = 1, + tint_style_config_step, #endif #ifdef USE_JUMP_START jump_start_config_step, -- cgit v1.2.3 From 402b2893e8fb19a05a3e5cca6b703faca8907b8b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 6 Oct 2023 11:02:24 -0600 Subject: smooth steps: fixed a few corner cases - Off -> 1H - Off -> 2H and release - Off -> 2C - Off -> 3C or more - Ramp -> 2C (in smooth ramp mode) ... also reduced ROM size a bit. Now it does smooth animations for 2C turbo, regardless of the current ramp mode. Before, in smooth ramp mode, 2C turbo did a hard step. Hard steps were also eliminated for 1H from Off, momentary turbo from Off, regular turbo from Off, and anything longer than 2C from Off. --- spaghetti-monster/anduril/off-mode.c | 40 +++++++++++++++++++++-------------- spaghetti-monster/anduril/ramp-mode.c | 6 +++++- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/spaghetti-monster/anduril/off-mode.c b/spaghetti-monster/anduril/off-mode.c index af09d70..0a381b7 100644 --- a/spaghetti-monster/anduril/off-mode.c +++ b/spaghetti-monster/anduril/off-mode.c @@ -10,17 +10,20 @@ #include "sunset-timer.h" #endif +// set level smooth maybe +void off_state_set_level(uint8_t level); + + uint8_t off_state(Event event, uint16_t arg) { // turn emitter off when entering state if (event == EV_enter_state) { + // turn off + off_state_set_level(0); #ifdef USE_SMOOTH_STEPS - if (cfg.smooth_steps_style && actual_level) { - set_level_smooth(0, 8); - arg = 1; // don't go to sleep immediately - } else + // don't go to sleep while animating + arg |= smooth_steps_in_progress; #endif - set_level(0); ticks_since_on = 0; #if NUM_CHANNEL_MODES > 1 // reset to ramp mode's channel when light turns off @@ -92,7 +95,7 @@ uint8_t off_state(Event event, uint16_t arg) { #if (B_TIMING_ON == B_PRESS_T) // hold (initially): go to lowest level (floor), but allow abort for regular click else if (event == EV_click1_press) { - set_level(nearest_level(1)); + off_state_set_level(nearest_level(1)); return EVENT_HANDLED; } #endif // B_TIMING_ON == B_PRESS_T @@ -107,7 +110,7 @@ uint8_t off_state(Event event, uint16_t arg) { } else #endif #else // B_RELEASE_T or B_TIMEOUT_T - set_level(nearest_level(1)); + off_state_set_level(nearest_level(1)); #endif #ifdef USE_RAMP_AFTER_MOON_CONFIG if (cfg.dont_ramp_after_moon) { @@ -139,12 +142,7 @@ uint8_t off_state(Event event, uint16_t arg) { manual_memory_restore(); } #endif - #ifdef USE_SMOOTH_STEPS - if (cfg.smooth_steps_style) - set_level_smooth(nearest_level(memorized_level), 8); - else - #endif - set_level(nearest_level(memorized_level)); + off_state_set_level(nearest_level(memorized_level)); return EVENT_HANDLED; } #endif // if (B_TIMING_ON != B_TIMEOUT_T) @@ -186,11 +184,11 @@ uint8_t off_state(Event event, uint16_t arg) { turbo_level = MAX_LEVEL; #endif - set_level(turbo_level); + off_state_set_level(turbo_level); return EVENT_HANDLED; } else if (event == EV_click2_hold_release) { - set_level(0); + off_state_set_level(0); return EVENT_HANDLED; } @@ -206,7 +204,7 @@ uint8_t off_state(Event event, uint16_t arg) { // immediately cancel any animations in progress smooth_steps_in_progress = 0; #endif - set_level(0); + off_state_set_level(0); return EVENT_HANDLED; } @@ -374,3 +372,13 @@ uint8_t off_state(Event event, uint16_t arg) { return EVENT_NOT_HANDLED; } + +void off_state_set_level(uint8_t level) { + // this pattern gets used a few times, so reduce duplication + #ifdef USE_SMOOTH_STEPS + if (cfg.smooth_steps_style) set_level_smooth(level, 8); + else + #endif + set_level(level); +} + diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index 87bfe63..019fa2a 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -680,8 +680,12 @@ void set_level_and_therm_target(uint8_t level) { target_level = level; #endif #ifdef USE_SMOOTH_STEPS + // if adjusting by more than 1 ramp level, + // animate the step change (if smooth steps enabled) + uint8_t diff = (level > actual_level) + ? (level - actual_level) : (actual_level - level); if (smooth_steps_in_progress - || (cfg.smooth_steps_style && cfg.ramp_style)) + || (cfg.smooth_steps_style && (diff > 1))) set_level_smooth(level, 4); else #endif -- cgit v1.2.3 From 4b6d6be3b26460bb81b41efcae63cac3a578dfb7 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 9 Oct 2023 10:54:18 -0600 Subject: converted old MF01S / MT18S build --- hwdef-Mateminco_MF01S.h | 61 -------------- hwdef-mateminco-mf01s.h | 101 ++++++++++++++++++++++++ spaghetti-monster/anduril/cfg-mateminco-mf01s.h | 22 ++++-- 3 files changed, 116 insertions(+), 68 deletions(-) delete mode 100644 hwdef-Mateminco_MF01S.h create mode 100644 hwdef-mateminco-mf01s.h diff --git a/hwdef-Mateminco_MF01S.h b/hwdef-Mateminco_MF01S.h deleted file mode 100644 index 0ae30a6..0000000 --- a/hwdef-Mateminco_MF01S.h +++ /dev/null @@ -1,61 +0,0 @@ -// MF01S driver layout -// Copyright (C) 2019-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * ---- - * Reset -|1 8|- VCC (unused) - * eswitch -|2 7|- Voltage divider (2S) - * AUX LED -|3 6|- PWM (FET) - * GND -|4 5|- PWM (smaller FET) - * ---- - */ - -#define PWM_CHANNELS 2 - -#ifndef AUXLED_PIN -#define AUXLED_PIN PB4 // pin 3 -#endif - -#ifndef SWITCH_PIN -#define SWITCH_PIN PB3 // pin 2 -#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt -#endif - -#ifndef PWM1_PIN -#define PWM1_PIN PB0 // pin 5, 1x7135 PWM -#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 -#endif -#ifndef PWM2_PIN -#define PWM2_PIN PB1 // pin 6, FET PWM -#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 -#endif - -#define USE_VOLTAGE_DIVIDER // use a voltage divider on pin 7, not VCC -#ifndef VOLTAGE_PIN -#define VOLTAGE_PIN PB2 // pin 7, voltage ADC -#define VOLTAGE_CHANNEL 0x01 // MUX 01 corresponds with PB2 -#define VOLTAGE_ADC ADC1D // Digital input disable bit corresponding with PB2 -// inherited from tk-attiny.h -//#define VOLTAGE_ADC_DIDR DIDR0 // DIDR for ADC1 -// 1.1V reference, left-adjust, ADC1/PB2 -//#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | (1 << ADLAR) | VOLTAGE_CHANNEL) -// 1.1V reference, no left-adjust, ADC1/PB2 -#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | VOLTAGE_CHANNEL) -#endif -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V (in-between, we assume values form a straight line) -#ifndef ADC_44 -#define ADC_44 (234*4) -#endif -#ifndef ADC_22 -#define ADC_22 (117*4) -#endif - -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels - -#define LAYOUT_DEFINED - diff --git a/hwdef-mateminco-mf01s.h b/hwdef-mateminco-mf01s.h new file mode 100644 index 0000000..14cf76b --- /dev/null +++ b/hwdef-mateminco-mf01s.h @@ -0,0 +1,101 @@ +// Mateminco MT18S / Astrolux MF01S driver layout +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * ---- + * Reset -|1 8|- VCC (unused) + * eswitch -|2 7|- Voltage divider (2S) + * AUX LED -|3 6|- PWM (FET) + * GND -|4 5|- PWM (smaller FET) + * ---- + */ + +#define ATTINY 85 +#include + +#define HWDEF_C_FILE hwdef-emisar-d4.c + +// channel modes +// * 0. FET+7135 stacked +#define NUM_CHANNEL_MODES 1 +enum CHANNEL_MODES { + CM_MAIN = 0, +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00000001 + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 8 // attiny85 only supports up to 8 bits +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define PWM_DATATYPE2 uint16_t +#define PWM1_DATATYPE uint8_t // little FET ramp +#define PWM2_DATATYPE uint8_t // big FET ramp + +#define PWM_TOP_INIT 255 // highest value used in top half of ramp + +// little FET channel +#define CH1_PIN PB0 // pin 5, 1x7135 PWM +#define CH1_PWM OCR0A // OCR0A is the output compare register for PB0 + +// big FET channel +#define CH2_PIN PB1 // pin 6, FET PWM +#define CH2_PWM OCR0B // OCR0B is the output compare register for PB1 + +#define AUXLED_PIN PB4 // pin 3 + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt +#endif + +#define USE_VOLTAGE_DIVIDER // use a voltage divider on pin 7, not VCC +#ifndef VOLTAGE_PIN +#define VOLTAGE_PIN PB2 // pin 7, voltage ADC +#define VOLTAGE_CHANNEL 0x01 // MUX 01 corresponds with PB2 +#define VOLTAGE_ADC ADC1D // Digital input disable bit corresponding with PB2 +// inherited from tk-attiny.h +//#define VOLTAGE_ADC_DIDR DIDR0 // DIDR for ADC1 +// 1.1V reference, left-adjust, ADC1/PB2 +//#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | (1 << ADLAR) | VOLTAGE_CHANNEL) +// 1.1V reference, no left-adjust, ADC1/PB2 +#define ADMUX_VOLTAGE_DIVIDER ((1 << V_REF) | VOLTAGE_CHANNEL) +#endif +#define ADC_PRSCL 0x07 // clk/128 + +// Raw ADC readings at 4.4V and 2.2V (in-between, we assume values form a straight line) +#ifndef ADC_44 +#define ADC_44 (234*4) +#endif +#ifndef ADC_22 +#define ADC_22 (117*4) +#endif + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + + +inline void hwdef_setup() { + // configure PWM channels + DDRB = (1 << CH1_PIN) + | (1 << CH2_PIN); + + TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) + TCCR0A = PHASE; + + // configure e-switch + PORTB = (1 << SWITCH_PIN); // e-switch is the only input + PCMSK = (1 << SWITCH_PIN); // pin change interrupt uses this pin +} + + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/cfg-mateminco-mf01s.h b/spaghetti-monster/anduril/cfg-mateminco-mf01s.h index 20bcccd..de92693 100644 --- a/spaghetti-monster/anduril/cfg-mateminco-mf01s.h +++ b/spaghetti-monster/anduril/cfg-mateminco-mf01s.h @@ -1,10 +1,11 @@ -// Mateminco/Astrolux MF01S options for Anduril +// Mateminco MT18S / Astrolux MF01S options for Anduril // Copyright (C) 2019-2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #define MODEL_NUMBER "0511" -#include "hwdef-Mateminco_MF01S.h" +#include "hwdef-mateminco-mf01s.h" +// ATTINY: 85 // the button lights up #define USE_INDICATOR_LED @@ -15,10 +16,7 @@ #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) -// don't blink during ramp, it's irrelevant and annoying on this light -#define BLINK_AT_RAMP_CEIL -#undef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_FLOOR +#define RAMP_SIZE 150 // measured brightness with 4x30Q cells at 4.11V: // moon: 2.5 lm @@ -26,9 +24,9 @@ // channel 2: 13500 lm // ../../../bin/level_calc.py seventh 2 150 7135 1 12 717 FET 1 10 13000 // (with some manual tweaks afterward) -#define RAMP_LENGTH 150 #define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,5,6,7,7,8,9,10,11,12,13,14,15,17,18,19,21,22,24,26,28,30,32,34,36,38,41,44,46,49,52,55,59,62,66,70,74,78,83,87,92,97,102,108,114,120,126,133,139,147,154,162,170,178,187,196,206,215,226,236,248,255,235,255,240,255,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,3,3,4,4,5,6,7,8,9,10,11,12,13,14,16,17,19,20,22,23,25,26,28,30,31,33,35,37,39,41,43,45,47,49,52,54,57,59,62,65,67,70,73,76,80,83,86,90,93,97,101,105,109,113,117,122,126,131,135,140,145,151,156,161,167,173,179,185,191,197,204,211,218,225,232,239,247,255 + #define MAX_1x7135 70 // ~626 lm #define HALFSPEED_LEVEL 23 #define QUARTERSPEED_LEVEL 6 @@ -49,5 +47,15 @@ #define THERM_FASTER_LEVEL 125 // throttle back faster when high (>6000 lm) #define THERM_HARD_TURBO_DROP // this light is massively overpowered +// don't blink during ramp, it's irrelevant and annoying on this light +#define BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_FLOOR + +// enable extra features +#define USE_SMOOTH_STEPS + // too big, turn off extra features #undef USE_TACTICAL_MODE +#undef USE_SOS_MODE + -- cgit v1.2.3 From f79b92ab88cbe0a0e4c4dcd4f5520c86a1b7f26b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 9 Oct 2023 12:59:24 -0600 Subject: reduced @wurkoss-ts10 smooth ramp ceiling from 150 to 130 (150 was a misunderstanding, and is too high) --- spaghetti-monster/anduril/cfg-wurkkos-ts10-rgbaux.h | 2 +- spaghetti-monster/anduril/cfg-wurkkos-ts10.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts10-rgbaux.h b/spaghetti-monster/anduril/cfg-wurkkos-ts10-rgbaux.h index 4350828..6770c47 100644 --- a/spaghetti-monster/anduril/cfg-wurkkos-ts10-rgbaux.h +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts10-rgbaux.h @@ -43,7 +43,7 @@ #define DEFAULT_LEVEL 50 #define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 150 +#define RAMP_SMOOTH_CEIL 130 // 20 38 56 [75] 93 111 130 // 10 30 50 70 [90] 110 130 #define RAMP_DISCRETE_FLOOR 10 diff --git a/spaghetti-monster/anduril/cfg-wurkkos-ts10.h b/spaghetti-monster/anduril/cfg-wurkkos-ts10.h index 0819e42..90839e7 100644 --- a/spaghetti-monster/anduril/cfg-wurkkos-ts10.h +++ b/spaghetti-monster/anduril/cfg-wurkkos-ts10.h @@ -50,7 +50,7 @@ #define DEFAULT_LEVEL 50 #define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 150 +#define RAMP_SMOOTH_CEIL 130 // 10 30 50 70 [90] 110 130 #define RAMP_DISCRETE_FLOOR 10 #define RAMP_DISCRETE_CEIL 130 -- cgit v1.2.3 From 0ea7d6618d192376e81323bf646a2a78ab5ed34d Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 9 Oct 2023 18:01:21 -0600 Subject: converted sofirn-sp10-pro to new API --- hwdef-Sofirn_SP10-Pro.h | 142 --------------------- hwdef-sofirn-sp10-pro.c | 63 ++++++++++ hwdef-sofirn-sp10-pro.h | 157 ++++++++++++++++++++++++ spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h | 62 +++++----- 4 files changed, 250 insertions(+), 174 deletions(-) delete mode 100644 hwdef-Sofirn_SP10-Pro.h create mode 100644 hwdef-sofirn-sp10-pro.c create mode 100644 hwdef-sofirn-sp10-pro.h diff --git a/hwdef-Sofirn_SP10-Pro.h b/hwdef-Sofirn_SP10-Pro.h deleted file mode 100644 index 6bc26ea..0000000 --- a/hwdef-Sofirn_SP10-Pro.h +++ /dev/null @@ -1,142 +0,0 @@ -// Sofirn SP10 Pro pinout -// Copyright (C) 2022-2023 (FIXME) -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * ATTINY1616 Mapping: - * PB5 : PWM small channel (TCA0 - WO2 Alternate MUX) - * PB3 : eSwitch - * PB0 : PWM big channel (TCA0 - WO0) - * PB4 : Voltage divider (ADC0 - AIN9) - * PA1 : Boost Enable - */ - - -#define LAYOUT_DEFINED - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1616 -#include - -#ifndef SWITCH_PIN -#define SWITCH_PIN 3 -#define SWITCH_PORT VPORTB.IN -#define SWITCH_ISC_REG PORTB.PIN3CTRL -#define SWITCH_VECT PORTB_PORT_vect -#define SWITCH_INTFLG VPORTB.INTFLAGS -#endif - -#define PWM_CHANNELS 2 -#define PWM_BITS 16 // data type needs 16 bits, not 8 -#define PWM_TOP 255 // highest value used in top half of ramp -#define USE_DYN_PWM // dynamic frequency and speed - -// Small channel -#ifndef PWM1_PIN -#define PWM1_PIN PB5 -#define PWM1_LVL TCA0.SINGLE.CMP2BUF // PB5 is Alternate MUX for TCA Compare 2 -#endif - -// Big channel -#ifndef PWM2_PIN -#define PWM2_PIN PB0 -#define PWM2_LVL TCA0.SINGLE.CMP0BUF // PB0 is TCA Compare 0 -#endif - -// PWM parameters of both channels are tied together because they share a counter -#define PWM1_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM -// not necessary when double-buffered "BUF" registers are used -#define PWM1_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment -#define PWM1_PHASE_RESET_OFF // force reset while shutting off -#define PWM1_PHASE_RESET_ON // force reset while turning on -//#define PWM1_PHASE_SYNC // manual sync while changing level - -#define LED_ENABLE_PIN PIN1_bp -#define LED_ENABLE_PORT PORTA_OUT -//#define LED_OFF_DELAY 4 // only needed when PWM1_PHASE_RESET_OFF not used - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define DUAL_VOLTAGE_FLOOR 21 // for AA/14500 boost drivers, don't indicate low voltage if below this level -#define DUAL_VOLTAGE_LOW_LOW 7 // the lower voltage range's danger zone 0.7 volts (NiMH) -#define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN9_gc // which ADC channel to read - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// Resistors are 300,000 and 100,000 -#ifndef ADC_44 -#define ADC_44 1023 // raw value at 4.40V -#endif -#ifndef ADC_22 -#define ADC_22 512 // raw value at 2.20V -#endif - - - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - - // set up the system clock to run at 10 MHz instead of the default 3.33 MHz - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); - - VPORTA.DIR = PIN1_bm; // Boost enable pin - VPORTB.DIR = PIN0_bm | PIN5_bm; // PWM pins as output - //VPORTC.DIR = ...; - - // enable pullups on the input pins to reduce power - PORTA.PIN0CTRL = PORT_PULLUPEN_bm; - //PORTA.PIN1CTRL = PORT_PULLUPEN_bm; // Boost enable pin - PORTA.PIN2CTRL = PORT_PULLUPEN_bm; - PORTA.PIN3CTRL = PORT_PULLUPEN_bm; - PORTA.PIN4CTRL = PORT_PULLUPEN_bm; - PORTA.PIN5CTRL = PORT_PULLUPEN_bm; - PORTA.PIN6CTRL = PORT_PULLUPEN_bm; - PORTA.PIN7CTRL = PORT_PULLUPEN_bm; - - //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // Big PWM channel - PORTB.PIN1CTRL = PORT_PULLUPEN_bm; - PORTB.PIN2CTRL = PORT_PULLUPEN_bm; - PORTB.PIN3CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // Switch - //PORTB.PIN4CTRL = PORT_PULLUPEN_bm; // Voltage divider - //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Small PWM channel - - PORTC.PIN0CTRL = PORT_PULLUPEN_bm; - PORTC.PIN1CTRL = PORT_PULLUPEN_bm; - PORTC.PIN2CTRL = PORT_PULLUPEN_bm; - PORTC.PIN3CTRL = PORT_PULLUPEN_bm; - - // set up the PWM - // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf - // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm - // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm - // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm - // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc - // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc - // See the manual for other pins, clocks, configs, portmux, etc - PORTMUX.CTRLC = PORTMUX_TCA02_ALTERNATE_gc; // Use alternate pin for TCA0:WO2 - TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP2EN_bm | TCA_SINGLE_WGMODE_DSBOTTOM_gc; - PWM1_TOP = PWM_TOP; - TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; -} - - -// set fuses, these carry over to the ELF file -// we need this for enabling BOD in Active Mode from the factory. -// settings can be verified / dumped from the ELF file using this -// command: avr-objdump -d -S -j .fuse anduril.elf -FUSES = { - .WDTCFG = FUSE_WDTCFG_DEFAULT, // Watchdog Configuration - .BODCFG = FUSE_ACTIVE0_bm, // BOD Configuration - .OSCCFG = FUSE_OSCCFG_DEFAULT, // Oscillator Configuration - .TCD0CFG = FUSE_TCD0CFG_DEFAULT, // TCD0 Configuration - .SYSCFG0 = FUSE_SYSCFG0_DEFAULT, // System Configuration 0 - .SYSCFG1 = FUSE_SYSCFG1_DEFAULT, // System Configuration 1 - .APPEND = FUSE_APPEND_DEFAULT, // Application Code Section End - .BOOTEND = FUSE_BOOTEND_DEFAULT, // Boot Section End -}; - diff --git a/hwdef-sofirn-sp10-pro.c b/hwdef-sofirn-sp10-pro.c new file mode 100644 index 0000000..42844a7 --- /dev/null +++ b/hwdef-sofirn-sp10-pro.c @@ -0,0 +1,63 @@ +// Sofirn SP10 Pro PWM helper functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +void set_level_zero(); + +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // main LEDs + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, +}; + + +void set_level_zero() { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; // reset phase + BST_ENABLE_PORT &= ~(1 << BST_ENABLE_PIN); // boost off +} + +// single set of LEDs with 2 stacked power channels +void set_level_main(uint8_t level) { + PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); + PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); + // pulse frequency modulation, a.k.a. dynamic PWM + uint16_t top = PWM_GET16(pwm_tops, level); + + BST_ENABLE_PORT |= (1 << BST_ENABLE_PIN); // boost on + + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; + PWM_TOP = top; + + // force reset phase when turning on from zero + // (because otherwise the initial response is inconsistent) + if (! actual_level) PWM_CNT = 0; +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE pwm2 = PWM_GET(pwm2_levels, gt); + + // ch1 sometimes makes huge leaps; don't make it gradual + // if either current or new level is in the leap zone, just leap + if ((CH1_PWM + pwm1) > 128) CH1_PWM = pwm1; + else GRADUAL_ADJUST_SIMPLE(pwm1, CH1_PWM); + + GRADUAL_ADJUST_SIMPLE(pwm2, CH2_PWM); + + if ( (pwm1 == CH1_PWM) + && (pwm2 == CH2_PWM) + ) { + return true; // done + } + return false; // not done yet +} + diff --git a/hwdef-sofirn-sp10-pro.h b/hwdef-sofirn-sp10-pro.h new file mode 100644 index 0000000..5ed22c7 --- /dev/null +++ b/hwdef-sofirn-sp10-pro.h @@ -0,0 +1,157 @@ +// Sofirn SP10 Pro pinout +// Copyright (C) 2022-2023 (original author TBD), Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * ATTINY1616 Mapping: + * PB5 : PWM small channel (TCA0 - WO2 Alternate MUX) + * PB3 : eSwitch + * PB0 : PWM big channel (TCA0 - WO0) + * PB4 : Voltage divider (ADC0 - AIN9) + * PA1 : Boost Enable + */ + +#define ATTINY 1616 +#include + +#define HWDEF_C_FILE hwdef-sofirn-sp10-pro.c + +// channel modes: +// * 0. low+high PWM stacked +#define NUM_CHANNEL_MODES 1 +enum CHANNEL_MODES { + CM_MAIN = 0, +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00000001 + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 16 // data type needs 16 bits, not 8 +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // low PWM ramp +#define PWM2_DATATYPE uint16_t // high PWM ramp + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM +#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment +#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) + +// Small channel +#define CH1_PIN PB5 +#define CH1_PWM TCA0.SINGLE.CMP2BUF // PB5 is Alternate MUX for TCA Compare 2 + +// Big channel +#define CH2_PIN PB0 +#define CH2_PWM TCA0.SINGLE.CMP0BUF // PB0 is TCA Compare 0 + +// boost enable +#define BST_ENABLE_PIN PIN1_bp +#define BST_ENABLE_PORT PORTA_OUT + +// e-switch +#define SWITCH_PIN 3 +#define SWITCH_PORT VPORTB.IN +#define SWITCH_ISC_REG PORTB.PIN3CTRL +#define SWITCH_VECT PORTB_PORT_vect +#define SWITCH_INTFLG VPORTB.INTFLAGS +#define SWITCH_PCINT PCINT0 +#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] + +// Voltage divider battLVL +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated +#define DUAL_VOLTAGE_FLOOR 21 // for AA/14500 boost drivers, don't indicate low voltage if below this level +#define DUAL_VOLTAGE_LOW_LOW 7 // the lower voltage range's danger zone 0.7 volts (NiMH) +#define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN9_gc // which ADC channel to read + +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// Resistors are 300,000 and 100,000 +#ifndef ADC_44 +#define ADC_44 1023 // raw value at 4.40V +#endif +#ifndef ADC_22 +#define ADC_22 512 // raw value at 2.20V +#endif + + + +inline void hwdef_setup() { + + // set up the system clock to run at 10 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, + CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + + VPORTA.DIR = PIN1_bm; // Boost enable pin + VPORTB.DIR = PIN0_bm // big PWM channel + | PIN5_bm; // small PWM channel + //VPORTC.DIR = ...; + + // enable pullups on the input pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + //PORTA.PIN1CTRL = PORT_PULLUPEN_bm; // Boost enable pin + PORTA.PIN2CTRL = PORT_PULLUPEN_bm; + PORTA.PIN3CTRL = PORT_PULLUPEN_bm; + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm; + PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // Big PWM channel + PORTB.PIN1CTRL = PORT_PULLUPEN_bm; + PORTB.PIN2CTRL = PORT_PULLUPEN_bm; + PORTB.PIN3CTRL = PORT_PULLUPEN_bm + | PORT_ISC_BOTHEDGES_gc; // e-switch + //PORTB.PIN4CTRL = PORT_PULLUPEN_bm; // Voltage divider + //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Small PWM channel + + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + + // set up the PWM + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf + // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm + // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm + // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm + // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc + // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc + // See the manual for other pins, clocks, configs, portmux, etc + PORTMUX.CTRLC = PORTMUX_TCA02_ALTERNATE_gc; // Use alternate pin for TCA0:WO2 + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm + | TCA_SINGLE_CMP2EN_bm + | TCA_SINGLE_WGMODE_DSBOTTOM_gc; + PWM_TOP = PWM_TOP_INIT; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc + | TCA_SINGLE_ENABLE_bm; +} + + +// set fuses, these carry over to the ELF file +// we need this for enabling BOD in Active Mode from the factory. +// settings can be verified / dumped from the ELF file using this +// command: avr-objdump -d -S -j .fuse anduril.elf +FUSES = { + .WDTCFG = FUSE_WDTCFG_DEFAULT, // Watchdog Configuration + .BODCFG = FUSE_ACTIVE0_bm, // BOD Configuration + .OSCCFG = FUSE_OSCCFG_DEFAULT, // Oscillator Configuration + .TCD0CFG = FUSE_TCD0CFG_DEFAULT, // TCD0 Configuration + .SYSCFG0 = FUSE_SYSCFG0_DEFAULT, // System Configuration 0 + .SYSCFG1 = FUSE_SYSCFG1_DEFAULT, // System Configuration 1 + .APPEND = FUSE_APPEND_DEFAULT, // Application Code Section End + .BOOTEND = FUSE_BOOTEND_DEFAULT, // Boot Section End +}; + + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h b/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h index 3a02fc2..d9ac882 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h @@ -4,48 +4,37 @@ #pragma once #define MODEL_NUMBER "0631" -#include "hwdef-Sofirn_SP10-Pro.h" +#include "hwdef-sofirn-sp10-pro.h" // ATTINY: 1616 -// don't blink during the ramp or at the ceiling -#ifdef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_MIDDLE -#endif -#ifdef BLINK_AT_RAMP_CEIL -#undef BLINK_AT_RAMP_CEIL -#endif - -#define USE_DYNAMIC_UNDERCLOCKING - // 1....15: level_calc.py 3.01 1 15 7135 1 0.1 2 --pwm dyn:15:64:64 // 16..150: level_calc.py 5.01 1 135 7135 1 2 800 --pwm dyn:49:3072:255:3.0 -#define RAMP_LENGTH 150 -#define USE_DYN_PWM -#define _PWM1_LEVELS_ 1,2,4,6,9,12,15,19,23,28,34,41,48,55,64 -#define _PWM1_TOPS_ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64 -#define _PWM2_LEVELS_ 1,1,2,2,3,3,4,4,5,5,6,6,6,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,10,10,10,11,11,12,13,13,14,15,15,16,17,18,18,19,20,21,22,23,24,25,26,27,28,29,30,31,33,34,35,37,38,39,41,42,44,46,47,49,51,53,55,57,59,61,63,65,67,70,72,74,77,79,82,85,88,90,93,96,99,103,106,109,113,116,120,123,127,131,135,139,143,147,151,156,160,165,170,175,180,185,190,195,201,206,212,218,223,230,236,242,248,255 -#define _PWM2_TOPS_ 3072,1960,2372,1476,2097,1572,1920,1570,1777,1524,1646,1454,1286,1369,1234,1115,1011,918,837,894,823,759,702,650,603,560,522,487,455,425,398,374,351,330,310,292,275,259,280,265,251,266,253,240,252,240,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 -#define PWM1_LEVELS _PWM1_LEVELS_,_PWM2_TOPS_ -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,_PWM2_LEVELS_ -#define PWM_TOPS _PWM1_TOPS_,_PWM2_TOPS_ - -#define MAX_1x7135 15 -#define HALFSPEED_LEVEL 15 +#define RAMP_SIZE 150 +#define _PWM1_LEVELS_ 1, 2, 4, 6, 9,12,15,19,23,28,34,41,48,55,64 +#define _PWM1_TOPS_ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64 +#define _PWM2_LEVELS_ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 13, 13, 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 37, 38, 39, 41, 42, 44, 46, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 70, 72, 74, 77, 79, 82, 85, 88, 90, 93, 96, 99,103,106,109,113,116,120,123,127,131,135,139,143,147,151,156,160,165,170,175,180,185,190,195,201,206,212,218,223,230,236,242,248,255 +#define _PWM2_TOPS_ 3072,1960,2372,1476,2097,1572,1920,1570,1777,1524,1646,1454,1286,1369,1234,1115,1011,918,837,894,823,759,702,650,603,560,522,487,455,425,398,374,351,330,310,292,275,259,280,265,251,266,253,240,252,240,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#define PWM1_LEVELS _PWM1_LEVELS_,_PWM2_TOPS_ +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,_PWM2_LEVELS_ +#define PWM_TOPS _PWM1_TOPS_,_PWM2_TOPS_ + +#define MAX_1x7135 15 +#define HALFSPEED_LEVEL 15 #define QUARTERSPEED_LEVEL 15 -#define DEFAULT_LEVEL 75 +#define DEFAULT_LEVEL 50 -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 150 +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 150 // 1 25 50 [75] 100 125 150 -#define RAMP_DISCRETE_FLOOR 1 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 7 +#define RAMP_DISCRETE_FLOOR 1 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 // at Sofirn's request, use max (150) for the Simple UI ceiling // 15 48 [82] 116 150 -#define SIMPLE_UI_FLOOR MAX_1x7135 -#define SIMPLE_UI_CEIL 150 -#define SIMPLE_UI_STEPS 5 +#define SIMPLE_UI_FLOOR MAX_1x7135 +#define SIMPLE_UI_CEIL 150 +#define SIMPLE_UI_STEPS 5 // turn on at ~6 lm by default (level 50/150, or ramp step 2/5 or 3/7) // (also sets lockout mode 2H to a useful level) @@ -78,6 +67,15 @@ // enable 2 click turbo (replaces USE_2C_MAX_TURBO) #define DEFAULT_2C_STYLE 1 +// don't blink during the ramp or at the ceiling +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif +#ifdef BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_CEIL +#endif + + // enable factory reset on 13H without loosening tailcap #define USE_SOFT_FACTORY_RESET -- cgit v1.2.3 From 55b5ad0665bb362dc266fd1ed79aa62bb17cd94e Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 10 Oct 2023 22:32:00 -0600 Subject: converted FW3A to new API (my FW3A dev host is dead though, so the DD FET channel isn't 100% confirmed to work ... will have to solder together a new dev host at some point) --- hwdef-FW3A.h | 51 -------------- hwdef-fw3a.c | 71 +++++++++++++++++++ hwdef-fw3a.h | 105 +++++++++++++++++++++++++++++ spaghetti-monster/anduril/cfg-fw3a-219.h | 1 + spaghetti-monster/anduril/cfg-fw3a-nofet.h | 13 +++- spaghetti-monster/anduril/cfg-fw3a.h | 34 ++++++++-- 6 files changed, 214 insertions(+), 61 deletions(-) delete mode 100644 hwdef-FW3A.h create mode 100644 hwdef-fw3a.c create mode 100644 hwdef-fw3a.h diff --git a/hwdef-FW3A.h b/hwdef-FW3A.h deleted file mode 100644 index f2b5c8d..0000000 --- a/hwdef-FW3A.h +++ /dev/null @@ -1,51 +0,0 @@ -// BLF/TLF FW3A driver layout -// Copyright (C) 2018-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * ---- - * Reset -|1 8|- VCC - * eswitch -|2 7|- optic nerve - * FET -|3 6|- 7x7135 - * GND -|4 5|- 1x7135 - * ---- - */ - -#define PWM_CHANNELS 3 - -#ifndef SWITCH_PIN -#define SWITCH_PIN PB3 // pin 2 -#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt -#endif - -#ifndef PWM1_PIN -#define PWM1_PIN PB0 // pin 5, 1x7135 PWM -#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 -#endif -#ifndef PWM2_PIN -#define PWM2_PIN PB1 // pin 6, 7x7135 PWM -#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 -#endif -#ifndef PWM3_PIN -#define PWM3_PIN PB4 // pin 3, FET PWM -#define PWM3_LVL OCR1B // OCR1B is the output compare register for PB4 -#endif - -#ifndef VISION_PIN -#define VISION_PIN PB2 // pin 7, optic nerve -//#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 -//#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 -#endif -#define ADC_PRSCL 0x07 // clk/128 - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V -#endif - -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels - -#define LAYOUT_DEFINED - diff --git a/hwdef-fw3a.c b/hwdef-fw3a.c new file mode 100644 index 0000000..b20969d --- /dev/null +++ b/hwdef-fw3a.c @@ -0,0 +1,71 @@ +// BLF/TLF FW3A PWM helper functions +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +void set_level_zero(); + +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // main LEDs + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, +}; + + +void set_level_zero() { + CH1_PWM = 0; + CH2_PWM = 0; + #ifdef CH3_PIN + CH3_PWM = 0; + #endif +} + +// TODO: implement delta-sigma modulation for better low modes + +// single set of LEDs with 3 stacked power channels, FET+N+1 +// (or just use N+1 on the no-FET model or FET+1 model) +void set_level_main(uint8_t level) { + PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); + PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); + #ifdef CH3_PIN + PWM_DATATYPE ch3_pwm = PWM_GET(pwm3_levels, level); + #endif + + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; + #ifdef CH3_PIN + CH3_PWM = ch3_pwm; + #endif +} + +bool gradual_tick_main(uint8_t gt) { + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE pwm2 = PWM_GET(pwm2_levels, gt); + #ifdef CH3_PIN + PWM_DATATYPE pwm3 = PWM_GET(pwm3_levels, gt); + #endif + + GRADUAL_ADJUST_STACKED(pwm1, CH1_PWM, PWM_TOP_INIT); + #ifdef CH3_PIN + GRADUAL_ADJUST_STACKED(pwm2, CH2_PWM, PWM_TOP_INIT); + GRADUAL_ADJUST_SIMPLE (pwm3, CH3_PWM); + #else + GRADUAL_ADJUST_SIMPLE (pwm2, CH2_PWM); + #endif + + if ( (pwm1 == CH1_PWM) + && (pwm2 == CH2_PWM) + #ifdef CH3_PIN + && (pwm3 == CH3_PWM) + #endif + ) { + return true; // done + } + return false; // not done yet +} + diff --git a/hwdef-fw3a.h b/hwdef-fw3a.h new file mode 100644 index 0000000..519fb97 --- /dev/null +++ b/hwdef-fw3a.h @@ -0,0 +1,105 @@ +// BLF/TLF FW3A driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * ---- + * Reset -|1 8|- VCC + * eswitch -|2 7|- optic nerve + * FET -|3 6|- 7x7135 + * GND -|4 5|- 1x7135 + * ---- + */ + +#define ATTINY 85 +#include + +#define HWDEF_C_FILE hwdef-fw3a.c + +// channel modes +// * 0. FET+7+1 stacked +#define NUM_CHANNEL_MODES 1 +enum CHANNEL_MODES { + CM_MAIN = 0, +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00000001 + + +#define PWM_CHANNELS 3 // old, remove this + +#define PWM_BITS 8 // attiny85 only supports up to 8 bits +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define PWM_DATATYPE2 uint16_t +#define PWM1_DATATYPE uint8_t // 1x7135 ramp +#define PWM2_DATATYPE uint8_t // 7x7135 ramp +#define PWM3_DATATYPE uint8_t // DD FET ramp + +#define PWM_TOP_INIT 255 // highest value used in top half of ramp + +// 1x7135 channel +#define CH1_PIN PB0 // pin 5, 1x7135 PWM +#define CH1_PWM OCR0A // OCR0A is the output compare register for PB0 + +// 7x7135 channel +#define CH2_PIN PB1 // pin 6, 7x7135 PWM +#define CH2_PWM OCR0B // OCR0B is the output compare register for PB1 + +// DD FET channel +#define CH3_PIN PB4 // pin 3, FET PWM +#define CH3_PWM OCR1B // OCR1B is the output compare register for PB4 + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt +#endif + +#ifndef VISION_PIN +#define VISION_PIN PB2 // pin 7, optic nerve +//#define ADC_CHANNEL 0x01 // MUX 01 corresponds with PB2 +//#define ADC_DIDR ADC1D // Digital input disable bit corresponding with PB2 +#endif +#define ADC_PRSCL 0x07 // clk/128 + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V +#endif + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + + +inline void hwdef_setup() { + + // configure PWM channels + DDRB = (1 << CH1_PIN) + | (1 << CH2_PIN) + | (1 << CH3_PIN); + + // configure PWM channels + TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) + TCCR0A = PHASE; + + // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = PWM_TOP_INIT; // Set ceiling value to maximum + + // configure e-switch + PORTB = (1 << SWITCH_PIN); // e-switch is the only input + PCMSK = (1 << SWITCH_PIN); // pin change interrupt uses this pin + + // TODO: set up the vision pin + +} + + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/cfg-fw3a-219.h b/spaghetti-monster/anduril/cfg-fw3a-219.h index 88739bf..0bd5250 100644 --- a/spaghetti-monster/anduril/cfg-fw3a-219.h +++ b/spaghetti-monster/anduril/cfg-fw3a-219.h @@ -13,3 +13,4 @@ #define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,8,10,13,15,17,19,22,24,26,29,31,34,37,39,42,45,48,51,54,57,60,64,67,70,74,77,81,85,88,92,96,100,104,108,112,116,121,125,130,134,139,143,148,153,158,163,168,173,179,184,189,195,201,206,212,218,224,230,236,243,249,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 #define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,13,19,25,30,36,42,48,54,61,67,73,80,86,93,100,107,114,120,128 + diff --git a/spaghetti-monster/anduril/cfg-fw3a-nofet.h b/spaghetti-monster/anduril/cfg-fw3a-nofet.h index e828ac5..b5d4166 100644 --- a/spaghetti-monster/anduril/cfg-fw3a-nofet.h +++ b/spaghetti-monster/anduril/cfg-fw3a-nofet.h @@ -9,8 +9,8 @@ // don't use channel 3 (FET) #undef PWM_CHANNELS -#undef PWM3_PIN -#undef PWM3_LVL +#undef CH3_PIN +#undef CH3_PWM #define PWM_CHANNELS 2 // reconfigure the ramp @@ -22,8 +22,9 @@ #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 #undef MAX_1x7135 #define MAX_1x7135 65 +#undef MAX_Nx7135 #undef HALFSPEED_LEVEL -#define HALFSPEED_LEVEL 14 +#define HALFSPEED_LEVEL 15 #undef QUARTERSPEED_LEVEL #define QUARTERSPEED_LEVEL 6 @@ -45,3 +46,9 @@ #undef SIMPLE_UI_CEIL #define SIMPLE_UI_CEIL 120 +#undef THERM_FASTER_LEVEL +#define THERM_FASTER_LEVEL 130 + +// without the 3rd channel, extra features can fit +#define USE_TACTICAL_MODE + diff --git a/spaghetti-monster/anduril/cfg-fw3a.h b/spaghetti-monster/anduril/cfg-fw3a.h index f75fe13..7a8f417 100644 --- a/spaghetti-monster/anduril/cfg-fw3a.h +++ b/spaghetti-monster/anduril/cfg-fw3a.h @@ -4,31 +4,51 @@ #pragma once #define MODEL_NUMBER "0311" -#include "hwdef-FW3A.h" +#include "hwdef-fw3a.h" + +#define RAMP_SIZE 150 // ../../bin/level_calc.py 1 65 7135 1 0.8 150 // ... mixed with this: // ../../../bin/level_calc.py 3 150 7135 1 0.33 150 7135 1 1 850 FET 1 10 1500 -#define RAMP_LENGTH 150 #define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,8,10,13,15,17,19,22,24,26,29,31,34,37,39,42,45,48,51,54,57,60,64,67,70,74,77,81,85,88,92,96,100,104,108,112,116,121,125,130,134,139,143,148,153,158,163,168,173,179,184,189,195,201,206,212,218,224,230,236,243,249,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,19,31,43,55,67,79,91,104,117,130,143,157,170,184,198,212,226,240,255 + +#define DEFAULT_LEVEL 50 #define MAX_1x7135 65 #define MAX_Nx7135 130 -#define HALFSPEED_LEVEL 14 -#define QUARTERSPEED_LEVEL 5 +#define HALFSPEED_LEVEL 15 +#define QUARTERSPEED_LEVEL 6 + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL MAX_Nx7135 +// 10, 30, 50, [70], 90, 110, 130 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 // safe limit ~20% power // 20 40 60 80 100 -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#define SIMPLE_UI_CEIL 100 -#define SIMPLE_UI_STEPS 5 +#define SIMPLE_UI_FLOOR 20 +#define SIMPLE_UI_CEIL 100 +#define SIMPLE_UI_STEPS 5 // stop panicking at about 3A or ~1100 lm, this light is a hotrod #define THERM_FASTER_LEVEL MAX_Nx7135 +// don't blink during ramp +#define BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_FLOOR + +// enable extra features +#define USE_SMOOTH_STEPS + // can't reset the normal way because power is connected before the button #define USE_SOFT_FACTORY_RESET // too big, turn off extra features #undef USE_TACTICAL_MODE +#undef USE_SOS_MODE + -- cgit v1.2.3 From 8f8a5943b83ecb3324dcbfedcb6d81010ff38c50 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 10 Oct 2023 22:56:07 -0600 Subject: fix failed builds without USE_RAMP_AFTER_MOON_CONFIG --- spaghetti-monster/anduril/load-save-config.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/load-save-config.h b/spaghetti-monster/anduril/load-save-config.h index c70bb2b..6ae2ba2 100644 --- a/spaghetti-monster/anduril/load-save-config.h +++ b/spaghetti-monster/anduril/load-save-config.h @@ -57,7 +57,9 @@ Config cfg = { #endif #endif - .dont_ramp_after_moon = DEFAULT_DONT_RAMP_AFTER_MOON, + #ifdef USE_RAMP_AFTER_MOON_CONFIG + .dont_ramp_after_moon = DEFAULT_DONT_RAMP_AFTER_MOON, + #endif #ifdef USE_MANUAL_MEMORY .manual_memory = DEFAULT_MANUAL_MEMORY, -- cgit v1.2.3 From b5059bfc15cfab0fab0f2ef914128b63323e64c9 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 10 Oct 2023 22:58:04 -0600 Subject: converted mateminco-mf01-mini build to new API --- hwdef-Mateminco_MF01-Mini.h | 50 ----------- hwdef-mateminco-mf01-mini.h | 100 +++++++++++++++++++++ hwdef-mateminco-mf01s.h | 3 +- .../anduril/cfg-mateminco-mf01-mini.h | 38 ++++---- 4 files changed, 122 insertions(+), 69 deletions(-) delete mode 100644 hwdef-Mateminco_MF01-Mini.h create mode 100644 hwdef-mateminco-mf01-mini.h diff --git a/hwdef-Mateminco_MF01-Mini.h b/hwdef-Mateminco_MF01-Mini.h deleted file mode 100644 index 557e641..0000000 --- a/hwdef-Mateminco_MF01-Mini.h +++ /dev/null @@ -1,50 +0,0 @@ -// MF01-Mini driver layout -// Copyright (C) 2019-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * ---- - * Reset -|1 8|- VCC - * eswitch -|2 7|- aux LEDs - * FET PWM -|3 6|- PWM (7x7135) - * GND -|4 5|- PWM (1x7135) - * ---- - */ - -#define PWM_CHANNELS 3 - -#ifndef AUXLED_PIN -#define AUXLED_PIN PB2 // pin 7 -#endif - -#ifndef SWITCH_PIN -#define SWITCH_PIN PB3 // pin 2 -#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt -#endif - -#ifndef PWM1_PIN -#define PWM1_PIN PB0 // pin 5, 1x7135 PWM -#define PWM1_LVL OCR0A // OCR0A is the output compare register for PB0 -#endif -#ifndef PWM2_PIN -#define PWM2_PIN PB1 // pin 6, 7x7135 PWM -#define PWM2_LVL OCR0B // OCR0B is the output compare register for PB1 -#endif -#ifndef PWM3_PIN -#define PWM3_PIN PB4 // pin 3, FET PWM -#define PWM3_LVL OCR1B // OCR1B is the output compare register for PB4 -#endif - -#define ADC_PRSCL 0x07 // clk/128 - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V -#endif - -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels - -#define LAYOUT_DEFINED - diff --git a/hwdef-mateminco-mf01-mini.h b/hwdef-mateminco-mf01-mini.h new file mode 100644 index 0000000..35405db --- /dev/null +++ b/hwdef-mateminco-mf01-mini.h @@ -0,0 +1,100 @@ +// Mateminco MF01-Mini driver layout +// Copyright (C) 2019-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * ---- + * Reset -|1 8|- VCC + * eswitch -|2 7|- aux LEDs + * FET PWM -|3 6|- PWM (7x7135) + * GND -|4 5|- PWM (1x7135) + * ---- + */ + +#define ATTINY 85 +#include + +#define HWDEF_C_FILE hwdef-fw3a.c + +// channel modes +// * 0. FET+N+1 stacked +#define NUM_CHANNEL_MODES 1 +enum CHANNEL_MODES { + CM_MAIN = 0, +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00000001 + + +#define PWM_CHANNELS 3 // old, remove this + +#define PWM_BITS 8 // attiny85 only supports up to 8 bits +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define PWM_DATATYPE2 uint16_t +#define PWM1_DATATYPE uint8_t // 1x7135 ramp +#define PWM2_DATATYPE uint8_t // 7x7135 ramp +#define PWM3_DATATYPE uint8_t // DD FET ramp + +#define PWM_TOP_INIT 255 // highest value used in top half of ramp + +// 1x7135 channel +#define CH1_PIN PB0 // pin 5, 1x7135 PWM +#define CH1_PWM OCR0A // OCR0A is the output compare register for PB0 + +// 7x7135 channel +#define CH2_PIN PB1 // pin 6, 7x7135 PWM +#define CH2_PWM OCR0B // OCR0B is the output compare register for PB1 + +// DD FET channel +#define CH3_PIN PB4 // pin 3, FET PWM +#define CH3_PWM OCR1B // OCR1B is the output compare register for PB4 + +// lighted button and 1-channel front aux +#define AUXLED_PIN PB2 // pin 7 + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt +#endif + +#define ADC_PRSCL 0x07 // clk/128 + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V +#endif + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + + +inline void hwdef_setup() { + + // configure PWM channels + DDRB = (1 << CH1_PIN) + | (1 << CH2_PIN) + | (1 << CH3_PIN); + + // configure PWM channels + TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) + TCCR0A = PHASE; + + // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = PWM_TOP_INIT; // Set ceiling value to maximum + + // configure e-switch + PORTB = (1 << SWITCH_PIN); // e-switch is the only input + PCMSK = (1 << SWITCH_PIN); // pin change interrupt uses this pin +} + + +#define LAYOUT_DEFINED + diff --git a/hwdef-mateminco-mf01s.h b/hwdef-mateminco-mf01s.h index 14cf76b..af214b2 100644 --- a/hwdef-mateminco-mf01s.h +++ b/hwdef-mateminco-mf01s.h @@ -18,7 +18,7 @@ #define HWDEF_C_FILE hwdef-emisar-d4.c // channel modes -// * 0. FET+7135 stacked +// * 0. small FET + big FET stacked #define NUM_CHANNEL_MODES 1 enum CHANNEL_MODES { CM_MAIN = 0, @@ -49,6 +49,7 @@ enum CHANNEL_MODES { #define CH2_PIN PB1 // pin 6, FET PWM #define CH2_PWM OCR0B // OCR0B is the output compare register for PB1 +// lighted button and 1-channel front aux #define AUXLED_PIN PB4 // pin 3 // e-switch diff --git a/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h b/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h index 47ff84b..fb62ac6 100644 --- a/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h +++ b/spaghetti-monster/anduril/cfg-mateminco-mf01-mini.h @@ -4,7 +4,7 @@ #pragma once #define MODEL_NUMBER "0521" -#include "hwdef-Mateminco_MF01-Mini.h" +#include "hwdef-mateminco-mf01-mini.h" // the button lights up #define USE_INDICATOR_LED @@ -16,10 +16,7 @@ #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) -// don't blink during ramp, it's irrelevant and annoying on this light -#define BLINK_AT_RAMP_CEIL -#undef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_FLOOR +#define RAMP_SIZE 150 // measured brightness with Sofirn 5500mAh cell at 3.97V: // moon: 0.3 lm @@ -28,13 +25,13 @@ // channel 3: 3500 lm // ../../../bin/level_calc.py ninth 3 150 7135 1 2.5 115.65 7135 11 5 708.65 FET 1 10 3500 // (plus some manual tweaks for a smoother ramp) -#define RAMP_LENGTH 150 #define PWM1_LEVELS 1,1,2,2,3,3,4,5,5,6,7,8,9,9,10,14,15,16,17,18,19,20,21,22,24,26,28,30,32,34,37,39,42,45,48,51,54,58,62,65,69,74,78,83,88,93,98,104,110,116,123,130,137,145,153,161,170,179,188,198,208,219,231,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,13,16,18,20,23,25,28,31,34,37,40,43,47,50,54,58,62,66,70,75,80,85,90,95,100,106,112,118,125,131,138,145,153,161,169,177,185,194,204,213,223,233,244,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,6,10,13,17,21,24,28,33,37,41,46,50,55,60,66,71,76,82,88,94,101,107,114,121,128,135,143,151,159,167,176,185,194,203,213,223,233,244,255 -#define MAX_1x7135 65 // ~113 lm -#define MAX_Nx7135 110 -#define HALFSPEED_LEVEL 16 + +#define MAX_1x7135 65 // ~113 lm +#define MAX_Nx7135 110 +#define HALFSPEED_LEVEL 16 #define QUARTERSPEED_LEVEL 8 #define RAMP_SMOOTH_FLOOR 1 // ~0.3 lm @@ -55,18 +52,23 @@ #define THERM_FASTER_LEVEL 130 // throttle back faster when high +// don't blink during ramp +//#define BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_FLOOR + +// enable extra features +#define USE_SMOOTH_STEPS -// too big, remove stuff to make room +// too big, turn off extra features +#define USE_SOFT_FACTORY_RESET +//#undef USE_SIMPLE_UI +#undef USE_TACTICAL_MODE #undef USE_SOS_MODE +#undef USE_BEACON_MODE #undef USE_RAMP_AFTER_MOON_CONFIG -#undef USE_RAMP_SPEED_CONFIG +//#undef USE_RAMP_SPEED_CONFIG #undef USE_VOLTAGE_CORRECTION //#undef USE_2C_STYLE_CONFIG -// reduce size a bit -#ifdef USE_LOWPASS_WHILE_ASLEEP -#undef USE_LOWPASS_WHILE_ASLEEP -#endif - -// too big, turn off extra features -#undef USE_TACTICAL_MODE -- cgit v1.2.3 From 06e238bd72c2ecafa5d5a1ac8cc643bd2438ff6b Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 10 Oct 2023 23:58:38 -0600 Subject: emisar-d4: added smooth steps and tactical mode, reduced ramp bump, removed SOS mode to make room for other stuff --- spaghetti-monster/anduril/cfg-emisar-d4.h | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-emisar-d4.h b/spaghetti-monster/anduril/cfg-emisar-d4.h index 4ae5694..4b3ae5a 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d4.h +++ b/spaghetti-monster/anduril/cfg-emisar-d4.h @@ -18,7 +18,7 @@ #define MAX_1x7135 65 #define DEFAULT_LEVEL 65 -#define HALFSPEED_LEVEL 14 +#define HALFSPEED_LEVEL 15 #define QUARTERSPEED_LEVEL 6 #define RAMP_SMOOTH_FLOOR 1 @@ -29,12 +29,20 @@ #define RAMP_DISCRETE_STEPS 7 // safe limit ~20% power -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#define SIMPLE_UI_CEIL 95 -#define SIMPLE_UI_STEPS 5 +#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR +#define SIMPLE_UI_CEIL 100 +#define SIMPLE_UI_STEPS 5 // stop panicking at ~30% power or ~1200 lm #define THERM_FASTER_LEVEL 105 +// don't blink during ramp +#undef BLINK_AT_RAMP_MIDDLE + +// enable extra features +#define USE_SMOOTH_STEPS + // too big, turn off extra features -#undef USE_TACTICAL_MODE +//#undef USE_TACTICAL_MODE +#undef USE_SOS_MODE + -- cgit v1.2.3 From ad4fb567fbc0a86fcc24ceba951e467ab8b91211 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 12 Oct 2023 15:11:26 -0600 Subject: fixed RGB aux colors being off by one (bug introduced in r772, when adding AA/NiMH RGB voltage support) --- spaghetti-monster/anduril/aux-leds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/aux-leds.c b/spaghetti-monster/anduril/aux-leds.c index 097cf28..af59aa6 100644 --- a/spaghetti-monster/anduril/aux-leds.c +++ b/spaghetti-monster/anduril/aux-leds.c @@ -131,7 +131,7 @@ void rgb_led_update(uint8_t mode, uint16_t arg) { } #endif - const uint8_t *colors = rgb_led_colors; + const uint8_t *colors = rgb_led_colors + 1; uint8_t actual_color = 0; if (color < 7) { // normal color actual_color = pgm_read_byte(colors + color); -- cgit v1.2.3 From cfdbff9ff8ee8f5a36303c8710957fb88ef8b1c7 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 12 Oct 2023 17:54:35 -0600 Subject: misc comments, spacing, documentation --- hwdef-thefreeman-boost-fwaa-mp3432-hdr-dac-rgb.h | 6 +++--- hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c | 2 +- hwdef-wurkkos-ts25.c | 1 - spaghetti-monster/anduril/MODELS | 2 ++ spaghetti-monster/anduril/anduril-manual.txt | 1 + spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/hwdef-thefreeman-boost-fwaa-mp3432-hdr-dac-rgb.h b/hwdef-thefreeman-boost-fwaa-mp3432-hdr-dac-rgb.h index efa3ca7..9126a1a 100755 --- a/hwdef-thefreeman-boost-fwaa-mp3432-hdr-dac-rgb.h +++ b/hwdef-thefreeman-boost-fwaa-mp3432-hdr-dac-rgb.h @@ -106,7 +106,7 @@ enum CHANNEL_MODES { // Voltage divider battLVL #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is regulated -#define DUAL_VOLTAGE_FLOOR 21 // for AA/14500 boost drivers, don't indicate low voltage if below this level +#define DUAL_VOLTAGE_FLOOR 21 // for AA/14500 boost drivers, don't indicate low voltage if below this level #define DUAL_VOLTAGE_LOW_LOW 7 // the lower voltage range's danger zone 0.7 volts (NiMH) #define ADMUX_VOLTAGE_DIVIDER ADC_MUXPOS_AIN2_gc // which ADC channel to read @@ -157,14 +157,14 @@ inline void hwdef_setup() { //PORTA.PIN5CTRL = PORT_PULLUPEN_bm; // HDR //PORTA.PIN6CTRL = PORT_PULLUPEN_bm; // DAC PORTA.PIN7CTRL = PORT_PULLUPEN_bm; - + PORTB.PIN0CTRL = PORT_PULLUPEN_bm; PORTB.PIN1CTRL = PORT_PULLUPEN_bm; //PORTB.PIN2CTRL = PORT_PULLUPEN_bm; // IN- NFET //PORTB.PIN3CTRL = PORT_PULLUPEN_bm; // R //PORTB.PIN4CTRL = PORT_PULLUPEN_bm; // G //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // B - + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; PORTC.PIN1CTRL = PORT_PULLUPEN_bm; PORTC.PIN2CTRL = PORT_PULLUPEN_bm; diff --git a/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c b/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c index 555167e..31feec9 100644 --- a/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c +++ b/hwdef-thefreeman-boost21-mp3431-hdr-dac-argb.c @@ -12,7 +12,7 @@ bool gradual_tick_main(uint8_t gt); Channel channels[] = { - { // channel 1 only + { // main LEDs .set_level = set_level_main, .gradual_tick = gradual_tick_main }, diff --git a/hwdef-wurkkos-ts25.c b/hwdef-wurkkos-ts25.c index 3c98716..26c9b0d 100644 --- a/hwdef-wurkkos-ts25.c +++ b/hwdef-wurkkos-ts25.c @@ -25,7 +25,6 @@ void set_level_zero() { CH1_PWM = 0; CH2_PWM = 0; PWM_CNT = 0; // reset phase - return; } // single set of LEDs with 2 stacked power channels, DDFET+1 or DDFET+linear diff --git a/spaghetti-monster/anduril/MODELS b/spaghetti-monster/anduril/MODELS index 97af879..23c5842 100644 --- a/spaghetti-monster/anduril/MODELS +++ b/spaghetti-monster/anduril/MODELS @@ -74,6 +74,8 @@ Model Name MCU 0716 wurkkos-fc13 attiny1616 0717 wurkkos-ts11 attiny1616 1618 gchart-fet1-t1616 attiny1616 +1631 thefreeman-boost21-6a attiny1616 +1632 thefreeman-boost-fwaa attiny1616 Duplicates: diff --git a/spaghetti-monster/anduril/anduril-manual.txt b/spaghetti-monster/anduril/anduril-manual.txt index d47cc57..545af0f 100644 --- a/spaghetti-monster/anduril/anduril-manual.txt +++ b/spaghetti-monster/anduril/anduril-manual.txt @@ -934,6 +934,7 @@ Lockout Full 10H Auto-lock config menu: Strobe (any) Full 1C Off Strobe (any) Full 2C Next strobe mode +Strobe (any) Full 3C Next channel mode (saved per strobe mode) Strobe (any) Full 4C Prev strobe mode Strobe (any) Full 5C Momentary mode (using current strobe) diff --git a/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h b/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h index d9ac882..0e2f28d 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-sp10-pro.h @@ -1,5 +1,5 @@ // Sofirn SP10 Pro config options for Anduril -// Copyright (C) 2022-2023 (FIXME) +// Copyright (C) 2022-2023 (original author TBD), Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -- cgit v1.2.3 From 1fdec464891262b06d19f53d1f152a560effa576 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 13 Oct 2023 14:29:57 -0600 Subject: rewrote emisar-d4k-3ch to use delta-sigma modulation (PWM + DSM), which gives much better resolution, especially for the 8-bit channel. Also... - set_channel_mode() aborts when going from/to the same channel, to avoid unnecessary flicker - hsv2rgb() uses 16-bit R/G/B and V now - changed default channel to All - reduced default channel modes to just A, B, C, and All - smooth ramp floor defaults to 1/150 - raised level when aux LEDs turn on high during use (for better compatibility with red main LEDs) --- hwdef-emisar-d4k-3ch.c | 279 ++++++++++++------------- hwdef-emisar-d4k-3ch.h | 26 ++- spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h | 39 ++-- spaghetti-monster/fsm-channels.c | 11 +- spaghetti-monster/fsm-channels.h | 8 +- 5 files changed, 179 insertions(+), 184 deletions(-) diff --git a/hwdef-emisar-d4k-3ch.c b/hwdef-emisar-d4k-3ch.c index 8c46003..3fed41a 100644 --- a/hwdef-emisar-d4k-3ch.c +++ b/hwdef-emisar-d4k-3ch.c @@ -81,133 +81,138 @@ void set_level_zero() { MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); + main2_dsm_lvl = 0; + led3_dsm_lvl = 0; + led4_dsm_lvl = 0; MAIN2_PWM_LVL = 0; LED3_PWM_LVL = 0; LED4_PWM_LVL = 0; PWM_CNT = 0; - PWM_TOP = PWM_TOP_INIT; + //PWM_TOP = PWM_TOP_INIT; +} + +// wrap setting the dsm vars, to get a faster response +// (just setting *_dsm_lvl doesn't work well for strobes) +void set_hw_levels(PWM_DATATYPE main2, // brightness, 0 to DSM_TOP + PWM_DATATYPE led3, + PWM_DATATYPE led4, + bool main2_en, // enable even at PWM=0? + bool led3_en, + bool led4_en + ) { + + // enable/disable LED power channels + if (main2 | main2_en) + MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); + else MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); + + if (led3 | led3_en ) + LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN); + else LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN); + + if (led4 | led4_en ) + LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN); + else LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN); + + // set delta-sigma soft levels + main2_dsm_lvl = main2; + led3_dsm_lvl = led3; + led4_dsm_lvl = led4; + // set hardware PWM levels and init dsm loop + MAIN2_PWM_LVL = main2_pwm = main2 >> 7; + LED3_PWM_LVL = led3_pwm = led3 >> 7; + LED4_PWM_LVL = led4_pwm = led4 >> 7; + // force phase reset + PWM_CNT = PWM_CNT2 = 0; +} + +// delta-sigma modulation of PWM outputs +// happens on each Timer0 overflow (every 512 cpu clock cycles) +// uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD) +ISR(TIMER0_OVF_vect) { + // set new hardware values first, + // for best timing (reduce effect of interrupt jitter) + MAIN2_PWM_LVL = main2_pwm; + LED3_PWM_LVL = led3_pwm; + LED4_PWM_LVL = led4_pwm; + + // calculate next values, now that timing matters less + + // accumulate error + main2_dsm += (main2_dsm_lvl & 0x007f); + // next PWM = base PWM value + carry bit + main2_pwm = (main2_dsm_lvl >> 7) + (main2_dsm > 0x7f); + // clear carry bit + main2_dsm &= 0x7f; + + // repeat for other channels + + led3_dsm += (led3_dsm_lvl & 0x007f); + led3_pwm = (led3_dsm_lvl >> 7) + (led3_dsm > 0x7f); + led3_dsm &= 0x7f; + + led4_dsm += (led4_dsm_lvl & 0x007f); + led4_pwm = (led4_dsm_lvl >> 7) + (led4_dsm > 0x7f); + led4_dsm &= 0x7f; } // LEDs 1+2 are 8-bit // this 8-bit channel may be LEDs 1+2 or LED 4, depending on wiring void set_level_main2(uint8_t level) { - LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off unused LEDs - LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs - - MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); - MAIN2_PWM_LVL = PWM_GET8(pwm1_levels, level); + set_hw_levels(PWM_GET(pwm1_levels, level), 0, 0, + 1, 0, 0); } // LED 3 is 16-bit void set_level_led3(uint8_t level) { - MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs - LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs - - LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN); - LED3_PWM_LVL = PWM_GET16(pwm2_levels, level); - uint16_t top = PWM_GET16(pwm_tops, level); - while(actual_level && (PWM_CNT > (top - 32))) {} - PWM_TOP = top; - if (! actual_level) PWM_CNT = 0; + set_hw_levels(0, PWM_GET(pwm1_levels, level), 0, + 0, 1, 0); } // this 16-bit channel may be LED 4 or LEDs 1+2, depending on wiring void set_level_led4(uint8_t level) { - MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs - LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); // turn off unused LEDs - - // gotta turn on the opamp before light can come out - LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN); - LED4_PWM_LVL = PWM_GET16(pwm2_levels, level); - // pulse frequency modulation, a.k.a. dynamic PWM - uint16_t top = PWM_GET16(pwm_tops, level); - // wait to sync the counter and avoid flashes - while(actual_level && (PWM_CNT > (top - 32))) {} - PWM_TOP = top; - // force reset phase when turning on from zero - // (because otherwise the initial response is inconsistent) - if (! actual_level) PWM_CNT = 0; + set_hw_levels(0, 0, PWM_GET(pwm1_levels, level), + 0, 0, 1); } void set_level_all(uint8_t level) { - MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); - LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN ); - LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN ); - // FIXME? It might be better to calculate the 8-bit value from the - // 16-bit tables instead of using the 8-bit ramp - // 8bit = max(1, 16bit * 255 / top) - MAIN2_PWM_LVL = PWM_GET8 (pwm1_levels, level); - LED3_PWM_LVL = PWM_GET16(pwm2_levels, level); - LED4_PWM_LVL = PWM_GET16(pwm2_levels, level); - uint16_t top = PWM_GET16(pwm_tops, level); - while(actual_level && (PWM_CNT > (top - 32))) {} - PWM_TOP = top; - if (! actual_level) PWM_CNT = 0; + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, level); + set_hw_levels(pwm, pwm, pwm, 1, 1, 1); } // 8/16/16 wiring, mix 16+16 void set_level_led34a_blend(uint8_t level) { - MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); // turn off unused LEDs - PWM_DATATYPE warm_PWM, cool_PWM; - PWM_DATATYPE brightness = PWM_GET16(pwm2_levels, level); - PWM_DATATYPE top = PWM_GET16(pwm_tops, level); + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); uint8_t blend = cfg.channel_mode_args[channel_mode]; - calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, DSM_TOP, blend); - if (warm_PWM > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN); - if (cool_PWM > 0) LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN); - LED3_PWM_LVL = warm_PWM; - LED4_PWM_LVL = cool_PWM; - while(actual_level && (PWM_CNT > (top - 32))) {} - PWM_TOP = top; - if (! actual_level) PWM_CNT = 0; + set_hw_levels(0, warm_PWM, cool_PWM, + 0, (blend<170), (blend>85)); } // 16/16/8 wiring, mix 16+8 void set_level_led34b_blend(uint8_t level) { - LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); // turn off unused LEDs - - const uint16_t top = 2047; - uint16_t warm_PWM, cool_PWM; // 11 bits, 8 bits + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); uint8_t blend = cfg.channel_mode_args[channel_mode]; - uint16_t brightness = PWM_GET8(pwm1_levels, level); - - if (0 == brightness) brightness = 1; - brightness = brightness << 3; - - calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); - // adjust to halfway between 8-bit steps - warm_PWM -= 4; - if (warm_PWM > top) warm_PWM = 0; + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, DSM_TOP, blend); - if (cool_PWM > 0) MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); - if (warm_PWM > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN); - MAIN2_PWM_LVL = (uint8_t)(cool_PWM >> 3); - LED3_PWM_LVL = warm_PWM; - //while(actual_level && (PWM_CNT > (top - 32))) {} - PWM_TOP = top; - if (! actual_level) PWM_CNT = 0; + set_hw_levels(cool_PWM, warm_PWM, 0, + (blend>85), (blend<170), 0); } void set_level_hsv(uint8_t level) { RGB_t color; uint8_t h = cfg.channel_mode_args[channel_mode]; uint8_t s = 255; // TODO: drop saturation at brightest levels - uint8_t v = PWM_GET8(pwm1_levels, level); + PWM_DATATYPE v = PWM_GET(pwm1_levels, level); color = hsv2rgb(h, s, v); - if (color.r > 0) MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); - if (color.g > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN ); - if (color.b > 0) LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN ); - MAIN2_PWM_LVL = color.r; - LED3_PWM_LVL = color.g; - LED4_PWM_LVL = color.b; - //while(actual_level && (PWM_CNT > (255 - 32))) {} - PWM_TOP = 255; - if (! actual_level) PWM_CNT = 0; + set_hw_levels(color.r, color.g, color.b, + 0, 0, 0); } // calculate a 3-channel "auto tint" blend @@ -216,15 +221,12 @@ void set_level_hsv(uint8_t level) { // level : ramp level to convert into 3 channel levels // (assumes ramp table is "pwm1_levels") void calc_auto_3ch_blend( - uint16_t *a, // red - uint16_t *b, // warm - uint8_t *c, // cool + PWM_DATATYPE *a, // red + PWM_DATATYPE *b, // warm + PWM_DATATYPE *c, // cool uint8_t level) { - // led4=red, led3=warm - uint16_t vpwm = PWM_GET16(pwm2_levels, level); - // main2=white, 8-bit - uint8_t vpwm8 = PWM_GET8 (pwm1_levels, level); + PWM_DATATYPE vpwm = PWM_GET(pwm1_levels, level); // tint goes from 0 (red) to 127 (warm white) to 255 (cool white) uint8_t mytint; @@ -244,106 +246,88 @@ void calc_auto_3ch_blend( *b = (((PWM_DATATYPE2)triangle_wave(mytint) * (PWM_DATATYPE2)vpwm) ) / 255; // cool white is low at 0, high at 255 (linear) - *c = (uint8_t)( - (((PWM_DATATYPE2)rising - * (PWM_DATATYPE2)vpwm8) + 127) / 255 - ); + *c = (((PWM_DATATYPE2)rising + * (PWM_DATATYPE2)vpwm) + 127) / 255; } // 3-channel "auto tint" channel mode void set_level_auto3(uint8_t level) { - uint16_t a, b; - uint8_t c; + PWM_DATATYPE a, b, c; calc_auto_3ch_blend(&a, &b, &c, level); - // pulse frequency modulation, a.k.a. dynamic PWM - uint16_t top = PWM_GET(pwm_tops, level); + set_hw_levels(c, b, a, + 0, 0, (0 == level)); +} - if ((a > 0) || (0 == level)) // don't turn off at bottom level - LED4_ENABLE_PORT |= (1 << LED4_ENABLE_PIN ); - else LED4_ENABLE_PORT &= ~(1 << LED4_ENABLE_PIN ); - if (b > 0) LED3_ENABLE_PORT |= (1 << LED3_ENABLE_PIN ); - else LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); - if (c > 0) MAIN2_ENABLE_PORT |= (1 << MAIN2_ENABLE_PIN); - else MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); +///// "gradual tick" functions for smooth thermal regulation ///// - LED4_PWM_LVL = a; // red - LED3_PWM_LVL = b; // warm - MAIN2_PWM_LVL = c; // cool +bool gradual_adjust(PWM_DATATYPE main2, PWM_DATATYPE led3, PWM_DATATYPE led4) { + // adjust multiple times based on current brightness + // (so it adjusts faster/coarser when bright, slower/finer when dim) - while(actual_level && (PWM_CNT > (255 - 32))) {} - PWM_TOP = top; - if (! actual_level) PWM_CNT = 0; -} + // higher shift = slower/finer adjustments + const uint8_t shift = 9; // ((255 << 7) >> 9) = 63 max + uint8_t steps; -///// "gradual tick" functions for smooth thermal regulation ///// + steps = main2_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(main2, main2_dsm_lvl); -bool gradual_adjust(uint8_t main2, uint16_t led3, uint16_t led4) { - GRADUAL_ADJUST_SIMPLE(main2, MAIN2_PWM_LVL); - GRADUAL_ADJUST_SIMPLE(led3, LED3_PWM_LVL ); - GRADUAL_ADJUST_SIMPLE(led4, LED4_PWM_LVL ); + steps = led3_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(led3, led3_dsm_lvl ); - if ((main2 == MAIN2_PWM_LVL) - && (led3 == LED3_PWM_LVL ) - && (led4 == LED4_PWM_LVL )) { + steps = led4_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(led4, led4_dsm_lvl ); + + if ((main2 == main2_dsm_lvl) + && (led3 == led3_dsm_lvl ) + && (led4 == led4_dsm_lvl )) { return true; // done } return false; // not done yet } bool gradual_tick_main2(uint8_t gt) { - uint8_t main2 = PWM_GET8(pwm1_levels, gt); + PWM_DATATYPE main2 = PWM_GET(pwm1_levels, gt); return gradual_adjust(main2, 0, 0); } bool gradual_tick_led3(uint8_t gt) { - uint16_t led3 = PWM_GET16(pwm2_levels, gt); + PWM_DATATYPE led3 = PWM_GET(pwm1_levels, gt); return gradual_adjust(0, led3, 0); } bool gradual_tick_led4(uint8_t gt) { - uint16_t led4 = PWM_GET16(pwm2_levels, gt); + PWM_DATATYPE led4 = PWM_GET(pwm1_levels, gt); return gradual_adjust(0, 0, led4); } bool gradual_tick_all(uint8_t gt) { - uint8_t main2 = PWM_GET8 (pwm1_levels, gt); - uint16_t led3 = PWM_GET16(pwm2_levels, gt); - uint16_t led4 = PWM_GET16(pwm2_levels, gt); - return gradual_adjust(main2, led3, led4); + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(pwm, pwm, pwm); } // 8/16/16 wiring, mix 16+16 bool gradual_tick_led34a_blend(uint8_t gt) { PWM_DATATYPE warm_PWM, cool_PWM; - PWM_DATATYPE brightness = PWM_GET16(pwm2_levels, gt); - PWM_DATATYPE top = PWM_GET16(pwm_tops, gt); + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); uint8_t blend = cfg.channel_mode_args[channel_mode]; - calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, DSM_TOP, blend); return gradual_adjust(0, warm_PWM, cool_PWM); } // 16/16/8 wiring, mix 16+8 bool gradual_tick_led34b_blend(uint8_t gt) { - const uint16_t top = 2047; - uint16_t warm_PWM, cool_PWM; // 11 bits, 8 bits + PWM_DATATYPE warm_PWM, cool_PWM; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); uint8_t blend = cfg.channel_mode_args[channel_mode]; - uint16_t brightness = PWM_GET8(pwm1_levels, gt); - - if (0 == brightness) brightness = 1; - brightness = brightness << 3; - - calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, top, blend); - - // adjust to halfway between 8-bit steps - warm_PWM -= 4; - if (warm_PWM > top) warm_PWM = 0; - // convert to 8-bit - cool_PWM = (uint8_t)(cool_PWM >> 3); + calc_2ch_blend(&warm_PWM, &cool_PWM, brightness, DSM_TOP, blend); return gradual_adjust(cool_PWM, warm_PWM, 0); } @@ -353,7 +337,7 @@ bool gradual_tick_hsv(uint8_t gt) { RGB_t color; uint8_t h = cfg.channel_mode_args[channel_mode]; uint8_t s = 255; // TODO: drop saturation at brightest levels - uint8_t v = PWM_GET8(pwm1_levels, gt); + PWM_DATATYPE v = PWM_GET(pwm1_levels, gt); color = hsv2rgb(h, s, v); return gradual_adjust(color.r, color.g, color.b); @@ -361,8 +345,7 @@ bool gradual_tick_hsv(uint8_t gt) { bool gradual_tick_auto3(uint8_t gt) { // figure out what exact PWM levels we're aiming for - uint16_t red, warm; - uint8_t cool; + PWM_DATATYPE red, warm, cool; calc_auto_3ch_blend(&red, &warm, &cool, gt); return gradual_adjust(cool, warm, red); } diff --git a/hwdef-emisar-d4k-3ch.h b/hwdef-emisar-d4k-3ch.h index 538e3f6..59e6f01 100644 --- a/hwdef-emisar-d4k-3ch.h +++ b/hwdef-emisar-d4k-3ch.h @@ -68,7 +68,7 @@ enum channel_modes_e { RGB_AUX_ENUMS }; -#define CHANNEL_MODES_ENABLED 0b0000000000011111 +#define CHANNEL_MODES_ENABLED 0b0000000000001111 #define USE_CHANNEL_MODE_ARGS // _, _, _, _, 128=middle CCT, 128=middle CCT, 213=purple, _ #define CHANNEL_MODE_ARGS 0,0,0,0,128,128,213,0,RGB_AUX_CM_ARGS @@ -86,28 +86,35 @@ enum channel_modes_e { #define PWM_GET PWM_GET16 #define PWM_DATATYPE uint16_t #define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 -#define PWM1_DATATYPE uint8_t // 8-bit PWM on main2 -#define PWM2_DATATYPE uint16_t // dynamic PWM on led3 + led4 +#define PWM1_DATATYPE uint16_t // 15-bit PWM+DSM ramp // dynamic PWM #define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM -#define PWM_TOP_INIT 511 // highest value used in top half of ramp -#define PWM_CNT TCNT1 // for dynamic PWM, reset phase +#define PWM_TOP_INIT 255 // highest value used in top half of ramp +#define PWM_CNT TCNT1 // for checking / resetting phase +#define PWM_CNT2 TCNT0 // for checking / resetting phase +// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) +#define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry // main 2 LEDs / 1st channel (2 LEDs) +uint16_t main2_dsm_lvl; +uint8_t main2_pwm, main2_dsm; #define MAIN2_PWM_PIN PC0 #define MAIN2_PWM_LVL OCR0A // OCR0A is the output compare register for PC0 #define MAIN2_ENABLE_PIN PB0 // Opamp power #define MAIN2_ENABLE_PORT PORTB // control port for PB0 // LED 3 / 2nd channel (1 LED) +uint16_t led3_dsm_lvl; +uint8_t led3_pwm, led3_dsm; #define LED3_PWM_PIN PB3 #define LED3_PWM_LVL OCR1A // OCR1A is the output compare register for PB3 #define LED3_ENABLE_PIN PA1 // Opamp power #define LED3_ENABLE_PORT PORTA // control port for PA1 // LED 4 / 3rd channel (1 LED) -// 8-bit PWM only on OCR0A :( +uint16_t led4_dsm_lvl; +uint8_t led4_pwm, led4_dsm; #define LED4_PWM_PIN PA6 #define LED4_PWM_LVL OCR1B // OCR1B is the output compare register for PA6 #define LED4_ENABLE_PIN PA0 // Opamp power @@ -206,6 +213,8 @@ inline void hwdef_setup() { //| (1< 1 void set_channel_mode(uint8_t mode) { + if (mode == channel_mode) return; // abort if nothing to do + uint8_t cur_level = actual_level; + // turn off old LEDs before changing channel set_level(0); @@ -85,7 +88,7 @@ void calc_2ch_blend( #ifdef USE_HSV2RGB -RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v) { +RGB_t hsv2rgb(uint8_t h, uint8_t s, uint16_t v) { RGB_t color; if (s == 0) { // grey @@ -105,11 +108,11 @@ RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v) { // calculate graph segments, doing integer multiplication // TODO: calculate 16-bit results, not 8-bit high = v; - low = (v * (255 - s)) >> 8; + low = ((uint32_t)v * (255 - s)) >> 8; // TODO: use a cosine crossfade instead of linear // (because it looks better and feels more natural) - falling = (v * (255 - ((s * fpart) >> 8))) >> 8; - rising = (v * (255 - ((s * (255 - fpart)) >> 8))) >> 8; + falling = ((uint32_t)v * (255 - ((s * fpart) >> 8))) >> 8; + rising = ((uint32_t)v * (255 - ((s * (255 - fpart)) >> 8))) >> 8; // default floor color.r = low; diff --git a/spaghetti-monster/fsm-channels.h b/spaghetti-monster/fsm-channels.h index 113a85c..218f4f5 100644 --- a/spaghetti-monster/fsm-channels.h +++ b/spaghetti-monster/fsm-channels.h @@ -96,11 +96,11 @@ void calc_2ch_blend( #ifdef USE_HSV2RGB typedef struct RGB_t { - uint8_t r; - uint8_t g; - uint8_t b; + uint16_t r; + uint16_t g; + uint16_t b; } RGB_t; -RGB_t hsv2rgb(uint8_t h, uint8_t s, uint8_t v); +RGB_t hsv2rgb(uint8_t h, uint8_t s, uint16_t v); #endif // ifdef USE_HSV2RGB -- cgit v1.2.3 From f3302fae9366d36ad01bea57be87c55438900f24 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 23 Oct 2023 05:24:28 -0600 Subject: fixed bug: smooth ramp from turbo down to ceiling caused flickering when smooth_steps was enabled --- spaghetti-monster/anduril/ramp-mode.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/spaghetti-monster/anduril/ramp-mode.c b/spaghetti-monster/anduril/ramp-mode.c index 019fa2a..4611b4f 100644 --- a/spaghetti-monster/anduril/ramp-mode.c +++ b/spaghetti-monster/anduril/ramp-mode.c @@ -153,15 +153,21 @@ uint8_t steady_state(Event event, uint16_t arg) { // hold: change brightness (brighter, dimmer) // click, hold: change brightness (dimmer) else if ((event == EV_click1_hold) || (event == EV_click2_hold)) { - // ramp slower in discrete mode - if (cfg.ramp_style && (arg % HOLD_TIMEOUT != 0)) { + // ramp infrequently in stepped mode + if (cfg.ramp_style && (arg % HOLD_TIMEOUT != 0)) return EVENT_HANDLED; - } #ifdef USE_RAMP_SPEED_CONFIG - // ramp slower if user configured things that way - if ((! cfg.ramp_style) && (arg % ramp_speed)) { - return EVENT_HANDLED; - } + // ramp slower if user configured things that way + if ((! cfg.ramp_style) && (arg % ramp_speed)) + return EVENT_HANDLED; + #endif + #ifdef USE_SMOOTH_STEPS + // if a brightness transition is already happening, + // don't interrupt it + // (like 2C for full turbo then 1H to smooth ramp down + // ... without this clause, it flickers because it trips + // the "blink at ramp ceil" clause below, over and over) + if (smooth_steps_in_progress) return EVENT_HANDLED; #endif // fix ramp direction on first frame if necessary if (!arg) { @@ -200,6 +206,11 @@ uint8_t steady_state(Event event, uint16_t arg) { + (step_size * ramp_direction)); #if defined(BLINK_AT_RAMP_CEIL) || defined(BLINK_AT_RAMP_MIDDLE) // only blink once for each threshold + // FIXME: blinks at beginning of smooth_steps animation instead + // of the end, so it should blink when actual_level reaches a + // threshold, instead of when memorized_level does + // (one possible fix is to just remove mid-ramp blinks entirely, + // and just blink only when it hits the top while going up) if ((memorized_level != actual_level) && ( 0 // for easier syntax below #ifdef BLINK_AT_RAMP_MIDDLE_1 @@ -209,6 +220,7 @@ uint8_t steady_state(Event event, uint16_t arg) { || (memorized_level == BLINK_AT_RAMP_MIDDLE_2) #endif #ifdef BLINK_AT_RAMP_CEIL + // FIXME: only blink at top when going up, not down || (memorized_level == mode_max) #endif #ifdef BLINK_AT_RAMP_FLOOR -- cgit v1.2.3 From ec547ce3180679ed4847a7c3368e3ac7f4d56755 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 25 Oct 2023 06:44:53 -0600 Subject: fixed emisar-d1 + emisar-d1s --- hwdef-Emisar_D1.h | 8 -------- hwdef-Emisar_D1S.h | 8 -------- spaghetti-monster/anduril/cfg-emisar-d1.h | 2 +- spaghetti-monster/anduril/cfg-emisar-d1s.h | 4 ++-- 4 files changed, 3 insertions(+), 19 deletions(-) delete mode 100644 hwdef-Emisar_D1.h delete mode 100644 hwdef-Emisar_D1S.h diff --git a/hwdef-Emisar_D1.h b/hwdef-Emisar_D1.h deleted file mode 100644 index bf3a224..0000000 --- a/hwdef-Emisar_D1.h +++ /dev/null @@ -1,8 +0,0 @@ -// Emisar D1 driver layout -// Copyright (C) 2018-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -// D1 driver is exactly the same as a D4 -#include "hwdef-Emisar_D4.h" - diff --git a/hwdef-Emisar_D1S.h b/hwdef-Emisar_D1S.h deleted file mode 100644 index 15cbedb..0000000 --- a/hwdef-Emisar_D1S.h +++ /dev/null @@ -1,8 +0,0 @@ -// Emisar D1S driver layout -// Copyright (C) 2018-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -// D1S driver is exactly the same as a D4 -#include "hwdef-Emisar_D4.h" - diff --git a/spaghetti-monster/anduril/cfg-emisar-d1.h b/spaghetti-monster/anduril/cfg-emisar-d1.h index 3bcf6a5..c81171c 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1.h @@ -3,8 +3,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -#include "hwdef-Emisar_D1.h" // same as Emisar D4, mostly +#include "hwdef-emisar-d4.h" #include "cfg-emisar-d4.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0121" diff --git a/spaghetti-monster/anduril/cfg-emisar-d1s.h b/spaghetti-monster/anduril/cfg-emisar-d1s.h index 43d8160..8b70a5d 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1s.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1s.h @@ -3,8 +3,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -#include "hwdef-Emisar_D1S.h" // same as Emisar D4, mostly +#include "hwdef-emisar-d4.h" #include "cfg-emisar-d4.h" #undef MODEL_NUMBER #define MODEL_NUMBER "0122" @@ -20,4 +20,4 @@ #define THERM_FASTER_LEVEL 144 // throttle back faster when high // too big, turn off extra features -#undef USE_TACTICAL_MODE +//#undef USE_TACTICAL_MODE -- cgit v1.2.3 From 3a654aa5150a8943a787ecbfc65c2f9ff2bff75f Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Wed, 25 Oct 2023 10:26:56 -0600 Subject: rewrote blf-lantern (blf-lt1) code to use multi-channel and PWM+DSM, which required ... a few pretty significant changes: - no dynamic underclocking (it isn't compatible with DSM yet) - no tint ramping brightness correction (removed to save space) - removed ramp blinks (to save space, and because they're annoying) - removed momentary mode (to save space) - removed SOS mode (to save space) - removed (to save space) some other relatively recent features which weren't present in the original production firmware ... but some other things improved: + added smooth steps + extended Simple UI + added stepped tint ramping + added 13H factory reset, to save wear on threads + lower lows + smoother ramp + much higher tint ramp resolution in low modes I'm not entirely happy with this yet, so it probably needs additional work later in order to adjust the weird ramp shape (these 7135 chips have a weird response curve), add dynamic underclocking, cut down the ROM size if possible, re-add tint ramping brightness correction, etc. Multi-channel stuff in particular added a lot to the size. This is a pretty big change from the previous working build, so some users may want to stick with the last pre-multi-channel version. Non-trivial sacrifices were made to bring in more recent features. --- hwdef-BLF_LT1.h | 58 ------- hwdef-blf-lt1.c | 197 +++++++++++++++++++++++ hwdef-blf-lt1.h | 106 ++++++++++++ spaghetti-monster/anduril/cfg-blf-lantern.h | 97 ++++++----- spaghetti-monster/anduril/config-default.h | 4 + spaghetti-monster/anduril/load-save-config-fsm.h | 2 +- spaghetti-monster/anduril/load-save-config.h | 2 +- spaghetti-monster/anduril/ramp-mode.h | 2 +- spaghetti-monster/anduril/strobe-modes.c | 4 +- 9 files changed, 368 insertions(+), 104 deletions(-) delete mode 100644 hwdef-BLF_LT1.h create mode 100644 hwdef-blf-lt1.c create mode 100644 hwdef-blf-lt1.h diff --git a/hwdef-BLF_LT1.h b/hwdef-BLF_LT1.h deleted file mode 100644 index e7c4791..0000000 --- a/hwdef-BLF_LT1.h +++ /dev/null @@ -1,58 +0,0 @@ -// BLF LT1 driver layout -// Copyright (C) 2018-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * ---- - * Reset -|1 8|- VCC - * eswitch -|2 7|- (unused) - * aux LED -|3 6|- PWM (5000K) - * GND -|4 5|- PWM (3000K) - * ---- - */ - -#define ATTINY 85 -#include - -#define PWM_CHANNELS 1 // 1 virtual channel (1 for main LEDs + 1 for 2nd LEDs) -#define PWM_BITS 9 // 0 to 255 at 15.6 kHz, but goes to 510 for "200%" turbo -#define PWM_TOP 255 - -// dynamic PWM with tint ramping (not supported on attiny85) -//#define USE_DYN_PWM // dynamic frequency and speed -//#define PWM1_CNT TCNT0 // for dynamic PWM, reset phase -//#define PWM1_PHASE_RESET_OFF // force reset while shutting off -//#define PWM1_PHASE_RESET_ON // force reset while turning on -//#define PWM1_PHASE_SYNC // manual sync while changing level - -// usually PWM1_LVL would be a hardware register, but we need to abstract -// it out to a soft brightness value, in order to handle tint ramping -// (this allows smooth thermal regulation to work, and makes things -// otherwise simpler and easier) -uint16_t PWM1_LVL; - -#define PWM1_PIN PB0 // pin 5, warm tint PWM -#define TINT1_LVL OCR0A // OCR0A is the output compare register for PB0 - -#define PWM2_PIN PB1 // pin 6, cold tint PWM -#define TINT2_LVL OCR0B // OCR0B is the output compare register for PB1 - - -#define AUXLED_PIN PB4 // pin 3 - -#define SWITCH_PIN PB3 // pin 2 -#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt - -#define ADC_PRSCL 0x07 // clk/128 - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V -#endif - -#define FAST 0xA3 // fast PWM both channels -#define PHASE 0xA1 // phase-correct PWM both channels - -#define LAYOUT_DEFINED - diff --git a/hwdef-blf-lt1.c b/hwdef-blf-lt1.c new file mode 100644 index 0000000..df17612 --- /dev/null +++ b/hwdef-blf-lt1.c @@ -0,0 +1,197 @@ +// BLF LT1 PWM functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + + +void set_level_zero(); + +void set_level_ch1(uint8_t level); +void set_level_ch2(uint8_t level); +void set_level_both(uint8_t level); +void set_level_blend(uint8_t level); +//void set_level_auto(uint8_t level); // redundant + +#if 0 // gradual adjustments are disabled to save space +bool gradual_tick_ch1(uint8_t gt); +bool gradual_tick_ch2(uint8_t gt); +bool gradual_tick_both(uint8_t gt); +bool gradual_tick_blend(uint8_t gt); +//bool gradual_tick_auto(uint8_t gt); // redundant +#endif + + +Channel channels[] = { + { // channel 1 only + .set_level = set_level_ch1, + //.gradual_tick = gradual_tick_ch1, + .has_args = 0 + }, + { // channel 2 only + .set_level = set_level_ch2, + //.gradual_tick = gradual_tick_ch2, + .has_args = 0 + }, + { // both channels, tied together (max "200%" power) + .set_level = set_level_both, + //.gradual_tick = gradual_tick_both, + .has_args = 0 + }, + { // both channels, manual blend (max "100%" power) + .set_level = set_level_blend, + //.gradual_tick = gradual_tick_blend, + .has_args = 1 + }, + { // both channels, auto blend + .set_level = set_level_blend, + //.gradual_tick = gradual_tick_blend, + .has_args = 1 + }, +}; + +void set_level_zero() { + // turn off all LEDs + ch1_dsm_lvl = 0; + ch2_dsm_lvl = 0; + CH1_PWM = 0; + CH2_PWM = 0; +} + +// wrap setting the dsm vars, to get a faster response +// (just setting *_dsm_lvl doesn't work well for strobes) +void set_hw_levels(PWM_DATATYPE ch1, PWM_DATATYPE ch2) { + // set delta-sigma soft levels + ch1_dsm_lvl = ch1; + ch2_dsm_lvl = ch2; + + // set hardware PWM levels and init dsm loop + CH1_PWM = ch1_pwm = ch1 >> 7; + CH2_PWM = ch2_pwm = ch2 >> 7; +} + +// delta-sigma modulation of PWM outputs +// happens on each Timer0 overflow (every 512 cpu clock cycles) +// uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD) +ISR(TIMER0_OVF_vect) { + // set new hardware values first, + // for best timing (reduce effect of interrupt jitter) + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; + + // calculate next values, now that timing matters less + + // accumulate error + ch1_dsm += (ch1_dsm_lvl & 0x007f); + // next PWM = base PWM value + carry bit + ch1_pwm = (ch1_dsm_lvl >> 7) + (ch1_dsm > 0x7f); + // clear carry bit + ch1_dsm &= 0x7f; + + // repeat for other channels + + ch2_dsm += (ch2_dsm_lvl & 0x007f); + ch2_pwm = (ch2_dsm_lvl >> 7) + (ch2_dsm > 0x7f); + ch2_dsm &= 0x7f; +} + + +void set_level_ch1(uint8_t level) { + set_hw_levels(PWM_GET(pwm1_levels, level), 0); +} + +void set_level_ch2(uint8_t level) { + set_hw_levels(0, PWM_GET(pwm1_levels, level)); +} + +void set_level_both(uint8_t level) { + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, level); + set_hw_levels(pwm, pwm); +} + +void blend_helper(PWM_DATATYPE *warm, PWM_DATATYPE *cool, uint8_t level) { + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + uint8_t blend; + if (channel_mode == CM_AUTO) { + blend = 255 * (uint16_t)level / RAMP_SIZE; + if (cfg.channel_mode_args[channel_mode] & 0b01000000) + blend = 255 - blend; + } else { + blend = cfg.channel_mode_args[channel_mode]; + } + + calc_2ch_blend(warm, cool, brightness, DSM_TOP, blend); +} + +void set_level_blend(uint8_t level) { + PWM_DATATYPE warm, cool; + blend_helper(&warm, &cool, level); + set_hw_levels(warm, cool); +} + +/* +void set_level_auto(uint8_t level) { + PWM_DATATYPE warm, cool; + blend_helper(&warm, &cool, level); + set_hw_levels(warm, cool); +} +*/ + +///// "gradual tick" functions for smooth thermal regulation ///// +// (and other smooth adjustments) + +#if 0 // disabled to save space +///// bump each channel toward a target value ///// +bool gradual_adjust(PWM_DATATYPE ch1, PWM_DATATYPE ch2) { + // adjust multiple times based on current brightness + // (so it adjusts faster/coarser when bright, slower/finer when dim) + + // higher shift = slower/finer adjustments + const uint8_t shift = 9; // ((255 << 7) >> 9) = 63 max + uint8_t steps; + + steps = ch1_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(ch1, ch1_dsm_lvl); + + steps = ch2_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(ch2, ch2_dsm_lvl); + + if ((ch1 == ch1_dsm_lvl) + && (ch2 == ch2_dsm_lvl )) { + return true; // done + } + return false; // not done yet +} + +bool gradual_tick_ch1(uint8_t gt) { + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(pwm, 0); +} + +bool gradual_tick_ch2(uint8_t gt) { + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(0, pwm); +} + +bool gradual_tick_both(uint8_t gt) { + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(pwm, pwm); +} + +bool gradual_tick_blend(uint8_t gt) { + PWM_DATATYPE warm, cool; + blend_helper(&warm, &cool, gt); + return gradual_adjust(warm, cool); +} + +/* +bool gradual_tick_auto(uint8_t gt) { + PWM_DATATYPE warm, cool; + blend_helper(&warm, &cool, gt); + return gradual_adjust(warm, cool); +} +*/ + +#endif // if 0 + diff --git a/hwdef-blf-lt1.h b/hwdef-blf-lt1.h new file mode 100644 index 0000000..571fa44 --- /dev/null +++ b/hwdef-blf-lt1.h @@ -0,0 +1,106 @@ +// BLF LT1 driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * ---- + * Reset -|1 8|- VCC + * eswitch -|2 7|- (unused) + * aux LED -|3 6|- PWM (5000K) + * GND -|4 5|- PWM (3000K) + * ---- + */ + +#define ATTINY 85 +#include + +#define HWDEF_C_FILE hwdef-blf-lt1.c + +// channel modes: +// * 0. channel 1 only +// * 1. channel 2 only +// * 2. both channels, tied together, max "200%" power +// * 3. both channels, manual blend, max "100%" power +// * 4. both channels, auto blend, reversible +#define NUM_CHANNEL_MODES 5 +enum channel_modes_e { + CM_CH1 = 0, + CM_CH2, + CM_BOTH, + CM_BLEND, + CM_AUTO, +}; + + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00011000 +#define USE_CHANNEL_MODE_ARGS +// _, _, _, 128=middle CCT, 0=warm-to-cool +#define CHANNEL_MODE_ARGS 0,0,0,128,0 + +// can use some of the common handlers +#define USE_CALC_2CH_BLEND + + +#define PWM_CHANNELS 1 // old, remove this + +#define PWM_BITS 16 // 8-bit hardware PWM + 16-bit DSM + +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // 15-bit PWM+DSM ramp + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP_INIT 255 +#define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry + +// warm LEDs +uint16_t ch1_dsm_lvl; +uint8_t ch1_pwm, ch1_dsm; +#define CH1_PIN PB1 // pin 6, warm tint PWM +#define CH1_PWM OCR0B // OCR0B is the output compare register for PB1 + +// cold LEDs +uint16_t ch2_dsm_lvl; +uint8_t ch2_pwm, ch2_dsm; +#define CH2_PIN PB0 // pin 5, cold tint PWM +#define CH2_PWM OCR0A // OCR0A is the output compare register for PB0 + +#define AUXLED_PIN PB4 // pin 3 + +// e-switch +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt + +#define ADC_PRSCL 0x07 // clk/128 + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + + +inline void hwdef_setup() { + // configure PWM channels + DDRB = (1 << CH1_PIN) + | (1 << CH2_PIN); + + TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) + TCCR0A = PHASE; + + // enable timer 0 overflow interrupt for DSM purposes + TIMSK |= (1 << TOIE0); + + // configure e-switch + PORTB = (1 << SWITCH_PIN); // e-switch is the only input + PCMSK = (1 << SWITCH_PIN); // pin change interrupt uses this pin +} + + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/cfg-blf-lantern.h b/spaghetti-monster/anduril/cfg-blf-lantern.h index c6b7bc8..b4e9ce7 100644 --- a/spaghetti-monster/anduril/cfg-blf-lantern.h +++ b/spaghetti-monster/anduril/cfg-blf-lantern.h @@ -4,69 +4,70 @@ #pragma once #define MODEL_NUMBER "0621" -#include "hwdef-BLF_LT1.h" +#include "hwdef-blf-lt1.h" // ATTINY: 85 // the button lights up #define USE_INDICATOR_LED // the button is visible while main LEDs are on #define USE_INDICATOR_LED_WHILE_RAMPING -// off mode: high (2) +// off mode: low (1) // lockout: blinking (3) -#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) + +// channel modes... +// CM_CH1, CM_CH2, CM_BOTH, CM_BLEND, CM_AUTO +#define DEFAULT_CHANNEL_MODE CM_AUTO -// the lantern has two PWM channels, but they drive different sets of emitters -// (one channel for warm emitters, one channel for cold) -// so enable a special ramping mode which changes tint instead of brightness -#define USE_TINT_RAMPING // how much to increase total brightness at middle tint // (0 = 100% brightness, 64 = 200% brightness) //#define TINT_RAMPING_CORRECTION 26 // prototype, 140% -#define TINT_RAMPING_CORRECTION 10 // production model, 115% -//#define TINT_RAMPING_CORRECTION 0 // none +//#define TINT_RAMPING_CORRECTION 10 // production model, 115% +#define TINT_RAMPING_CORRECTION 0 // none -#ifdef RAMP_LENGTH -#undef RAMP_LENGTH -#endif +#define RAMP_SIZE 150 +// delta-sigma modulated PWM (0b0HHHHHHHHLLLLLLL = 0, 8xHigh, 7xLow bits) +// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) +// level_calc.py 5.01 1 150 7135 2 0.2 600 --pwm 32640 +//#define PWM1_LEVELS 2,4,5,7,9,12,14,17,20,23,27,31,35,39,44,50,56,62,68,76,83,91,100,110,120,130,142,154,167,181,195,211,227,244,263,282,303,324,347,371,397,424,452,482,513,545,580,616,653,693,734,778,823,871,920,972,1026,1083,1142,1203,1267,1334,1403,1475,1551,1629,1710,1795,1883,1974,2069,2167,2269,2375,2485,2599,2717,2839,2965,3096,3232,3372,3517,3667,3822,3982,4148,4319,4495,4677,4865,5060,5260,5466,5679,5899,6125,6358,6599,6846,7101,7363,7633,7911,8197,8491,8793,9104,9424,9753,10090,10437,10794,11160,11536,11922,12319,12726,13143,13572,14011,14462,14925,15399,15885,16383,16894,17417,17954,18503,19066,19642,20232,20837,21456,22089,22737,23400,24079,24774,25484,26211,26954,27713,28490,29284,30096,30926,31774,32640 +// level_calc.py 5.01 1 150 7135 128 0.2 600 --pwm 32640 +#define PWM1_LEVELS 128,130,131,133,135,138,140,143,146,149,153,157,161,165,170,176,181,188,194,201,209,217,226,235,245,256,267,279,292,306,320,336,352,369,388,407,428,449,472,496,521,548,576,606,637,669,703,739,777,816,858,901,946,993,1043,1094,1148,1204,1263,1324,1388,1455,1524,1596,1671,1749,1830,1914,2002,2093,2187,2285,2387,2492,2601,2715,2832,2954,3080,3210,3345,3485,3629,3779,3933,4093,4258,4428,4604,4785,4973,5166,5366,5571,5783,6002,6228,6460,6699,6946,7199,7461,7730,8006,8291,8584,8885,9195,9514,9841,10178,10523,10878,11243,11618,12002,12397,12803,13219,13645,14083,14532,14993,15465,15949,16446,16955,17476,18010,18558,19118,19692,20280,20882,21499,22130,22775,23436,24112,24804,25512,26235,26976,27732,28506,29297,30106,30932,31777,32640 + +#define DEFAULT_LEVEL 75 +#define MAX_1x7135 75 +#define HALFSPEED_LEVEL 44 +#define QUARTERSPEED_LEVEL 34 +#undef USE_DYNAMIC_UNDERCLOCKING // makes huge bumps in the ramp -// 1-130: 0 to 100% power -// level_calc.py 3.0 1 130 7135 1 30 800 --pwm 255 -// 131-150: 101% to 200% power -// level_calc.py 8.69 1 150 7135 1 1 1600 --pwm 510 -#define RAMP_LENGTH 150 -#define PWM1_LEVELS 1,1,2,2,3,3,4,5,5,6,6,7,8,8,9,10,10,11,12,12,13,14,15,16,17,17,18,19,20,21,22,23,24,25,26,27,28,29,31,32,33,34,35,37,38,39,40,42,43,45,46,47,49,50,52,54,55,57,58,60,62,63,65,67,69,70,72,74,76,78,80,82,84,86,88,90,92,95,97,99,101,104,106,108,111,113,115,118,121,123,126,128,131,134,136,139,142,145,148,150,153,156,159,162,166,169,172,175,178,181,185,188,191,195,198,202,205,209,213,216,220,224,227,231,235,239,243,247,251,255,264,274,284,294,305,316,327,339,351,363,376,389,403,417,431,446,461,477,493,510 -#define MAX_1x7135 130 -#define DEFAULT_LEVEL 70 -#define HALFSPEED_LEVEL 14 -#define QUARTERSPEED_LEVEL 5 +#define USE_SMOOTH_STEPS +//#define USE_SET_LEVEL_GRADUALLY // the default of 26 looks a bit flat, so increase it #define CANDLE_AMPLITUDE 40 // override default ramp style #undef RAMP_STYLE -#define RAMP_STYLE 1 // 0 = smooth, 1 = stepped +#define RAMP_STYLE 1 // 0 = smooth, 1 = stepped // set floor and ceiling as far apart as possible // because this lantern isn't overpowered -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 130 -#define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 5 +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 150 +#define RAMP_DISCRETE_FLOOR 1 +#define RAMP_DISCRETE_CEIL 150 +#define RAMP_DISCRETE_STEPS 7 // Allow 3C in Simple UI for switching between smooth and stepped ramping #define USE_SIMPLE_UI_RAMPING_TOGGLE +#define USE_EXTENDED_SIMPLE_UI // LT1 can handle heat well, so don't limit simple mode -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL -#define SIMPLE_UI_STEPS RAMP_DISCRETE_STEPS +#define SIMPLE_UI_FLOOR 10 +#define SIMPLE_UI_CEIL 150 +#define SIMPLE_UI_STEPS 5 // also at Sofirn's request, enable 2 click turbo (Anduril 1 style) -#define DEFAULT_2C_STYLE 1 +#define DEFAULT_2C_STYLE 1 -#define USE_SOS_MODE -#define USE_SOS_MODE_IN_BLINKY_GROUP // the sensor (attiny85) is nowhere near the emitters // so thermal regulation can't work @@ -74,18 +75,32 @@ #undef USE_THERMAL_REGULATION #endif -// don't blink at floor +// don't blink while ramping #ifdef BLINK_AT_RAMP_FLOOR #undef BLINK_AT_RAMP_FLOOR #endif -// blink at 100% power -#ifndef BLINK_AT_RAMP_MIDDLE -#define BLINK_AT_RAMP_MIDDLE +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE #endif -// blink again at the 200% power / ceil / turbo -#ifndef BLINK_AT_RAMP_CEIL -#define BLINK_AT_RAMP_CEIL +#ifdef BLINK_AT_RAMP_CEIL +#undef BLINK_AT_RAMP_CEIL #endif // too big, turn off extra features +//#undef USE_STEPPED_TINT_RAMPING +#undef USE_MOMENTARY_MODE #undef USE_TACTICAL_MODE +#undef USE_SOS_MODE +//#undef USE_SIMPLE_UI +//#undef USE_BEACON_MODE +//#undef USE_RAMP_SPEED_CONFIG +#undef USE_RAMP_AFTER_MOON_CONFIG +#undef USE_2C_STYLE_CONFIG +#undef USE_VOLTAGE_CORRECTION +//#undef USE_CHANNEL_PER_STROBE +// party strobe, tac strobe, lightning, candle, bike +#define DEFAULT_STROBE_CHANNELS CM_BOTH,CM_BOTH,CM_AUTO,CM_AUTO,CM_AUTO + +// for consistency with other models +#define USE_SOFT_FACTORY_RESET + diff --git a/spaghetti-monster/anduril/config-default.h b/spaghetti-monster/anduril/config-default.h index bc301e0..899bc4a 100644 --- a/spaghetti-monster/anduril/config-default.h +++ b/spaghetti-monster/anduril/config-default.h @@ -201,3 +201,7 @@ // 0 = none, 1 = smooth, 2+ = undefined #define DEFAULT_SMOOTH_STEPS_STYLE 1 +// by default, allow user to set the channel for each strobe-group mode +// (but allow disabling this feature per build) +#define USE_CHANNEL_PER_STROBE + diff --git a/spaghetti-monster/anduril/load-save-config-fsm.h b/spaghetti-monster/anduril/load-save-config-fsm.h index 0a9cabd..d189d3a 100644 --- a/spaghetti-monster/anduril/load-save-config-fsm.h +++ b/spaghetti-monster/anduril/load-save-config-fsm.h @@ -75,7 +75,7 @@ typedef struct Config { ///// strobe / blinky mode settings #ifdef USE_STROBE_STATE uint8_t strobe_type; - #if NUM_CHANNEL_MODES > 1 + #if (NUM_CHANNEL_MODES > 1) && defined(USE_CHANNEL_PER_STROBE) uint8_t strobe_channels[NUM_STROBES]; #endif #endif diff --git a/spaghetti-monster/anduril/load-save-config.h b/spaghetti-monster/anduril/load-save-config.h index 6ae2ba2..514fcbb 100644 --- a/spaghetti-monster/anduril/load-save-config.h +++ b/spaghetti-monster/anduril/load-save-config.h @@ -105,7 +105,7 @@ Config cfg = { #ifdef USE_STROBE_STATE .strobe_type = DEFAULT_STROBE, - #if NUM_CHANNEL_MODES > 1 + #if (NUM_CHANNEL_MODES > 1) && defined(USE_CHANNEL_PER_STROBE) // channel mode saved per strobe-group mode #ifdef DEFAULT_STROBE_CHANNELS .strobe_channels = { DEFAULT_STROBE_CHANNELS }, diff --git a/spaghetti-monster/anduril/ramp-mode.h b/spaghetti-monster/anduril/ramp-mode.h index 615da87..59c8db0 100644 --- a/spaghetti-monster/anduril/ramp-mode.h +++ b/spaghetti-monster/anduril/ramp-mode.h @@ -129,7 +129,7 @@ uint8_t nearest_level(int16_t target); // ensure ramp globals are correct void ramp_update_config(); -#ifdef USE_THERMAL_REGULATION +#if defined(USE_THERMAL_REGULATION) || defined(USE_SMOOTH_STEPS) // brightness before thermal step-down uint8_t target_level = 0; void set_level_and_therm_target(uint8_t level); diff --git a/spaghetti-monster/anduril/strobe-modes.c b/spaghetti-monster/anduril/strobe-modes.c index 31d2aad..ad17964 100644 --- a/spaghetti-monster/anduril/strobe-modes.c +++ b/spaghetti-monster/anduril/strobe-modes.c @@ -43,7 +43,7 @@ uint8_t strobe_state(Event event, uint16_t arg) { save_config(); return EVENT_HANDLED; } - #if NUM_CHANNEL_MODES > 1 + #if (NUM_CHANNEL_MODES > 1) && defined(USE_CHANNEL_PER_STROBE) // 3 clicks: rotate through channel modes for the current strobe else if (event == EV_3clicks) { // TODO: maybe skip aux modes? @@ -167,7 +167,7 @@ uint8_t strobe_state(Event event, uint16_t arg) { inline void strobe_state_iter() { uint8_t st = current_strobe_type; // can't use switch() on an enum - #if NUM_CHANNEL_MODES > 1 + #if (NUM_CHANNEL_MODES > 1) && defined(USE_CHANNEL_PER_STROBE) // remember channel mode for each strobe channel_mode = cfg.strobe_channels[st]; #endif -- cgit v1.2.3 From 5e86193dce022967cbe41288d30cb4b21500f5e6 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 26 Oct 2023 06:58:23 -0600 Subject: improved blf-lt1 ramp and fixed issue with missed button presses (it seems t85 doesn't like having timer overflow interrupts enabled in standby?) --- hwdef-blf-lt1.c | 7 +++++++ hwdef-blf-lt1.h | 2 +- spaghetti-monster/anduril/cfg-blf-lantern.h | 6 ++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/hwdef-blf-lt1.c b/hwdef-blf-lt1.c index df17612..8a8af52 100644 --- a/hwdef-blf-lt1.c +++ b/hwdef-blf-lt1.c @@ -50,6 +50,10 @@ Channel channels[] = { }; void set_level_zero() { + // disable timer 0 overflow interrupt + // (helps improve button press handling from Off state) + TIMSK &= ~(1 << TOIE0); + // turn off all LEDs ch1_dsm_lvl = 0; ch2_dsm_lvl = 0; @@ -67,6 +71,9 @@ void set_hw_levels(PWM_DATATYPE ch1, PWM_DATATYPE ch2) { // set hardware PWM levels and init dsm loop CH1_PWM = ch1_pwm = ch1 >> 7; CH2_PWM = ch2_pwm = ch2 >> 7; + + // enable timer 0 overflow interrupt so DSM can work + TIMSK |= (1 << TOIE0); } // delta-sigma modulation of PWM outputs diff --git a/hwdef-blf-lt1.h b/hwdef-blf-lt1.h index 571fa44..bac21cf 100644 --- a/hwdef-blf-lt1.h +++ b/hwdef-blf-lt1.h @@ -94,7 +94,7 @@ inline void hwdef_setup() { TCCR0A = PHASE; // enable timer 0 overflow interrupt for DSM purposes - TIMSK |= (1 << TOIE0); + //TIMSK |= (1 << TOIE0); // moved to hwdef.c functions instead // configure e-switch PORTB = (1 << SWITCH_PIN); // e-switch is the only input diff --git a/spaghetti-monster/anduril/cfg-blf-lantern.h b/spaghetti-monster/anduril/cfg-blf-lantern.h index b4e9ce7..b4c47db 100644 --- a/spaghetti-monster/anduril/cfg-blf-lantern.h +++ b/spaghetti-monster/anduril/cfg-blf-lantern.h @@ -28,10 +28,8 @@ #define RAMP_SIZE 150 // delta-sigma modulated PWM (0b0HHHHHHHHLLLLLLL = 0, 8xHigh, 7xLow bits) // (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) -// level_calc.py 5.01 1 150 7135 2 0.2 600 --pwm 32640 -//#define PWM1_LEVELS 2,4,5,7,9,12,14,17,20,23,27,31,35,39,44,50,56,62,68,76,83,91,100,110,120,130,142,154,167,181,195,211,227,244,263,282,303,324,347,371,397,424,452,482,513,545,580,616,653,693,734,778,823,871,920,972,1026,1083,1142,1203,1267,1334,1403,1475,1551,1629,1710,1795,1883,1974,2069,2167,2269,2375,2485,2599,2717,2839,2965,3096,3232,3372,3517,3667,3822,3982,4148,4319,4495,4677,4865,5060,5260,5466,5679,5899,6125,6358,6599,6846,7101,7363,7633,7911,8197,8491,8793,9104,9424,9753,10090,10437,10794,11160,11536,11922,12319,12726,13143,13572,14011,14462,14925,15399,15885,16383,16894,17417,17954,18503,19066,19642,20232,20837,21456,22089,22737,23400,24079,24774,25484,26211,26954,27713,28490,29284,30096,30926,31774,32640 -// level_calc.py 5.01 1 150 7135 128 0.2 600 --pwm 32640 -#define PWM1_LEVELS 128,130,131,133,135,138,140,143,146,149,153,157,161,165,170,176,181,188,194,201,209,217,226,235,245,256,267,279,292,306,320,336,352,369,388,407,428,449,472,496,521,548,576,606,637,669,703,739,777,816,858,901,946,993,1043,1094,1148,1204,1263,1324,1388,1455,1524,1596,1671,1749,1830,1914,2002,2093,2187,2285,2387,2492,2601,2715,2832,2954,3080,3210,3345,3485,3629,3779,3933,4093,4258,4428,4604,4785,4973,5166,5366,5571,5783,6002,6228,6460,6699,6946,7199,7461,7730,8006,8291,8584,8885,9195,9514,9841,10178,10523,10878,11243,11618,12002,12397,12803,13219,13645,14083,14532,14993,15465,15949,16446,16955,17476,18010,18558,19118,19692,20280,20882,21499,22130,22775,23436,24112,24804,25512,26235,26976,27732,28506,29297,30106,30932,31777,32640 +// level_calc.py 3.333 1 150 7135 32 0.2 600 --pwm 32640 +#define PWM1_LEVELS 32,35,38,41,45,50,55,61,67,74,82,91,100,110,121,133,146,160,175,192,209,227,247,268,291,314,340,366,395,424,456,489,524,560,599,639,681,726,772,820,871,924,979,1036,1096,1158,1222,1289,1359,1431,1506,1584,1664,1747,1834,1923,2015,2111,2209,2311,2416,2524,2636,2751,2870,2992,3118,3247,3380,3518,3659,3803,3952,4105,4262,4423,4589,4759,4933,5111,5294,5482,5674,5871,6073,6279,6491,6707,6928,7155,7386,7623,7865,8113,8365,8624,8888,9157,9432,9713,10000,10292,10591,10895,11206,11523,11846,12175,12511,12853,13202,13557,13919,14287,14663,15045,15434,15830,16233,16644,17061,17486,17919,18358,18805,19260,19723,20193,20671,21156,21650,22152,22662,23180,23706,24241,24784,25335,25895,26464,27041,27627,28222,28826,29439,30060,30691,31332,31981,32640 #define DEFAULT_LEVEL 75 #define MAX_1x7135 75 -- cgit v1.2.3 From be7c2ec510ca74b4f435684746039b42801724b3 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 26 Oct 2023 07:11:46 -0600 Subject: converted blf-gt-mini to new API --- hwdef-BLF_GT_Mini.h | 13 ------------- hwdef-blf-gt-mini.h | 14 ++++++++++++++ spaghetti-monster/anduril/cfg-blf-gt-mini.h | 3 ++- 3 files changed, 16 insertions(+), 14 deletions(-) delete mode 100644 hwdef-BLF_GT_Mini.h create mode 100644 hwdef-blf-gt-mini.h diff --git a/hwdef-BLF_GT_Mini.h b/hwdef-BLF_GT_Mini.h deleted file mode 100644 index 1706749..0000000 --- a/hwdef-BLF_GT_Mini.h +++ /dev/null @@ -1,13 +0,0 @@ -// BLF/Lumintop GT Mini driver layout -// Copyright (C) 2018-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -// exactly the same as a D1S, but with a lighted button -#include "hwdef-Emisar_D1S.h" - -// lighted button -#ifndef AUXLED_PIN -#define AUXLED_PIN PB4 // pin 3 -#endif - diff --git a/hwdef-blf-gt-mini.h b/hwdef-blf-gt-mini.h new file mode 100644 index 0000000..f4a4d7b --- /dev/null +++ b/hwdef-blf-gt-mini.h @@ -0,0 +1,14 @@ +// BLF/Lumintop GT Mini driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// exactly the same as a D1S, but with a lighted button +// (which is the same hwdef as a D4) +#include "hwdef-emisar-d4.h" + +// lighted button +#ifndef AUXLED_PIN +#define AUXLED_PIN PB4 // pin 3 +#endif + diff --git a/spaghetti-monster/anduril/cfg-blf-gt-mini.h b/spaghetti-monster/anduril/cfg-blf-gt-mini.h index 4158f21..083f18e 100644 --- a/spaghetti-monster/anduril/cfg-blf-gt-mini.h +++ b/spaghetti-monster/anduril/cfg-blf-gt-mini.h @@ -3,7 +3,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -#include "hwdef-BLF_GT_Mini.h" +#include "hwdef-blf-gt-mini.h" // Same as an Emisar D1S, except it has a lighted button #include "cfg-emisar-d1s.h" #undef MODEL_NUMBER @@ -15,6 +15,7 @@ #define USE_INDICATOR_LED_WHILE_RAMPING // too big, remove stuff to make room +#undef USE_TACTICAL_MODE #undef USE_SOS_MODE //#undef USE_RAMP_AFTER_MOON_CONFIG //#undef USE_RAMP_SPEED_CONFIG -- cgit v1.2.3 From fd7aa0297954c511d3f0ec2353a8fcc3c68a3b5a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 26 Oct 2023 08:29:44 -0600 Subject: converted Sofirn LT1-t1616 to new API, using SiteRelEnby's branch for reference (needs further updates though, to improve ramping, since this version is basically a straight conversion of the old t85 code with 8-bit ramps) --- hwdef-BLF_LT1-t1616.h | 105 --------------- hwdef-blf-lt1-t1616.c | 149 ++++++++++++++++++++++ hwdef-blf-lt1-t1616.h | 141 ++++++++++++++++++++ hwdef-sofirn-lt1s-pro.h | 51 ++++---- spaghetti-monster/anduril/cfg-blf-lantern-t1616.h | 57 +++++---- spaghetti-monster/anduril/cfg-blf-lantern.h | 9 +- spaghetti-monster/fsm-ramping.h | 4 +- 7 files changed, 353 insertions(+), 163 deletions(-) delete mode 100644 hwdef-BLF_LT1-t1616.h create mode 100644 hwdef-blf-lt1-t1616.c create mode 100644 hwdef-blf-lt1-t1616.h diff --git a/hwdef-BLF_LT1-t1616.h b/hwdef-BLF_LT1-t1616.h deleted file mode 100644 index 3e1d946..0000000 --- a/hwdef-BLF_LT1-t1616.h +++ /dev/null @@ -1,105 +0,0 @@ -// BLF LT1 driver layout using the Attiny1616 -// Copyright (C) 2021-2023 (FIXME) -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * Driver pinout: - * eSwitch: PA5 - * Aux LED: PB5 - * PWM FET: PB0 (TCA0 WO0) - * PWM 1x7135: PB1 (TCA0 WO1) - * Voltage: VCC - */ - - -#define LAYOUT_DEFINED - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1616 -#include - -#define PWM_CHANNELS 1 - -#ifndef SWITCH_PIN -#define SWITCH_PIN PIN5_bp -#define SWITCH_PORT VPORTA.IN -#define SWITCH_ISC_REG PORTA.PIN2CTRL -#define SWITCH_VECT PORTA_PORT_vect -#define SWITCH_INTFLG VPORTA.INTFLAGS -#endif - - -// usually PWM1_LVL would be a hardware register, but we need to abstract -// it out to a soft brightness value, in order to handle tint ramping -// (this allows smooth thermal regulation to work, and makes things -// otherwise simpler and easier) -uint8_t PWM1_LVL; - -// warm tint channel -#ifndef PWM1_PIN -#define PWM1_PIN PB1 // -#define TINT1_LVL TCA0.SINGLE.CMP1 // CMP1 is the output compare register for PB1 -#endif - -// cold tint channel -#ifndef PWM2_PIN -#define PWM2_PIN PB0 // -#define TINT2_LVL TCA0.SINGLE.CMP0 // CMP0 is the output compare register for PB0 -#endif - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V -#endif - - -// lighted button -#ifndef AUXLED_PIN -#define AUXLED_PIN PIN5_bp -#define AUXLED_PORT PORTB -#endif - - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - - // set up the system clock to run at 5 MHz instead of the default 3.33 MHz - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm ); - - //VPORTA.DIR = ...; - VPORTB.DIR = PIN0_bm | PIN1_bm | PIN5_bm; // Outputs: Aux LED and PWMs - //VPORTC.DIR = ...; - - // enable pullups on the unused pins to reduce power - PORTA.PIN0CTRL = PORT_PULLUPEN_bm; - PORTA.PIN1CTRL = PORT_PULLUPEN_bm; - PORTA.PIN2CTRL = PORT_PULLUPEN_bm; - PORTA.PIN3CTRL = PORT_PULLUPEN_bm; - PORTA.PIN4CTRL = PORT_PULLUPEN_bm; - PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch - PORTA.PIN6CTRL = PORT_PULLUPEN_bm; - PORTA.PIN7CTRL = PORT_PULLUPEN_bm; - - //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // cold tint channel - //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // warm tint channel - PORTB.PIN2CTRL = PORT_PULLUPEN_bm; - PORTB.PIN3CTRL = PORT_PULLUPEN_bm; - PORTB.PIN4CTRL = PORT_PULLUPEN_bm; - //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED - - PORTC.PIN0CTRL = PORT_PULLUPEN_bm; - PORTC.PIN1CTRL = PORT_PULLUPEN_bm; - PORTC.PIN2CTRL = PORT_PULLUPEN_bm; - PORTC.PIN3CTRL = PORT_PULLUPEN_bm; - - // set up the PWM - // TODO: add references to MCU documentation - TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_WGMODE_SINGLESLOPE_gc; - TCA0.SINGLE.PER = 255; - TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; -} - diff --git a/hwdef-blf-lt1-t1616.c b/hwdef-blf-lt1-t1616.c new file mode 100644 index 0000000..ea7e6b4 --- /dev/null +++ b/hwdef-blf-lt1-t1616.c @@ -0,0 +1,149 @@ +// Sofirn LT1-t1616 PWM helpers +// Copyright (C) 2023 SiteRelEnby, Selene ToyKeeper +// (adapted from emisar-2ch 15/10/2023) +#pragma once + +#include "chan-aux.c" + + +void set_level_zero(); + +void set_level_ch1(uint8_t level); +void set_level_ch2(uint8_t level); +void set_level_both(uint8_t level); +void set_level_blend(uint8_t level); +void set_level_auto(uint8_t level); + +bool gradual_tick_ch1(uint8_t gt); +bool gradual_tick_ch2(uint8_t gt); +bool gradual_tick_both(uint8_t gt); +bool gradual_tick_blend(uint8_t gt); +bool gradual_tick_auto(uint8_t gt); + + +Channel channels[] = { + { // channel 1 only + .set_level = set_level_ch1, + .gradual_tick = gradual_tick_ch1, + .has_args = 0 + }, + { // channel 2 only + .set_level = set_level_ch2, + .gradual_tick = gradual_tick_ch2, + .has_args = 0 + }, + { // both channels, tied together (max "200%" power) + .set_level = set_level_both, + .gradual_tick = gradual_tick_both, + .has_args = 0 + }, + { // both channels, manual blend (max "100%" power) + .set_level = set_level_blend, + .gradual_tick = gradual_tick_blend, + .has_args = 1 + }, + { // both channels, auto blend + .set_level = set_level_auto, + .gradual_tick = gradual_tick_auto, + .has_args = 1 + }, + AUX_CHANNELS +}; + + +void set_level_zero() { + CH1_PWM = 0; + CH2_PWM = 0; +} + +void set_pwms(PWM_DATATYPE ch1_pwm, PWM_DATATYPE ch2_pwm) { + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; +} + +void set_level_ch1(uint8_t level) { + set_pwms(PWM_GET(pwm1_levels, level), 0); +} + +void set_level_ch2(uint8_t level) { + set_pwms(0, PWM_GET(pwm1_levels, level)); +} + +void set_level_both(uint8_t level) { + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, level); + set_pwms(pwm, pwm); +} + +void set_level_blend(uint8_t level) { + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + uint8_t blend = cfg.channel_mode_args[channel_mode]; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend); + + set_pwms(ch1_pwm, ch2_pwm); +} + +void set_level_auto(uint8_t level) { + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); + uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; + if (cfg.channel_mode_args[channel_mode] & 0b01000000) + blend = 255 - blend; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend); + + set_pwms(ch1_pwm, ch2_pwm); +} + + +///// bump each channel toward a target value ///// +bool gradual_adjust(uint16_t ch1_pwm, uint16_t ch2_pwm) { + GRADUAL_ADJUST_SIMPLE(ch1_pwm, CH1_PWM); + GRADUAL_ADJUST_SIMPLE(ch2_pwm, CH2_PWM); + + // check for completion + if ((ch1_pwm == CH1_PWM) + && (ch2_pwm == CH2_PWM)) { + return true; // done + } + return false; // not done yet +} + +bool gradual_tick_ch1(uint8_t gt) { + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(pwm, 0); +} + +bool gradual_tick_ch2(uint8_t gt) { + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(0, pwm); +} + +bool gradual_tick_both(uint8_t gt) { + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt); + return gradual_adjust(pwm, pwm); +} + +bool gradual_tick_blend(uint8_t gt) { + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + uint8_t blend = cfg.channel_mode_args[channel_mode]; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend); + + return gradual_adjust(ch1_pwm, ch2_pwm); +} + +bool gradual_tick_auto(uint8_t gt) { + PWM_DATATYPE ch1_pwm, ch2_pwm; + PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); + uint8_t blend = 255 * (uint16_t)gt / RAMP_SIZE; + if (cfg.channel_mode_args[channel_mode] & 0b01000000) + blend = 255 - blend; + + calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend); + + return gradual_adjust(ch1_pwm, ch2_pwm); +} + diff --git a/hwdef-blf-lt1-t1616.h b/hwdef-blf-lt1-t1616.h new file mode 100644 index 0000000..4a411d4 --- /dev/null +++ b/hwdef-blf-lt1-t1616.h @@ -0,0 +1,141 @@ +// BLF LT1 driver layout using the Attiny1616 +// Copyright (C) 2021-2023 (gchart), Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * Driver pinout: + * eSwitch: PA5 + * Aux LED: PB5 + * PWM cool: PB0 (TCA0 WO0) + * PWM warm: PB1 (TCA0 WO1) + * Voltage: VCC + */ + +#define ATTINY 1616 +#include + +#define HWDEF_C_FILE hwdef-blf-lt1-t1616.c + +// allow using aux LEDs as extra channel modes +#include "chan-aux.h" + +// channel modes: +// * 0. warm only +// * 1. cool only +// * 2. both channels, tied together, max "200%" power +// * 3. both channels, manual blend, max "100%" power +// * 4. both channels, auto blend, reversible +#define NUM_CHANNEL_MODES 6 +enum channel_modes_e { + CM_CH1 = 0, + CM_CH2, + CM_BOTH, + CM_BLEND, + CM_AUTO, + CM_AUX +}; + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00011000 +#define USE_CHANNEL_MODE_ARGS +// _, _, _, 128=middle CCT, 0=warm-to-cool +#define CHANNEL_MODE_ARGS 0,0,0,128,0,0 + +// can use some of the common handlers +#define USE_CALC_2CH_BLEND + + +#define PWM_CHANNELS 1 // old, remove this + +#define PWM_BITS 8 // + +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP_INIT 255 // highest value used in the top half of the ramp +#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM +#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment +// TODO: implement DSM +#define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry + +// warm LEDs +#define CH1_PIN PB1 +#define CH1_PWM TCA0.SINGLE.CMP1 // CMP1 is the output compare register for PB1 + +// cold LEDs +#define CH2_PIN PB0 +#define CH2_PWM TCA0.SINGLE.CMP0 // CMP0 is the output compare register for PB0 + +// lighted button +#define AUXLED_PIN PIN5_bp +#define AUXLED_PORT PORTB + +// e-switch +#define SWITCH_PIN PIN5_bp +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN2CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + + +inline void hwdef_setup() { + + // set up the system clock to run at 5 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm ); + + //VPORTA.DIR = ...; + // Outputs: + VPORTB.DIR = PIN0_bm // cool white + | PIN1_bm // warm white + | PIN5_bm; // aux LED + //VPORTC.DIR = ...; + + // enable pullups on the unused pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + PORTA.PIN1CTRL = PORT_PULLUPEN_bm; + PORTA.PIN2CTRL = PORT_PULLUPEN_bm; + PORTA.PIN3CTRL = PORT_PULLUPEN_bm; + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch + PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // cold tint channel + //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // warm tint channel + PORTB.PIN2CTRL = PORT_PULLUPEN_bm; + PORTB.PIN3CTRL = PORT_PULLUPEN_bm; + PORTB.PIN4CTRL = PORT_PULLUPEN_bm; + //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED + + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + + // set up the PWM + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf + // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm + // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm + // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc + // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc + // TODO: add references to MCU documentation + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm + | TCA_SINGLE_CMP1EN_bm + | TCA_SINGLE_WGMODE_SINGLESLOPE_gc; + PWM_TOP = PWM_TOP_INIT; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc + | TCA_SINGLE_ENABLE_bm; +} + + +#define LAYOUT_DEFINED + diff --git a/hwdef-sofirn-lt1s-pro.h b/hwdef-sofirn-lt1s-pro.h index 3cc0ca9..97de7d7 100644 --- a/hwdef-sofirn-lt1s-pro.h +++ b/hwdef-sofirn-lt1s-pro.h @@ -43,57 +43,54 @@ enum channel_modes_e { //#define USE_CALC_AUTO_3CH_BLEND -// TODO: remove this as soon as it's not needed -#define PWM_CHANNELS 1 +#define PWM_CHANNELS 1 // old, remove this -#define SWITCH_PIN PIN5_bp -#define SWITCH_PORT VPORTA.IN -#define SWITCH_ISC_REG PORTA.PIN2CTRL -#define SWITCH_VECT PORTA_PORT_vect -#define SWITCH_INTFLG VPORTA.INTFLAGS +// only using 16-bit PWM on this light +#define PWM_BITS 16 +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM1_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // dynamic PWM // PWM parameters of all channels are tied together because they share a counter -#define PWM_TOP_INIT 511 // highest value used in the top half of the ramp +#define PWM_TOP_INIT 511 // highest value used in the top half of the ramp #define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM #define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment -// warm tint channel +// warm LEDs //#define WARM_PWM_PIN PB0 #define WARM_PWM_LVL TCA0.SINGLE.CMP0BUF // CMP1 is the output compare register for PB0 -// cold tint channel +// cold LEDs //#define COOL_PWM_PIN PB1 #define COOL_PWM_LVL TCA0.SINGLE.CMP1BUF // CMP0 is the output compare register for PB1 -// red channel +// red LEDs //#define RED_PWM_PIN PB2 #define RED_PWM_LVL TCA0.SINGLE.CMP2BUF // CMP2 is the output compare register for PB2 -// only using 16-bit PWM on this light -#define PWM_BITS 16 -#define PWM_GET PWM_GET16 -#define PWM_DATATYPE uint16_t -#define PWM1_DATATYPE uint16_t -#define PWM_DATATYPE2 uint32_t - - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V -#endif - - // lighted button -#define AUXLED_PIN PIN5_bp -#define AUXLED_PORT PORTB +#define AUXLED_PIN PIN5_bp +#define AUXLED_PORT PORTB // the button lights up #define USE_INDICATOR_LED // the button is visible while main LEDs are on #define USE_INDICATOR_LED_WHILE_RAMPING +// e-switch +#define SWITCH_PIN PIN5_bp +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN2CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif inline void hwdef_setup() { diff --git a/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h b/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h index 18caa5b..85784bb 100644 --- a/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h +++ b/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h @@ -1,35 +1,32 @@ // BLF Lantern config options for Anduril using the Attiny1616 -// Copyright (C) 2021-2023 (FIXME) +// Copyright (C) 2021-2023 (original author TBD), Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #define MODEL_NUMBER "0622" -#include "hwdef-BLF_LT1-t1616.h" +#include "hwdef-blf-lt1-t1616.h" // ATTINY: 1616 // the button lights up #define USE_INDICATOR_LED // the button is visible while main LEDs are on #define USE_INDICATOR_LED_WHILE_RAMPING -// off mode: high (2) +// off mode: low (1) // lockout: blinking (3) -#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2) +#define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) + +// channel modes... +// CM_CH1, CM_CH2, CM_BOTH, CM_BLEND, CM_AUTO +#define DEFAULT_CHANNEL_MODE CM_AUTO +#define DEFAULT_BLINK_CHANNEL CM_BOTH -// the lantern has two PWM channels, but they drive different sets of emitters -// (one channel for warm emitters, one channel for cold) -// so enable a special ramping mode which changes tint instead of brightness -#define USE_TINT_RAMPING // how much to increase total brightness at middle tint // (0 = 100% brightness, 64 = 200% brightness) //#define TINT_RAMPING_CORRECTION 26 // prototype, 140% #define TINT_RAMPING_CORRECTION 10 // production model, 115% -#ifdef RAMP_LENGTH -#undef RAMP_LENGTH -#endif - +#define RAMP_SIZE 150 // level_calc.py 1 150 7135 1 30 800 -#define RAMP_LENGTH 150 #define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,11,11,12,13,13,14,15,15,16,17,18,18,19,20,21,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,43,44,45,46,48,49,50,51,53,54,56,57,58,60,61,63,64,66,67,69,70,72,74,75,77,79,80,82,84,85,87,89,91,93,95,97,98,100,102,104,106,108,111,113,115,117,119,121,124,126,128,130,133,135,137,140,142,145,147,150,152,155,157,160,163,165,168,171,173,176,179,182,185,188,190,193,196,199,202,205,209,212,215,218,221,224,228,231,234,238,241,245,248,251,255 #define MAX_1x7135 65 #define HALFSPEED_LEVEL 14 @@ -40,40 +37,48 @@ // override default ramp style #undef RAMP_STYLE -#define RAMP_STYLE 1 // 0 = smooth, 1 = stepped +#define RAMP_STYLE 1 // 0 = smooth, 1 = stepped // set floor and ceiling as far apart as possible // because this lantern isn't overpowered -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 150 -#define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 5 +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 150 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL 150 +#define RAMP_DISCRETE_STEPS 7 // LT1 can handle heat well, so don't limit simple mode -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL -#define SIMPLE_UI_STEPS RAMP_DISCRETE_STEPS +#define SIMPLE_UI_FLOOR 10 +#define SIMPLE_UI_CEIL 150 +#define SIMPLE_UI_STEPS 5 // Allow 3C in Simple UI for switching between smooth and stepped ramping #define USE_SIMPLE_UI_RAMPING_TOGGLE +#define USE_EXTENDED_SIMPLE_UI #define USE_SOS_MODE #define USE_SOS_MODE_IN_BLINKY_GROUP -// the sensor (attiny85) is nowhere near the emitters +// the sensor (attiny1616) is nowhere near the emitters // so thermal regulation can't work #ifdef USE_THERMAL_REGULATION #undef USE_THERMAL_REGULATION #endif // don't blink while ramping -#ifdef BLINK_AT_RAMP_MIDDLE -#undef BLINK_AT_RAMP_MIDDLE -#endif #ifdef BLINK_AT_RAMP_FLOOR #undef BLINK_AT_RAMP_FLOOR #endif +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif // except the top... blink at the top #ifndef BLINK_AT_RAMP_CEIL #define BLINK_AT_RAMP_CEIL #endif + +#define USE_CHANNEL_MODE_ARGS +#define USE_SET_LEVEL_GRADUALLY + +// for consistency with other models +#define USE_SOFT_FACTORY_RESET + diff --git a/spaghetti-monster/anduril/cfg-blf-lantern.h b/spaghetti-monster/anduril/cfg-blf-lantern.h index b4c47db..53c3203 100644 --- a/spaghetti-monster/anduril/cfg-blf-lantern.h +++ b/spaghetti-monster/anduril/cfg-blf-lantern.h @@ -18,6 +18,7 @@ // channel modes... // CM_CH1, CM_CH2, CM_BOTH, CM_BLEND, CM_AUTO #define DEFAULT_CHANNEL_MODE CM_AUTO +//#define DEFAULT_BLINK_CHANNEL CM_BOTH // takes too much space // how much to increase total brightness at middle tint // (0 = 100% brightness, 64 = 200% brightness) @@ -54,15 +55,15 @@ #define RAMP_DISCRETE_CEIL 150 #define RAMP_DISCRETE_STEPS 7 -// Allow 3C in Simple UI for switching between smooth and stepped ramping -#define USE_SIMPLE_UI_RAMPING_TOGGLE -#define USE_EXTENDED_SIMPLE_UI - // LT1 can handle heat well, so don't limit simple mode #define SIMPLE_UI_FLOOR 10 #define SIMPLE_UI_CEIL 150 #define SIMPLE_UI_STEPS 5 +// Allow 3C in Simple UI for switching between smooth and stepped ramping +#define USE_SIMPLE_UI_RAMPING_TOGGLE +#define USE_EXTENDED_SIMPLE_UI + // also at Sofirn's request, enable 2 click turbo (Anduril 1 style) #define DEFAULT_2C_STYLE 1 diff --git a/spaghetti-monster/fsm-ramping.h b/spaghetti-monster/fsm-ramping.h index bfcc5fb..c4b7d48 100644 --- a/spaghetti-monster/fsm-ramping.h +++ b/spaghetti-monster/fsm-ramping.h @@ -69,7 +69,9 @@ void gradual_tick(); #define STACKED_PWM_DATATYPE uint8_t #define PWM_DATATYPE uint8_t #define PWM_DATATYPE2 uint16_t - #define PWM_TOP 255 + #ifndef PWM_TOP + #define PWM_TOP 255 + #endif #define STACKED_PWM_TOP 255 #ifndef PWM_GET #define PWM_GET(x,y) pgm_read_byte(x+y) -- cgit v1.2.3 From 3be63ea383d1a0a9251eb7de974ee2012535b1b1 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 26 Oct 2023 08:47:28 -0600 Subject: minor comment cleanup --- hwdef-blf-lt1.h | 1 + hwdef-emisar-2ch.c | 1 - hwdef-emisar-d4k-3ch.c | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hwdef-blf-lt1.h b/hwdef-blf-lt1.h index bac21cf..8fce09f 100644 --- a/hwdef-blf-lt1.h +++ b/hwdef-blf-lt1.h @@ -68,6 +68,7 @@ uint8_t ch2_pwm, ch2_dsm; #define CH2_PIN PB0 // pin 5, cold tint PWM #define CH2_PWM OCR0A // OCR0A is the output compare register for PB0 +// lighted button #define AUXLED_PIN PB4 // pin 3 // e-switch diff --git a/hwdef-emisar-2ch.c b/hwdef-emisar-2ch.c index 31d27af..b09b681 100644 --- a/hwdef-emisar-2ch.c +++ b/hwdef-emisar-2ch.c @@ -1,7 +1,6 @@ // Emisar 2-channel generic w/ tint ramping // Copyright (C) 2021-2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later - #pragma once #include "chan-rgbaux.c" diff --git a/hwdef-emisar-d4k-3ch.c b/hwdef-emisar-d4k-3ch.c index 3fed41a..58e9b35 100644 --- a/hwdef-emisar-d4k-3ch.c +++ b/hwdef-emisar-d4k-3ch.c @@ -6,6 +6,7 @@ #include "spaghetti-monster/anduril/channel-modes.h" //for circular_tint_3h() #include "chan-rgbaux.c" +void set_level_zero(); void set_level_main2(uint8_t level); void set_level_led3(uint8_t level); -- cgit v1.2.3 From 2ae15056b8ef9d1be92896fba37d24d4f37aeeaa Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 26 Oct 2023 11:42:07 -0600 Subject: fixed emisar-d1v2 builds (only needed a simple one-liner) --- spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h | 2 +- spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h | 2 +- spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h b/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h index 6df56cf..4022ba6 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1v2-7135-fet.h @@ -17,7 +17,7 @@ // (early short run had no button LEDs at all, later run uses linear+FET instead, // so it's unlikely that anyone needs this, but it doesn't hurt anything) #define USE_AUX_RGB_LEDS -#define USE_AUX_RGB_LEDS_WHILE_ON +#define USE_AUX_RGB_LEDS_WHILE_ON 25 #define USE_INDICATOR_LED_WHILE_RAMPING // safe limit ~50% power diff --git a/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h b/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h index c1f7238..28c57f8 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1v2-linear-fet.h @@ -15,7 +15,7 @@ #define USE_BUTTON_LED // the aux LEDs are in the button, so use them while main LEDs are on #define USE_AUX_RGB_LEDS -#define USE_AUX_RGB_LEDS_WHILE_ON +#define USE_AUX_RGB_LEDS_WHILE_ON 25 #define USE_INDICATOR_LED_WHILE_RAMPING // safe limit: max regulated power diff --git a/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h b/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h index a68a333..7f5bcc4 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h +++ b/spaghetti-monster/anduril/cfg-emisar-d1v2-nofet.h @@ -15,7 +15,7 @@ #define USE_BUTTON_LED // the aux LEDs are in the button, so use them while main LEDs are on #define USE_AUX_RGB_LEDS -#define USE_AUX_RGB_LEDS_WHILE_ON +#define USE_AUX_RGB_LEDS_WHILE_ON 25 #define USE_INDICATOR_LED_WHILE_RAMPING // safe limit: same as regular ramp -- cgit v1.2.3 From 72869219af30462fd803e2f801516d42d7d08cef Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 26 Oct 2023 11:45:04 -0600 Subject: fixed blf-q8 build (was 6 bytes too big) --- spaghetti-monster/anduril/cfg-blf-q8.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spaghetti-monster/anduril/cfg-blf-q8.h b/spaghetti-monster/anduril/cfg-blf-q8.h index 7eda018..956b9f4 100644 --- a/spaghetti-monster/anduril/cfg-blf-q8.h +++ b/spaghetti-monster/anduril/cfg-blf-q8.h @@ -49,10 +49,16 @@ // Allow 3C in Simple UI for switching between smooth and stepped ramping #define USE_SIMPLE_UI_RAMPING_TOGGLE +#define USE_EXTENDED_SIMPLE_UI // stop panicking at ~75% power or ~3000 lm, this light has high thermal mass #define THERM_FASTER_LEVEL (RAMP_SIZE*9/10) // throttle back faster when high +// don't blink mid-ramp +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + // too big, remove stuff to make room #undef USE_SOS_MODE //#undef USE_RAMP_AFTER_MOON_CONFIG -- cgit v1.2.3 From 0f3c3a649290f2fd7f03c7e59985c5760075d49a Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 27 Oct 2023 02:53:03 -0600 Subject: converted noctigon-kr4-boost to new API (it's almost identical to noctigon-dm11-boost) --- hwdef-Noctigon_KR4-12V.h | 158 --------------------- hwdef-noctigon-kr4-boost.h | 57 ++++++++ spaghetti-monster/anduril/cfg-noctigon-kr4-12v.h | 74 ---------- spaghetti-monster/anduril/cfg-noctigon-kr4-boost.h | 16 +++ 4 files changed, 73 insertions(+), 232 deletions(-) delete mode 100644 hwdef-Noctigon_KR4-12V.h create mode 100644 hwdef-noctigon-kr4-boost.h delete mode 100644 spaghetti-monster/anduril/cfg-noctigon-kr4-12v.h create mode 100644 spaghetti-monster/anduril/cfg-noctigon-kr4-boost.h diff --git a/hwdef-Noctigon_KR4-12V.h b/hwdef-Noctigon_KR4-12V.h deleted file mode 100644 index 57d39f2..0000000 --- a/hwdef-Noctigon_KR4-12V.h +++ /dev/null @@ -1,158 +0,0 @@ -// Noctigon KR4 (12V) driver layout (attiny1634) -// Copyright (C) 2020-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * (based on Noctigon DM11-12V and KR4) - * - * Pin / Name / Function - * 1 PA6 (none) (PWM1B) (reserved for DD drivers) - * 2 PA5 R: red aux LED (PWM0B) - * 3 PA4 G: green aux LED - * 4 PA3 B: blue aux LED - * 5 PA2 L: button LED - * 6 PA1 (none) - * 7 PA0 (none) - * 8 GND GND - * 9 VCC VCC - * 10 PC5 (none) - * 11 PC4 (none) - * 12 PC3 RESET - * 13 PC2 (none) - * 14 PC1 SCK - * 15 PC0 boost PMIC enable (PWM0A not used) - * 16 PB3 main LED PWM (PWM1A) - * 17 PB2 MISO / e-switch (PCINT10) - * 18 PB1 MOSI / battery voltage (ADC6) - * 19 PB0 Opamp power - * 20 PA7 (none) (PCINT7) - * ADC12 thermal sensor - * - * Main LED power uses one pin to turn the Opamp on/off, - * and one pin to control Opamp power level. - * Linear brightness control uses the power level pin, with dynamic PWM. - * The on/off pin is only used to turn the main LED on and off, - * not to change brightness. - */ - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1634 -#include - -#define PWM_CHANNELS 1 // can't use DD FET on boost drivers -#define PWM_BITS 16 // data type needs 16 bits, not 8 -#define PWM_TOP 255 // highest value used in top half of ramp -#define USE_DYN_PWM // dynamic frequency and speed - -#define SWITCH_PIN PB2 // pin 17 -#define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt -#define SWITCH_PCIE PCIE1 // PCIE1 is for PCINT[11:8] -#define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] -#define SWITCH_PORT PINB // PINA or PINB or PINC -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] - -#define PWM1_PIN PB3 // pin 16, Opamp reference -#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 -#define PWM1_CNT TCNT1 // for dynamic PWM, reset phase -#define PWM1_PHASE_RESET_OFF // force reset while shutting off -#define PWM1_PHASE_RESET_ON // force reset while turning on -#define PWM1_PHASE_SYNC // manual sync while changing level - -// PWM parameters of both channels are tied together because they share a counter -#define PWM1_TOP ICR1 // holds the TOP value for for variable-resolution PWM - -#define LED_ENABLE_PIN PB0 // pin 19, Opamp power -#define LED_ENABLE_PORT PORTB // control port for PB0 - -#define LED2_ENABLE_PIN PC0 // pin 15, boost PMIC enable -#define LED2_ENABLE_PORT PORTC // control port for PC0 - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -#define BUTTON_LED_PIN PA2 // pin 5 -#define BUTTON_LED_PORT PORTA // for all "PA" pins -#define BUTTON_LED_DDR DDRA // for all "PA" pins -#define BUTTON_LED_PUE PUEA // for all "PA" pins - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - // enable output ports - // boost PMIC on/off - DDRC = (1 << LED2_ENABLE_PIN); - // Opamp level and Opamp on/off - DDRB = (1 << PWM1_PIN) - | (1 << LED_ENABLE_PIN); - // aux R/G/B, button LED - DDRA = (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - | (1 << BUTTON_LED_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 0,0: PWM OC1B disabled (DS table 12-4) - TCCR1A = (1< end of dynamic PWM range - -// slow down party strobe; this driver can't pulse for 2ms or less -#define PARTY_STROBE_ONTIME 3 - -#define THERM_CAL_OFFSET 5 - -// the power regulator seems to "jump start" the LEDs all on its own, -// so the firmware doesn't have to -// (and unfortunately the power regulator jumps it a bit too hard) -#define DEFAULT_JUMP_START_LEVEL 1 -#define BLINK_BRIGHTNESS 50 -#define BLINK_ONCE_TIME 12 - -// can't reset the normal way because power is connected before the button -#define USE_SOFT_FACTORY_RESET diff --git a/spaghetti-monster/anduril/cfg-noctigon-kr4-boost.h b/spaghetti-monster/anduril/cfg-noctigon-kr4-boost.h new file mode 100644 index 0000000..1603acf --- /dev/null +++ b/spaghetti-monster/anduril/cfg-noctigon-kr4-boost.h @@ -0,0 +1,16 @@ +// Noctigon KR4 (12V) config options for Anduril +// (and Noctigon KR1) +// Copyright (C) 2020-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// the only things different from dm11-boost are: +// - e-switch is on a different pin (defined in hwdef) +// - different model number +#include "cfg-noctigon-dm11-boost.h" +#include "hwdef-noctigon-kr4-boost.h" +#undef MODEL_NUMBER +#define MODEL_NUMBER "0216" +#include "hank-cfg.h" +// ATTINY: 1634 + -- cgit v1.2.3 From 05015b37f89f508482946160fe716fa239d0e005 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 27 Oct 2023 03:24:25 -0600 Subject: converted blf-q8-t1616 to new API, using wurkkos-ts10 and wurkkos-ts25 as a base (since the Q8 driver was the direct predecessor to those Wurkkos drivers, they're almost identical) --- hwdef-BLF_Q8-T1616.h | 105 -------------------- hwdef-blf-q8-t1616.h | 138 +++++++++++++++++++++++++++ hwdef-wurkkos-ts10.h | 11 ++- spaghetti-monster/anduril/cfg-blf-q8-t1616.h | 60 ++++++++---- 4 files changed, 184 insertions(+), 130 deletions(-) delete mode 100644 hwdef-BLF_Q8-T1616.h create mode 100644 hwdef-blf-q8-t1616.h diff --git a/hwdef-BLF_Q8-T1616.h b/hwdef-BLF_Q8-T1616.h deleted file mode 100644 index 25734ba..0000000 --- a/hwdef-BLF_Q8-T1616.h +++ /dev/null @@ -1,105 +0,0 @@ -// BLF Q8 driver layout using the Attiny1616 -// Copyright (C) 2021-2023 (FIXME) -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * Driver pinout: - * eSwitch: PA5 - * Aux LED: PB5 - * PWM FET: PB0 (TCA0 WO0) - * PWM 1x7135: PB1 (TCA0 WO1) - * Voltage: VCC -*/ - - -#define LAYOUT_DEFINED - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1616 -#include - -#define PWM_CHANNELS 2 - -#ifndef SWITCH_PIN -#define SWITCH_PIN PIN5_bp -#define SWITCH_PORT VPORTA.IN -#define SWITCH_ISC_REG PORTA.PIN2CTRL -#define SWITCH_VECT PORTA_PORT_vect -#define SWITCH_INTFLG VPORTA.INTFLAGS -#endif - - -// 7135 channel -#ifndef PWM1_PIN -#define PWM1_PIN PB1 // -#define PWM1_LVL TCA0.SINGLE.CMP1 // CMP1 is the output compare register for PB1 -#endif - -// FET channel -#ifndef PWM2_PIN -#define PWM2_PIN PB0 // -#define PWM2_LVL TCA0.SINGLE.CMP0 // CMP0 is the output compare register for PB0 -#endif - -// average drop across diode on this hardware -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V -#endif - - -// lighted button -#ifndef AUXLED_PIN -#define AUXLED_PIN PIN5_bp -#define AUXLED_PORT PORTB -#endif - - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - - // set up the system clock to run at 10 MHz instead of the default 3.33 MHz - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); - - //VPORTA.DIR = ...; - VPORTB.DIR = PIN0_bm | PIN1_bm | PIN5_bm; // Outputs: Aux LED and PWMs - //VPORTC.DIR = ...; - - // enable pullups on the unused pins to reduce power - PORTA.PIN0CTRL = PORT_PULLUPEN_bm; - PORTA.PIN1CTRL = PORT_PULLUPEN_bm; - PORTA.PIN2CTRL = PORT_PULLUPEN_bm; - PORTA.PIN3CTRL = PORT_PULLUPEN_bm; - PORTA.PIN4CTRL = PORT_PULLUPEN_bm; - PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch - PORTA.PIN6CTRL = PORT_PULLUPEN_bm; - PORTA.PIN7CTRL = PORT_PULLUPEN_bm; - - //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // FET channel - //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // 7135 channel - PORTB.PIN2CTRL = PORT_PULLUPEN_bm; - PORTB.PIN3CTRL = PORT_PULLUPEN_bm; - PORTB.PIN4CTRL = PORT_PULLUPEN_bm; - //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED - - PORTC.PIN0CTRL = PORT_PULLUPEN_bm; - PORTC.PIN1CTRL = PORT_PULLUPEN_bm; - PORTC.PIN2CTRL = PORT_PULLUPEN_bm; - PORTC.PIN3CTRL = PORT_PULLUPEN_bm; - - // set up the PWM - // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf - // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm - // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm - // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm - // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc - // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc - // See the manual for other pins, clocks, configs, portmux, etc - TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_WGMODE_DSBOTTOM_gc; - TCA0.SINGLE.PER = 255; - TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; -} - diff --git a/hwdef-blf-q8-t1616.h b/hwdef-blf-q8-t1616.h new file mode 100644 index 0000000..d9b981f --- /dev/null +++ b/hwdef-blf-q8-t1616.h @@ -0,0 +1,138 @@ +// BLF Q8 driver layout using the Attiny1616 +// Copyright (C) 2021-2023 gchart, Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +/* + * (based on Wurkkos TS10 driver layout, + * which in turn was based on an older version of this BLF-Q8-t1616 driver) + * (should probably merge the two files at some point) + * Driver pinout: + * eSwitch: PA5 + * Aux LED: PB5 + * PWM FET: PB0 (TCA0 WO0) + * PWM 1x7135: PB1 (TCA0 WO1) + * Voltage: VCC + */ + +#define ATTINY 1616 +#include + +// nearly all t1616-based FET+1 drivers work pretty much the same +// (this one has single-color aux like the TS10) +#define HWDEF_C_FILE hwdef-wurkkos-ts10.c + +// allow using aux LEDs as extra channel modes +#include "chan-aux.h" + +// channel modes: +// * 0. FET+7135 stacked +// * 1. aux LEDs +#define NUM_CHANNEL_MODES 2 +enum CHANNEL_MODES { + CM_MAIN = 0, + CM_AUX +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00000001 + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // 1x7135 ramp +#define PWM2_DATATYPE uint8_t // DD FET ramp + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 255 // highest value used in top half of ramp +// not necessary when double-buffered "BUF" registers are used +#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment + +// 1x7135 channel +#define CH1_PIN PB1 +#define CH1_PWM TCA0.SINGLE.CMP1BUF // CMP1 is the output compare register for PB1 + +// DD FET channel +#define CH2_PIN PB0 +#define CH2_PWM TCA0.SINGLE.CMP0BUF // CMP0 is the output compare register for PB0 + +// e-switch +#define SWITCH_PIN PIN5_bp +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN2CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + +// lighted button +#define AUXLED_PIN PIN5_bp +#define AUXLED_PORT PORTB + + +inline void hwdef_setup() { + + // set up the system clock to run at 10 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, + CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + + //VPORTA.DIR = ...; + // Outputs + VPORTB.DIR = PIN0_bm // DD FET + | PIN1_bm // 7135 + | PIN5_bm; // Aux LED + //VPORTC.DIR = ...; + + // enable pullups on the unused pins to reduce power + PORTA.PIN0CTRL = PORT_PULLUPEN_bm; + PORTA.PIN1CTRL = PORT_PULLUPEN_bm; + PORTA.PIN2CTRL = PORT_PULLUPEN_bm; + PORTA.PIN3CTRL = PORT_PULLUPEN_bm; + PORTA.PIN4CTRL = PORT_PULLUPEN_bm; + PORTA.PIN5CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // eSwitch + PORTA.PIN6CTRL = PORT_PULLUPEN_bm; + PORTA.PIN7CTRL = PORT_PULLUPEN_bm; + + //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // FET channel + //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // 7135 channel + PORTB.PIN2CTRL = PORT_PULLUPEN_bm; + PORTB.PIN3CTRL = PORT_PULLUPEN_bm; + PORTB.PIN4CTRL = PORT_PULLUPEN_bm; + //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED + + PORTC.PIN0CTRL = PORT_PULLUPEN_bm; + PORTC.PIN1CTRL = PORT_PULLUPEN_bm; + PORTC.PIN2CTRL = PORT_PULLUPEN_bm; + PORTC.PIN3CTRL = PORT_PULLUPEN_bm; + + // set up the PWM + // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf + // PB0 is TCA0:WO0, use TCA_SINGLE_CMP0EN_bm + // PB1 is TCA0:WO1, use TCA_SINGLE_CMP1EN_bm + // PB2 is TCA0:WO2, use TCA_SINGLE_CMP2EN_bm + // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc + // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc + // See the manual for other pins, clocks, configs, portmux, etc + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm + | TCA_SINGLE_CMP1EN_bm + | TCA_SINGLE_WGMODE_DSBOTTOM_gc; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc + | TCA_SINGLE_ENABLE_bm; + + PWM_TOP = PWM_TOP_INIT; + +} + + +#define LAYOUT_DEFINED + diff --git a/hwdef-wurkkos-ts10.h b/hwdef-wurkkos-ts10.h index 4af6a84..e693c99 100644 --- a/hwdef-wurkkos-ts10.h +++ b/hwdef-wurkkos-ts10.h @@ -1,5 +1,5 @@ // Wurkkos TS10 driver layout -// Copyright (C) 2022-2023 (FIXME) +// Copyright (C) 2021-2023 gchart, Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once @@ -32,6 +32,7 @@ enum CHANNEL_MODES { #define DEFAULT_CHANNEL_MODE CM_MAIN +// right-most bit first, modes are in fedcba9876543210 order #define CHANNEL_MODES_ENABLED 0b00000001 @@ -84,10 +85,10 @@ inline void hwdef_setup() { CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); //VPORTA.DIR = ...; - // Outputs: Aux LED and PWMs - VPORTB.DIR = PIN0_bm - | PIN1_bm - | PIN5_bm; + // Outputs + VPORTB.DIR = PIN0_bm // DD FET + | PIN1_bm // 7135 + | PIN5_bm; // Aux LED //VPORTC.DIR = ...; // enable pullups on the unused pins to reduce power diff --git a/spaghetti-monster/anduril/cfg-blf-q8-t1616.h b/spaghetti-monster/anduril/cfg-blf-q8-t1616.h index a88ab24..9f0402c 100644 --- a/spaghetti-monster/anduril/cfg-blf-q8-t1616.h +++ b/spaghetti-monster/anduril/cfg-blf-q8-t1616.h @@ -1,10 +1,11 @@ // BLF Q8 config options for Anduril using the Attiny1616 -// Copyright (C) 2021-2023 (FIXME) +// Copyright (C) 2021-2023 gchart, Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #define MODEL_NUMBER "0613" -#include "hwdef-BLF_Q8-T1616.h" +#include "hwdef-blf-q8-t1616.h" +#include "wurkkos-cfg.h" // Sofirn lights are closely related to Wurkkos // ATTINY: 1616 // the button lights up @@ -15,28 +16,35 @@ // lockout: blinking (3) #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) -// copied from Emisar D4 ramp -// ../../bin/level_calc.py 1 65 7135 1 0.8 150 -// ... mixed with this: -// ../../bin/level_calc.py 2 150 7135 4 0.33 150 FET 1 10 1500 -#define RAMP_LENGTH 150 -#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 -#define MAX_1x7135 65 -#define HALFSPEED_LEVEL 14 +// copied from Wurkkos TS25 ramp +#define RAMP_SIZE 150 +// 7135 at 75/150 +// level_calc.py 5.7895 2 150 7135 1 0.1 130 FET 1 10 3000 --pwm dyn:74:4096:255:3 +// (with some manual tweaks) +#define PWM1_LEVELS 1,1,2,3,3,4,5,6,7,8,9,11,12,13,15,16,18,19,21,23,26,27,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,71,74,76,78,80,82,85,87,90,93,96,100,103,107,112,116,122,127,133,140,147,154,163,171,182,192,203,215,228,241,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +// non-zero part of FET channel calculated with: +// level_calc.py 3 1 75 7135 1 200 3000 +// (FIXME? there's a visible bump when the FET kicks in, even with just 1/255) +#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,7,8,10,11,13,14,16,17,19,21,22,24,26,28,30,32,34,37,39,41,44,46,48,51,54,56,59,62,65,68,71,74,77,81,84,87,91,94,98,102,106,110,114,118,122,126,130,135,139,144,148,153,158,163,168,173,178,184,189,195,200,206,212,218,224,230,236,242,248,255 +#define PWM_TOPS 4095,2701,3200,3586,2518,2778,2834,2795,2705,2587,2455,2582,2412,2247,2256,2091,2062,1907,1860,1802,1737,1605,1542,1477,1412,1347,1284,1222,1162,1105,1050,997,946,898,853,810,768,730,693,658,625,594,564,536,503,485,462,439,418,398,384,366,353,340,327,319,307,298,292,284,280,273,269,266,263,260,258,256,256,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 + +#define MAX_1x7135 75 +#define DEFAULT_LEVEL 50 +#define MIN_THERM_STEPDOWN 60 +#define HALFSPEED_LEVEL 20 #define QUARTERSPEED_LEVEL 5 -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 120 -// 10 28 46 [65] 83 101 120 -#define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 7 +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 150 +// 20 38 56 [75] 93 111 130 +#define RAMP_DISCRETE_FLOOR 20 +#define RAMP_DISCRETE_CEIL 130 +#define RAMP_DISCRETE_STEPS 7 // at Sofirn's request, use max (150) for the Simple UI ceiling -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#define SIMPLE_UI_CEIL 150 -#define SIMPLE_UI_STEPS 5 +#define SIMPLE_UI_FLOOR 1 +#define SIMPLE_UI_CEIL 150 +#define SIMPLE_UI_STEPS 5 // also at Sofirn's request, enable 2 click turbo (Anduril 1 style) #define DEFAULT_2C_STYLE 1 @@ -54,9 +62,21 @@ // stop panicking at ~75% power or ~3000 lm, this light has high thermal mass #define THERM_FASTER_LEVEL (RAMP_SIZE*9/10) // throttle back faster when high +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// blink numbers on the aux LEDs by default +#define DEFAULT_BLINK_CHANNEL CM_AUX + +// the default of 26 looks a bit rough, so increase it to make it smoother +#define CANDLE_AMPLITUDE 33 + // don't blink during the ramp; the button LED brightness is sufficient // to indicate which power channel(s) are being used #ifdef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_MIDDLE #endif +// enable factory reset on 13H without loosening tailcap (required) +#define USE_SOFT_FACTORY_RESET + -- cgit v1.2.3 From 1679fdfa41a27966149b8dd1d28f676e59aaeeb2 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 27 Oct 2023 03:47:01 -0600 Subject: converted gchart-fet1-t1616 to new API (is almost identical to a wurkkos-ts10) --- hwdef-gchart-fet1-t1616.h | 104 ++++++++++++++-------- spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h | 66 +++++++++----- 2 files changed, 112 insertions(+), 58 deletions(-) diff --git a/hwdef-gchart-fet1-t1616.h b/hwdef-gchart-fet1-t1616.h index 9625738..2d2b7a6 100644 --- a/hwdef-gchart-fet1-t1616.h +++ b/hwdef-gchart-fet1-t1616.h @@ -1,5 +1,5 @@ // gChart's custom FET+1 driver layout -// Copyright (C) 2020-2023 (FIXME) +// Copyright (C) 2020-2023 gchart, Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once @@ -11,60 +11,82 @@ * Read voltage from VCC pin, has diode with ~0.4v drop */ - -#define LAYOUT_DEFINED - -#ifdef ATTINY -#undef ATTINY -#endif #define ATTINY 1616 #include -#define PWM_CHANNELS 2 +// nearly all t1616-based FET+1 drivers work pretty much the same +// (this one has single-color aux like the TS10) +#define HWDEF_C_FILE hwdef-wurkkos-ts10.c -#ifndef SWITCH_PIN -#define SWITCH_PIN PIN2_bp -#define SWITCH_PORT VPORTB.IN -#define SWITCH_ISC_REG PORTB.PIN2CTRL -#define SWITCH_VECT PORTB_PORT_vect -#define SWITCH_INTFLG VPORTB.INTFLAGS -#endif +// allow using aux LEDs as extra channel modes +#include "chan-aux.h" +// channel modes: +// * 0. FET+7135 stacked +// * 1. aux LEDs +#define NUM_CHANNEL_MODES 2 +enum CHANNEL_MODES { + CM_MAIN = 0, + CM_AUX +}; -// 7135 channel -#ifndef PWM1_PIN -#define PWM1_PIN PB1 // -#define PWM1_LVL TCA0.SINGLE.CMP1 // CMP1 is the output compare register for PB1 -#endif +#define DEFAULT_CHANNEL_MODE CM_MAIN -// FET channel -#ifndef PWM2_PIN -#define PWM2_PIN PB0 // -#define PWM2_LVL TCA0.SINGLE.CMP0 // CMP0 is the output compare register for PB0 -#endif +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00000001 + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // 1x7135 ramp +#define PWM2_DATATYPE uint8_t // DD FET ramp + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 255 // highest value used in top half of ramp +// not necessary when double-buffered "BUF" registers are used +#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment + +// 1x7135 channel +#define CH1_PIN PB1 +#define CH1_PWM TCA0.SINGLE.CMP1BUF // CMP1 is the output compare register for PB1 + +// DD FET channel +#define CH2_PIN PB0 +#define CH2_PWM TCA0.SINGLE.CMP0BUF // CMP0 is the output compare register for PB0 + +// e-switch +#define SWITCH_PIN PIN2_bp +#define SWITCH_PORT VPORTB.IN +#define SWITCH_ISC_REG PORTB.PIN2CTRL +#define SWITCH_VECT PORTB_PORT_vect +#define SWITCH_INTFLG VPORTB.INTFLAGS // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR #define VOLTAGE_FUDGE_FACTOR 8 // 4 = add 0.20V #endif - // lighted button -#ifndef AUXLED_PIN -#define AUXLED_PIN PIN3_bp -#define AUXLED_PORT PORTB -#endif +#define AUXLED_PIN PIN3_bp +#define AUXLED_PORT PORTB -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead inline void hwdef_setup() { // set up the system clock to run at 10 MHz instead of the default 3.33 MHz - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, + CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); //VPORTA.DIR = 0b00000010; - VPORTB.DIR = PIN0_bm | PIN1_bm | PIN3_bm; + // Outputs + VPORTB.DIR = PIN0_bm // DD FET + | PIN1_bm // 7135 + | PIN3_bm; // Aux LED //VPORTC.DIR = 0b00000000; // enable pullups on the input pins to reduce power @@ -97,8 +119,16 @@ inline void hwdef_setup() { // For Fast (Single Slope) PWM use TCA_SINGLE_WGMODE_SINGLESLOPE_gc // For Phase Correct (Dual Slope) PWM use TCA_SINGLE_WGMODE_DSBOTTOM_gc // See the manual for other pins, clocks, configs, portmux, etc - TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm | TCA_SINGLE_WGMODE_DSBOTTOM_gc; - TCA0.SINGLE.PER = 255; - TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; + TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm + | TCA_SINGLE_CMP1EN_bm + | TCA_SINGLE_WGMODE_DSBOTTOM_gc; + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc + | TCA_SINGLE_ENABLE_bm; + + PWM_TOP = PWM_TOP_INIT; + } + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h b/spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h index eb17399..4082fca 100644 --- a/spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h +++ b/spaghetti-monster/anduril/cfg-gchart-fet1-t1616.h @@ -1,5 +1,5 @@ // gChart's custom FET+1 driver config options for Anduril -// Copyright (C) 2020-2023 (FIXME) +// Copyright (C) 2020-2023 gchart, Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once @@ -15,25 +15,49 @@ // lockout: blinking (3) #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) +#define RAMP_SIZE 150 + +// 7135 at 90/150 +// level_calc.py 5.7895 2 150 7135 0 0.1 125.25 FET 1 10 1200 --pwm dyn:61:4096:255:2.5 --clock 5:11:2.0 +// (with heavy manual tweaks up to ~15/150) +#define PWM1_LEVELS 1, 1, 2, 2, 3, 3, 4, 5, 6, 6, 8, 9, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 23, 24, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 35, 36, 37, 38, 40, 41, 43, 45, 47, 50, 53, 56, 60, 63, 67, 71, 75, 79, 84, 89, 94, 99,104,110,116,122,129,136,143,150,158,166,174,183,192,202,211,222,232,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 +#define PWM2_LEVELS 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 7, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 29, 31, 34, 37, 39, 42, 45, 48, 51, 54, 58, 61, 65, 68, 72, 76, 80, 84, 88, 93, 97,102,107,112,117,122,127,133,139,145,151,157,163,170,177,183,191,198,205,213,221,229,238,246,255 +#define PWM_TOPS 4095,2893,3917,2806,3252,2703,2684,2660,2640,2370,3000,2900,2630,2549,2246,2193,2030,1961,1889,1716,1642,1569,1497,1428,1290,1232,1176,1122,1070,976,932,890,849,779,745,685,656,605,579,536,514,476,457,424,407,379,364,340,327,314,302,291,280,276,266,262,257,253,253,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +#define MAX_1x7135 90 +#define MIN_THERM_STEPDOWN 60 +#define HALFSPEED_LEVEL 11 +#define QUARTERSPEED_LEVEL 5 +#define DEFAULT_LEVEL 50 + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 130 +// 10 30 50 70 [90] 110 130 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL 130 +#define RAMP_DISCRETE_STEPS 7 + +// 10 30 50 70 [90] 110 130 +#define SIMPLE_UI_FLOOR 10 +#define SIMPLE_UI_CEIL 130 +#define SIMPLE_UI_STEPS 7 + +// stop panicking at ~50% power +#define THERM_FASTER_LEVEL 130 // throttle back faster when high + +// show each channel while it scroll by in the menu +#define USE_CONFIG_COLORS + +// blink numbers on the aux LEDs by default +//#define DEFAULT_BLINK_CHANNEL CM_AUX + +// the default of 26 looks a bit rough, so increase it to make it smoother +#define CANDLE_AMPLITUDE 40 + +// don't blink mid-ramp +#ifdef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_MIDDLE +#endif + +// enable factory reset on 13H without loosening tailcap (required) +#define USE_SOFT_FACTORY_RESET -// Mostly borrowed from the D4 for now -#define RAMP_LENGTH 150 -#define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 -#define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,4,5,7,8,9,11,12,14,15,17,19,20,22,24,25,27,29,31,33,35,37,39,41,43,45,48,50,52,55,57,59,62,64,67,70,72,75,78,81,84,87,90,93,96,99,102,105,109,112,115,119,122,126,129,133,137,141,144,148,152,156,160,165,169,173,177,182,186,191,195,200,205,209,214,219,224,229,234,239,244,250,255 -#define MAX_1x7135 65 -#define HALFSPEED_LEVEL 14 -#define QUARTERSPEED_LEVEL 6 - -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 120 -// 10, 28, 46, [65], 83, 101, 120 -#define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 7 - -// stop panicking at ~30% power -#define THERM_FASTER_LEVEL 105 - -// enable 2 click turbo -#define DEFAULT_2C_STYLE 1 -- cgit v1.2.3 From 1ac0da62f1b582a2b62d07c164acc983a5c0b004 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Fri, 27 Oct 2023 05:48:14 -0600 Subject: converted noctigon-m44 to use PWM+DSM instead of PWM+PFM (dynamic PWM) (this gives better, smoother low modes and reduced flicker) --- hwdef-emisar-d4k-3ch.c | 1 + hwdef-emisar-d4k-3ch.h | 2 - hwdef-noctigon-m44.c | 190 ++++++++++++++++--------- hwdef-noctigon-m44.h | 43 +++--- spaghetti-monster/anduril/cfg-emisar-d4k-3ch.h | 4 +- spaghetti-monster/anduril/cfg-noctigon-m44.h | 50 ++++--- 6 files changed, 185 insertions(+), 105 deletions(-) diff --git a/hwdef-emisar-d4k-3ch.c b/hwdef-emisar-d4k-3ch.c index 58e9b35..ba6643d 100644 --- a/hwdef-emisar-d4k-3ch.c +++ b/hwdef-emisar-d4k-3ch.c @@ -262,6 +262,7 @@ void set_level_auto3(uint8_t level) { } ///// "gradual tick" functions for smooth thermal regulation ///// +// (and other smooth adjustments) bool gradual_adjust(PWM_DATATYPE main2, PWM_DATATYPE led3, PWM_DATATYPE led4) { // adjust multiple times based on current brightness diff --git a/hwdef-emisar-d4k-3ch.h b/hwdef-emisar-d4k-3ch.h index 59e6f01..581f51c 100644 --- a/hwdef-emisar-d4k-3ch.h +++ b/hwdef-emisar-d4k-3ch.h @@ -27,8 +27,6 @@ * 20 PA7 e-switch (PCINT7) * ADC12 thermal sensor * - * All 3 channels share a single Opamp enable pin, - * but have individual PWM controls. * PWM speed + resolution is dynamic on 2 channels, * and 8-bit 16 kHz on 1 channel. * diff --git a/hwdef-noctigon-m44.c b/hwdef-noctigon-m44.c index 776cb82..0b7f027 100644 --- a/hwdef-noctigon-m44.c +++ b/hwdef-noctigon-m44.c @@ -1,7 +1,6 @@ // hwdef for Noctigon M44 2-channel light // Copyright (C) 2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later - #pragma once #include "chan-rgbaux.c" @@ -52,20 +51,39 @@ Channel channels[] = { }; +void set_level_zero() { + // disable timer 1 overflow interrupt + // (helps improve button press handling from Off state) + TIMSK &= ~(1 << TOIE1); + + // turn off all LEDs + ch1_dsm_lvl = 0; + ch2_dsm_lvl = 0; + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp + CH2_ENABLE_PORT &= ~(1 << CH2_ENABLE_PIN); // disable opamp +} + + +// wrap setting the dsm vars, to get a faster response +// (just setting *_dsm_lvl doesn't work well for strobes) // set new values for both channels, // handling any possible combination // and any before/after state -void set_pwms(uint16_t ch1_pwm, uint16_t ch2_pwm, uint16_t top, - uint8_t ch1_on, uint8_t ch2_on) { +void set_hw_levels(PWM_DATATYPE ch1, PWM_DATATYPE ch2, + bool ch1_on, bool ch2_on) { bool was_on = (CH1_PWM>0) || (CH2_PWM>0) || ( CH1_ENABLE_PORT & (1 << CH1_ENABLE_PIN) ) || ( CH2_ENABLE_PORT & (1 << CH2_ENABLE_PIN) ); - bool now_on = (ch1_pwm>0) || (ch2_pwm>0) || ch1_on || ch2_on; + //bool now_on = (ch1>0) || (ch2>0) || ch1_on || ch2_on; + #if 0 // not needed any more, after switching to PWM+DSM // phase-correct PWM at zero (for flicker-free moon), // fast PWM otherwise - if (ch1_pwm || ch2_pwm) + if (ch1 || ch2) TCCR1B = (0<> 7; + CH2_PWM = ch2_pwm = ch2 >> 7; + + #if 0 // not needed any more, after switching to PWM+DSM // manual phase sync when changing level while already on if (was_on && now_on) while(PWM_CNT > (top - 32)) {} PWM_TOP = top; + #endif + + // enable timer 1 overflow interrupt so DSM can work + TIMSK |= (1 << TOIE1); // reset phase when turning on or off //if ((! was_on) | (! now_on)) PWM_CNT = 0; if (! was_on) PWM_CNT = 0; + } -void set_level_zero() { - CH1_PWM = 0; - CH2_PWM = 0; - PWM_TOP = PWM_TOP_INIT; - PWM_CNT = 0; - CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable opamp - CH2_ENABLE_PORT &= ~(1 << CH2_ENABLE_PIN); // disable opamp +// delta-sigma modulation of PWM outputs +// happens on each Timer0 overflow (every 512 cpu clock cycles) +// uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD) +ISR(TIMER1_OVF_vect) { + // set new hardware values first, + // for best timing (reduce effect of interrupt jitter) + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; + + // calculate next values, now that timing matters less + + // accumulate error + ch1_dsm += (ch1_dsm_lvl & 0x007f); + // next PWM = base PWM value + carry bit + ch1_pwm = (ch1_dsm_lvl >> 7) + (ch1_dsm > 0x7f); + // clear carry bit + ch1_dsm &= 0x7f; + + // repeat for other channels + + ch2_dsm += (ch2_dsm_lvl & 0x007f); + ch2_pwm = (ch2_dsm_lvl >> 7) + (ch2_dsm > 0x7f); + ch2_dsm &= 0x7f; } + void set_level_ch1(uint8_t level) { - uint16_t pwm = PWM_GET(pwm1_levels, level); - uint16_t top = PWM_GET(pwm_tops, level); - set_pwms(pwm, 0, top, 1, 0); + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, level); + set_hw_levels(pwm, 0, + 1, 0); } void set_level_ch2(uint8_t level) { - uint16_t pwm = PWM_GET(pwm1_levels, level); - uint16_t top = PWM_GET(pwm_tops, level); - set_pwms(0, pwm, top, 0, 1); + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, level); + set_hw_levels(0, pwm, + 0, 1); } void set_level_both(uint8_t level) { - uint16_t pwm = PWM_GET(pwm1_levels, level); - uint16_t top = PWM_GET(pwm_tops, level); - set_pwms(pwm, pwm, top, 1, 1); + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, level); + set_hw_levels(pwm, pwm, + 1, 1); } -void set_level_blend(uint8_t level) { - PWM_DATATYPE ch1_pwm, ch2_pwm; +void blend_helper(PWM_DATATYPE *warm, PWM_DATATYPE *cool, uint8_t level) { PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); - PWM_DATATYPE top = PWM_GET(pwm_tops, level); - uint8_t blend = cfg.channel_mode_args[channel_mode]; + uint8_t blend; + if (channel_mode == CM_AUTO) { + blend = 255 * (uint16_t)level / RAMP_SIZE; + if (cfg.channel_mode_args[channel_mode] & 0b01000000) + blend = 255 - blend; + } else { + blend = cfg.channel_mode_args[channel_mode]; + } - calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); + calc_2ch_blend(warm, cool, brightness, DSM_TOP, blend); +} +void set_level_blend(uint8_t level) { + PWM_DATATYPE warm, cool; + uint8_t blend = cfg.channel_mode_args[channel_mode]; + blend_helper(&warm, &cool, level); // don't turn off either emitter entirely while using middle blends - set_pwms(ch1_pwm, ch2_pwm, top, - blend < 255, blend > 0); + set_hw_levels(warm, cool, + blend < 255, blend > 0); } void set_level_auto(uint8_t level) { - PWM_DATATYPE ch1_pwm, ch2_pwm; - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); - PWM_DATATYPE top = PWM_GET(pwm_tops, level); - uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; - if (cfg.channel_mode_args[channel_mode] & 0b01000000) - blend = 255 - blend; - - calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); - + PWM_DATATYPE warm, cool; + blend_helper(&warm, &cool, level); // don't turn off either emitter entirely // (it blinks pretty bright when the regulator turns on mid-ramp) - set_pwms(ch1_pwm, ch2_pwm, top, 1, 1); + set_hw_levels(warm, cool, + 1, 1); } +///// "gradual tick" functions for smooth thermal regulation ///// +// (and other smooth adjustments) ///// bump each channel toward a target value ///// -bool gradual_adjust(uint16_t ch1_pwm, uint16_t ch2_pwm) { - GRADUAL_ADJUST_SIMPLE(ch1_pwm, CH1_PWM); - GRADUAL_ADJUST_SIMPLE(ch2_pwm, CH2_PWM); +bool gradual_adjust(PWM_DATATYPE ch1, PWM_DATATYPE ch2) { + // adjust multiple times based on current brightness + // (so it adjusts faster/coarser when bright, slower/finer when dim) + + // higher shift = slower/finer adjustments + const uint8_t shift = 9; // ((255 << 7) >> 9) = 63 max + uint8_t steps; + + steps = ch1_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(ch1, ch1_dsm_lvl); + + steps = ch2_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(ch2, ch2_dsm_lvl); - // check for completion - if ((ch1_pwm == CH1_PWM) - && (ch2_pwm == CH2_PWM)) { + if ((ch1 == ch1_dsm_lvl) + && (ch2 == ch2_dsm_lvl )) { return true; // done } return false; // not done yet } bool gradual_tick_ch1(uint8_t gt) { - uint16_t pwm = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt); return gradual_adjust(pwm, 0); } bool gradual_tick_ch2(uint8_t gt) { - uint16_t pwm = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt); return gradual_adjust(0, pwm); } bool gradual_tick_both(uint8_t gt) { - uint16_t pwm = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE pwm = PWM_GET(pwm1_levels, gt); return gradual_adjust(pwm, pwm); } bool gradual_tick_blend(uint8_t gt) { - PWM_DATATYPE ch1_pwm, ch2_pwm; - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); - PWM_DATATYPE top = PWM_GET(pwm_tops, gt); - uint8_t blend = cfg.channel_mode_args[channel_mode]; - - calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); - - return gradual_adjust(ch1_pwm, ch2_pwm); + PWM_DATATYPE warm, cool; + blend_helper(&warm, &cool, gt); + return gradual_adjust(warm, cool); } bool gradual_tick_auto(uint8_t gt) { - PWM_DATATYPE ch1_pwm, ch2_pwm; - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); - PWM_DATATYPE top = PWM_GET(pwm_tops, gt); - uint8_t blend = 255 * (uint16_t)gt / RAMP_SIZE; - if (cfg.channel_mode_args[channel_mode] & 0b01000000) - blend = 255 - blend; - - calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, top, blend); - - return gradual_adjust(ch1_pwm, ch2_pwm); + PWM_DATATYPE warm, cool; + blend_helper(&warm, &cool, gt); + return gradual_adjust(warm, cool); } diff --git a/hwdef-noctigon-m44.h b/hwdef-noctigon-m44.h index d02d8dd..2a9198a 100644 --- a/hwdef-noctigon-m44.h +++ b/hwdef-noctigon-m44.h @@ -63,34 +63,41 @@ enum channel_modes_e { #define USE_CALC_2CH_BLEND -#define PWM_CHANNELS 1 // old, remove this +#define PWM_CHANNELS 1 // old, remove this -#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz +#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz #define PWM_GET PWM_GET16 #define PWM_DATATYPE uint16_t #define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 -#define PWM1_DATATYPE uint16_t // regular ramp table +#define PWM1_DATATYPE uint16_t // 15-bit PWM+DSM ramp //#define PWM2_DATATYPE uint16_t // max "200% power" ramp table -//#define PWM3_DATATYPE uint16_t // PWM_TOPs for 2nd ramp table // PWM parameters of both channels are tied together because they share a counter +// dynamic PWM #define PWM_TOP ICR1 // holds the TOP value for for variable-resolution PWM -#define PWM_TOP_INIT 511 -#define PWM_CNT TCNT1 // for dynamic PWM, reset phase - -#define CH1_PIN PB3 // pin 16, Opamp reference -#define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 +#define PWM_TOP_INIT 255 +#define PWM_CNT TCNT1 // for checking / resetting phase +// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) +#define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry + +// 1st channel (8 LEDs) +uint16_t ch1_dsm_lvl; +uint8_t ch1_pwm, ch1_dsm; +#define CH1_PIN PB3 // pin 16, Opamp reference +#define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 #define CH1_ENABLE_PIN PB0 // pin 19, Opamp power #define CH1_ENABLE_PORT PORTB // control port for PB0 -#define CH2_PIN PA6 // pin 1, 2nd LED Opamp reference -#define CH2_PWM OCR1B // OCR1B is the output compare register for PA6 +// 2nd channel (8 LEDs) +uint16_t ch2_dsm_lvl; +uint8_t ch2_pwm, ch2_dsm; +#define CH2_PIN PA6 // pin 1, 2nd LED Opamp reference +#define CH2_PWM OCR1B // OCR1B is the output compare register for PA6 #define CH2_ENABLE_PIN PA0 // pin 7, Opamp power #define CH2_ENABLE_PORT PORTA // control port for PA0 // e-switch -#ifndef SWITCH_PIN #define SWITCH_PIN PA7 // pin 20 #define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt #define SWITCH_PCIE PCIE0 // PCIE1 is for PCINT[7:0] @@ -98,7 +105,6 @@ enum channel_modes_e { #define SWITCH_PORT PINA // PINA or PINB or PINC #define SWITCH_PUE PUEA // pullup group A #define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] -#endif #define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened #define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 @@ -161,7 +167,7 @@ inline void hwdef_setup() { // configure PWM // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter // pre-scale for timer: N = 1 - // Linear opamp PWM for both main and 2nd LEDs (10-bit) + // PWM for both channels // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) // WGM1[3:0]: 1,1,1,0: PWM, Fast, adjustable (DS table 12-5) // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) @@ -172,17 +178,22 @@ inline void hwdef_setup() { | (1<0) || (CH2_PWM>0); + + // set delta-sigma soft levels + ch1_dsm_lvl = ch1; + ch2_dsm_lvl = ch2; + + // set hardware PWM levels and init dsm loop + CH1_PWM = ch1_pwm = ch1 >> 7; + CH2_PWM = ch2_pwm = ch2 >> 7; + + // enable timer overflow interrupt so DSM can work + DSM_INTCTRL |= DSM_OVF_bm; + + // reset phase when turning on + if (! was_on) PWM_CNT = 0; + +} + +// delta-sigma modulation of PWM outputs +// happens on each Timer overflow (every 512 cpu clock cycles) +// uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD) +ISR(DSM_vect) { + // set new hardware values first, + // for best timing (reduce effect of interrupt jitter) CH1_PWM = ch1_pwm; CH2_PWM = ch2_pwm; + + // calculate next values, now that timing matters less + + // accumulate error + ch1_dsm += (ch1_dsm_lvl & 0x007f); + // next PWM = base PWM value + carry bit + ch1_pwm = (ch1_dsm_lvl >> 7) + (ch1_dsm > 0x7f); + // clear carry bit + ch1_dsm &= 0x7f; + + // repeat for other channels + + ch2_dsm += (ch2_dsm_lvl & 0x007f); + ch2_pwm = (ch2_dsm_lvl >> 7) + (ch2_dsm > 0x7f); + ch2_dsm &= 0x7f; } + void set_level_ch1(uint8_t level) { - set_pwms(PWM_GET(pwm1_levels, level), 0); + set_hw_levels(PWM_GET(pwm1_levels, level), 0); } void set_level_ch2(uint8_t level) { - set_pwms(0, PWM_GET(pwm1_levels, level)); + set_hw_levels(0, PWM_GET(pwm1_levels, level)); } void set_level_both(uint8_t level) { PWM_DATATYPE pwm = PWM_GET(pwm1_levels, level); - set_pwms(pwm, pwm); + set_hw_levels(pwm, pwm); } -void set_level_blend(uint8_t level) { - PWM_DATATYPE ch1_pwm, ch2_pwm; +void blend_helper(PWM_DATATYPE *warm, PWM_DATATYPE *cool, uint8_t level) { PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); - uint8_t blend = cfg.channel_mode_args[channel_mode]; + uint8_t blend; + if (channel_mode == CM_AUTO) { + blend = 255 * (uint16_t)level / RAMP_SIZE; + if (cfg.channel_mode_args[channel_mode] & 0b01000000) + blend = 255 - blend; + } else { + blend = cfg.channel_mode_args[channel_mode]; + } - calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend); + calc_2ch_blend(warm, cool, brightness, DSM_TOP, blend); +} - set_pwms(ch1_pwm, ch2_pwm); +void set_level_blend(uint8_t level) { + PWM_DATATYPE warm, cool; + blend_helper(&warm, &cool, level); + set_hw_levels(warm, cool); } void set_level_auto(uint8_t level) { - PWM_DATATYPE ch1_pwm, ch2_pwm; - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, level); - uint8_t blend = 255 * (uint16_t)level / RAMP_SIZE; - if (cfg.channel_mode_args[channel_mode] & 0b01000000) - blend = 255 - blend; - - calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend); - - set_pwms(ch1_pwm, ch2_pwm); + PWM_DATATYPE warm, cool; + blend_helper(&warm, &cool, level); + set_hw_levels(warm, cool); } +///// "gradual tick" functions for smooth thermal regulation ///// +// (and other smooth adjustments) ///// bump each channel toward a target value ///// -bool gradual_adjust(uint16_t ch1_pwm, uint16_t ch2_pwm) { - GRADUAL_ADJUST_SIMPLE(ch1_pwm, CH1_PWM); - GRADUAL_ADJUST_SIMPLE(ch2_pwm, CH2_PWM); +bool gradual_adjust(PWM_DATATYPE ch1, PWM_DATATYPE ch2) { + // adjust multiple times based on current brightness + // (so it adjusts faster/coarser when bright, slower/finer when dim) + + // higher shift = slower/finer adjustments + const uint8_t shift = 9; // ((255 << 7) >> 9) = 63 max + uint8_t steps; - // check for completion - if ((ch1_pwm == CH1_PWM) - && (ch2_pwm == CH2_PWM)) { + steps = ch1_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(ch1, ch1_dsm_lvl); + + steps = ch2_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(ch2, ch2_dsm_lvl); + + if ((ch1 == ch1_dsm_lvl) + && (ch2 == ch2_dsm_lvl )) { return true; // done } return false; // not done yet @@ -126,24 +192,15 @@ bool gradual_tick_both(uint8_t gt) { } bool gradual_tick_blend(uint8_t gt) { - PWM_DATATYPE ch1_pwm, ch2_pwm; - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); - uint8_t blend = cfg.channel_mode_args[channel_mode]; - - calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend); - - return gradual_adjust(ch1_pwm, ch2_pwm); + PWM_DATATYPE warm, cool; + blend_helper(&warm, &cool, gt); + return gradual_adjust(warm, cool); } bool gradual_tick_auto(uint8_t gt) { - PWM_DATATYPE ch1_pwm, ch2_pwm; - PWM_DATATYPE brightness = PWM_GET(pwm1_levels, gt); - uint8_t blend = 255 * (uint16_t)gt / RAMP_SIZE; - if (cfg.channel_mode_args[channel_mode] & 0b01000000) - blend = 255 - blend; - - calc_2ch_blend(&ch1_pwm, &ch2_pwm, brightness, PWM_TOP_INIT, blend); - - return gradual_adjust(ch1_pwm, ch2_pwm); + PWM_DATATYPE warm, cool; + blend_helper(&warm, &cool, gt); + return gradual_adjust(warm, cool); } + diff --git a/hwdef-blf-lt1-t1616.h b/hwdef-blf-lt1-t1616.h index 4a411d4..cc6d065 100644 --- a/hwdef-blf-lt1-t1616.h +++ b/hwdef-blf-lt1-t1616.h @@ -46,40 +46,49 @@ enum channel_modes_e { #define USE_CALC_2CH_BLEND -#define PWM_CHANNELS 1 // old, remove this +#define PWM_CHANNELS 1 // old, remove this -#define PWM_BITS 8 // - -#define PWM_GET PWM_GET8 -#define PWM_DATATYPE uint8_t -#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 -#define PWM1_DATATYPE uint8_t // +#define PWM_BITS 16 // 0 to 32640 (0 to 255 PWM + 0 to 127 DSM) at constant kHz +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // 15-bit PWM+DSM ramp // PWM parameters of both channels are tied together because they share a counter -#define PWM_TOP_INIT 255 // highest value used in the top half of the ramp -#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM -#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment -// TODO: implement DSM +// dynamic PWM +#define PWM_TOP TCA0.SINGLE.PERBUF // holds the TOP value for for variable-resolution PWM +#define PWM_TOP_INIT 255 +#define PWM_CNT TCA0.SINGLE.CNT // for resetting phase after each TOP adjustment +// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) #define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry +// timer interrupt for DSM +#define DSM_vect TCA0_OVF_vect +#define DSM_INTCTRL TCA0.SINGLE.INTCTRL +#define DSM_OVF_bm TCA_SINGLE_OVF_bm + // warm LEDs +uint16_t ch1_dsm_lvl; +uint8_t ch1_pwm, ch1_dsm; #define CH1_PIN PB1 -#define CH1_PWM TCA0.SINGLE.CMP1 // CMP1 is the output compare register for PB1 +#define CH1_PWM TCA0.SINGLE.CMP1 // CMP1 is the output compare register for PB1 // cold LEDs -#define CH2_PIN PB0 -#define CH2_PWM TCA0.SINGLE.CMP0 // CMP0 is the output compare register for PB0 +uint16_t ch2_dsm_lvl; +uint8_t ch2_pwm, ch2_dsm; +#define CH2_PIN PB0 +#define CH2_PWM TCA0.SINGLE.CMP0 // CMP0 is the output compare register for PB0 // lighted button #define AUXLED_PIN PIN5_bp #define AUXLED_PORT PORTB // e-switch -#define SWITCH_PIN PIN5_bp -#define SWITCH_PORT VPORTA.IN -#define SWITCH_ISC_REG PORTA.PIN2CTRL -#define SWITCH_VECT PORTA_PORT_vect -#define SWITCH_INTFLG VPORTA.INTFLAGS +#define SWITCH_PIN PIN5_bp +#define SWITCH_PORT VPORTA.IN +#define SWITCH_ISC_REG PORTA.PIN2CTRL +#define SWITCH_VECT PORTA_PORT_vect +#define SWITCH_INTFLG VPORTA.INTFLAGS // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR @@ -89,11 +98,12 @@ enum channel_modes_e { inline void hwdef_setup() { - // set up the system clock to run at 5 MHz instead of the default 3.33 MHz - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm ); + // set up the system clock to run at 10 MHz instead of the default 3.33 MHz + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, + CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); //VPORTA.DIR = ...; - // Outputs: + // Outputs VPORTB.DIR = PIN0_bm // cool white | PIN1_bm // warm white | PIN5_bm; // aux LED @@ -130,10 +140,16 @@ inline void hwdef_setup() { // TODO: add references to MCU documentation TCA0.SINGLE.CTRLB = TCA_SINGLE_CMP0EN_bm | TCA_SINGLE_CMP1EN_bm - | TCA_SINGLE_WGMODE_SINGLESLOPE_gc; - PWM_TOP = PWM_TOP_INIT; + | TCA_SINGLE_WGMODE_DSBOTTOM_gc; TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1_gc | TCA_SINGLE_ENABLE_bm; + + PWM_TOP = PWM_TOP_INIT; + + // set up interrupt for delta-sigma modulation + // (moved to hwdef.c functions so it can be enabled/disabled based on ramp level) + //DSM_INTCTRL |= DSM_OVF_bm; // interrupt once for each timer cycle + } diff --git a/hwdef-noctigon-m44.c b/hwdef-noctigon-m44.c index 0b7f027..395a7a2 100644 --- a/hwdef-noctigon-m44.c +++ b/hwdef-noctigon-m44.c @@ -52,9 +52,9 @@ Channel channels[] = { void set_level_zero() { - // disable timer 1 overflow interrupt + // disable timer overflow interrupt // (helps improve button press handling from Off state) - TIMSK &= ~(1 << TOIE1); + DSM_INTCTRL &= ~DSM_OVF_bm; // turn off all LEDs ch1_dsm_lvl = 0; @@ -120,19 +120,19 @@ void set_hw_levels(PWM_DATATYPE ch1, PWM_DATATYPE ch2, PWM_TOP = top; #endif - // enable timer 1 overflow interrupt so DSM can work - TIMSK |= (1 << TOIE1); + // enable timer overflow interrupt so DSM can work + DSM_INTCTRL |= DSM_OVF_bm; - // reset phase when turning on or off + // reset phase when turning on //if ((! was_on) | (! now_on)) PWM_CNT = 0; if (! was_on) PWM_CNT = 0; } // delta-sigma modulation of PWM outputs -// happens on each Timer0 overflow (every 512 cpu clock cycles) +// happens on each Timer overflow (every 512 cpu clock cycles) // uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD) -ISR(TIMER1_OVF_vect) { +ISR(DSM_vect) { // set new hardware values first, // for best timing (reduce effect of interrupt jitter) CH1_PWM = ch1_pwm; diff --git a/hwdef-noctigon-m44.h b/hwdef-noctigon-m44.h index 2a9198a..a41ea79 100644 --- a/hwdef-noctigon-m44.h +++ b/hwdef-noctigon-m44.h @@ -39,8 +39,8 @@ // channel modes: // * 0. channel 1 only // * 1. channel 2 only -// * 2. both channels, tied together -// * 3. both channels, manual blend +// * 2. both channels, tied together, max "200%" power +// * 3. both channels, manual blend, max "100%" power // * 4? both channels, manual blend, max 200% power // * 4. both channels, auto blend, reversible #define NUM_CHANNEL_MODES (5 + NUM_RGB_AUX_CHANNEL_MODES) @@ -65,7 +65,7 @@ enum channel_modes_e { #define PWM_CHANNELS 1 // old, remove this -#define PWM_BITS 16 // 0 to 16383 at variable Hz, not 0 to 255 at 16 kHz +#define PWM_BITS 16 // 0 to 32640 (0 to 255 PWM + 0 to 127 DSM) at constant kHz #define PWM_GET PWM_GET16 #define PWM_DATATYPE uint16_t #define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 @@ -80,6 +80,11 @@ enum channel_modes_e { // (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) #define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry +// timer interrupt for DSM +#define DSM_vect TIMER1_OVF_vect +#define DSM_INTCTRL TIMSK +#define DSM_OVF_bm (1< + +#define HWDEF_C_FILE hwdef-fw3a.c + +// channel modes +// * 0. FET+N+1 stacked +#define NUM_CHANNEL_MODES 1 +enum CHANNEL_MODES { + CM_MAIN = 0, +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00000001 + + +#define PWM_CHANNELS 3 // old, remove this + +#define PWM_BITS 8 // attiny85 only supports up to 8 bits +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define PWM_DATATYPE2 uint16_t +#define PWM1_DATATYPE uint8_t // 1x7135 ramp +#define PWM2_DATATYPE uint8_t // 7x7135 ramp +#define PWM3_DATATYPE uint8_t // DD FET ramp + +#define PWM_TOP_INIT 255 // highest value used in top half of ramp + +// 1x7135 channel +#define CH1_PIN PB0 // pin 5, 1x7135 PWM +#define CH1_PWM OCR0A // OCR0A is the output compare register for PB0 + +// 7x7135 channel +#define CH2_PIN PB1 // pin 6, 7x7135 PWM +#define CH2_PWM OCR0B // OCR0B is the output compare register for PB1 + +// DD FET channel +#define CH3_PIN PB4 // pin 3, FET PWM +#define CH3_PWM OCR1B // OCR1B is the output compare register for PB4 + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt +#endif + +#ifndef AUXLED_PIN +#define AUXLED_PIN PB2 // pin 7 +#endif +#define ADC_PRSCL 0x07 // clk/128 + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 5 // add 0.25V +#endif + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + + +inline void hwdef_setup() { + + // configure PWM channels + DDRB = (1 << CH1_PIN) + | (1 << CH2_PIN) + | (1 << CH3_PIN); + + // configure PWM channels + TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) + TCCR0A = PHASE; + + // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = PWM_TOP_INIT; // Set ceiling value to maximum + + // configure e-switch + PORTB = (1 << SWITCH_PIN); // e-switch is the only input + PCMSK = (1 << SWITCH_PIN); // pin change interrupt uses this pin + +} + + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/cfg-emisar-d18.h b/spaghetti-monster/anduril/cfg-emisar-d18.h index d59199c..3e5d3ae 100644 --- a/spaghetti-monster/anduril/cfg-emisar-d18.h +++ b/spaghetti-monster/anduril/cfg-emisar-d18.h @@ -4,25 +4,28 @@ #pragma once #define MODEL_NUMBER "0141" -#include "hwdef-Emisar_D18.h" +#include "hwdef-emisar-d18.h" #include "hank-cfg.h" +#define RAMP_SIZE 150 + // level_calc.py seventh 3 150 7135 1 1.4 117.99 7135 6 1 1706.86 FET 3 10 13000 // (designed to make 1x hit at level 50, and Nx hit at level 100) -#define RAMP_LENGTH 150 #define PWM1_LEVELS 1,1,2,2,3,4,4,5,6,7,8,9,10,11,15,16,18,20,22,24,26,28,30,33,36,39,43,47,51,56,61,66,72,78,85,92,99,107,116,125,135,145,156,168,180,194,208,222,238,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,10,11,13,14,16,18,19,21,23,26,28,30,33,35,38,41,44,47,51,54,58,62,66,70,75,79,84,90,95,101,106,112,119,126,133,140,147,155,164,172,181,190,200,210,221,232,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,7,9,11,13,15,18,20,23,25,28,31,34,37,40,44,47,51,54,58,62,66,70,75,79,84,89,94,99,104,110,115,121,127,134,140,147,154,161,168,176,183,191,200,208,217,226,235,245,255 -#define MAX_1x7135 50 -#define MAX_Nx7135 100 -#define HALFSPEED_LEVEL 15 -#define QUARTERSPEED_LEVEL 6 + +#define DEFAULT_LEVEL 50 +#define MAX_1x7135 50 +#define MAX_Nx7135 100 +#define HALFSPEED_LEVEL 15 +#define QUARTERSPEED_LEVEL 6 // start at ~2000 lm after battery change, not ~150 lm (at Emisar's request) //#define DEFAULT_LEVEL MAX_Nx7135 // go up to ~4000 lm -#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_FLOOR 1 #define RAMP_SMOOTH_CEIL 117 // 20 36 52 68 84 [100] 117 #define RAMP_DISCRETE_FLOOR 20 @@ -30,17 +33,29 @@ #define RAMP_DISCRETE_STEPS 7 // safe limit ~20% power / max regulated -#define SIMPLE_UI_FLOOR 20 -#define SIMPLE_UI_CEIL MAX_Nx7135 -#define SIMPLE_UI_STEPS 5 +// 20 40 60 80 100 +#define SIMPLE_UI_FLOOR 20 +#define SIMPLE_UI_CEIL MAX_Nx7135 +#define SIMPLE_UI_STEPS 5 // only blink at max regulated level and ceiling -#define BLINK_AT_RAMP_MIDDLE -#define BLINK_AT_RAMP_MIDDLE_1 MAX_Nx7135 +//#define BLINK_AT_RAMP_MIDDLE +//#define BLINK_AT_RAMP_MIDDLE_1 MAX_Nx7135 #define BLINK_AT_RAMP_CEIL +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif // stop panicking at about ~40% power or ~5000 lm #define THERM_FASTER_LEVEL 125 +// enable extra features +#define USE_SMOOTH_STEPS + +// for compatibility with other models +#define USE_SOFT_FACTORY_RESET + // too big, turn off extra features #undef USE_TACTICAL_MODE +#undef USE_SOS_MODE + diff --git a/spaghetti-monster/anduril/cfg-fw3a.h b/spaghetti-monster/anduril/cfg-fw3a.h index 7a8f417..1802f9b 100644 --- a/spaghetti-monster/anduril/cfg-fw3a.h +++ b/spaghetti-monster/anduril/cfg-fw3a.h @@ -15,11 +15,11 @@ #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,6,8,10,13,15,17,19,22,24,26,29,31,34,37,39,42,45,48,51,54,57,60,64,67,70,74,77,81,85,88,92,96,100,104,108,112,116,121,125,130,134,139,143,148,153,158,163,168,173,179,184,189,195,201,206,212,218,224,230,236,243,249,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,19,31,43,55,67,79,91,104,117,130,143,157,170,184,198,212,226,240,255 -#define DEFAULT_LEVEL 50 -#define MAX_1x7135 65 -#define MAX_Nx7135 130 -#define HALFSPEED_LEVEL 15 -#define QUARTERSPEED_LEVEL 6 +#define DEFAULT_LEVEL 50 +#define MAX_1x7135 65 +#define MAX_Nx7135 130 +#define HALFSPEED_LEVEL 15 +#define QUARTERSPEED_LEVEL 6 #define RAMP_SMOOTH_FLOOR 1 #define RAMP_SMOOTH_CEIL MAX_Nx7135 -- cgit v1.2.3 From fa9313280f6f326036f1798cae94924bb60fe1d8 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 28 Oct 2023 08:13:52 -0600 Subject: converted ff-rot66 to new API (it's mostly the same as FW3A, but has an aux LED so there's less room for other stuff) --- hwdef-FF_ROT66.h | 24 ----------------- hwdef-ff-rot66.h | 24 +++++++++++++++++ spaghetti-monster/anduril/cfg-ff-rot66.h | 43 ++++++++++++++++-------------- spaghetti-monster/anduril/cfg-ff-rot66g2.h | 3 +++ spaghetti-monster/anduril/cfg-fw3a.h | 10 +++---- 5 files changed, 55 insertions(+), 49 deletions(-) delete mode 100644 hwdef-FF_ROT66.h create mode 100644 hwdef-ff-rot66.h diff --git a/hwdef-FF_ROT66.h b/hwdef-FF_ROT66.h deleted file mode 100644 index e84b565..0000000 --- a/hwdef-FF_ROT66.h +++ /dev/null @@ -1,24 +0,0 @@ -// Fireflies ROT66 driver layout -// Copyright (C) 2018-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -// same as a FW3A, basically, except ... - -// ... except the ROT66 has a lighted button -#ifndef AUXLED_PIN -#define AUXLED_PIN PB2 // pin 7 -#endif - -// ... and slightly different calibration -#ifndef VOLTAGE_FUDGE_FACTOR -#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V -#endif - -#include "hwdef-FW3A.h" - -// ... and no optic nerve -#ifdef VISION_PIN -#undef VISION_PIN -#endif - diff --git a/hwdef-ff-rot66.h b/hwdef-ff-rot66.h new file mode 100644 index 0000000..3fea9f1 --- /dev/null +++ b/hwdef-ff-rot66.h @@ -0,0 +1,24 @@ +// Fireflies ROT66 driver layout +// Copyright (C) 2018-2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +// same as a FW3A, basically, except ... + +// ... except the ROT66 has a lighted button +#ifndef AUXLED_PIN +#define AUXLED_PIN PB2 // pin 7 +#endif + +// ... and slightly different calibration +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + +#include "hwdef-fw3a.h" + +// ... and no optic nerve +#ifdef VISION_PIN +#undef VISION_PIN +#endif + diff --git a/spaghetti-monster/anduril/cfg-ff-rot66.h b/spaghetti-monster/anduril/cfg-ff-rot66.h index f357956..752ddbb 100644 --- a/spaghetti-monster/anduril/cfg-ff-rot66.h +++ b/spaghetti-monster/anduril/cfg-ff-rot66.h @@ -4,7 +4,7 @@ #pragma once #define MODEL_NUMBER "0411" -#include "hwdef-FF_ROT66.h" +#include "hwdef-ff-rot66.h" // the button lights up #define USE_INDICATOR_LED @@ -15,28 +15,30 @@ // lockout: blinking (3) #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 2) +#define RAMP_SIZE 150 // driver is a FET+N+1, // where N=6 for the 219b version, // or N=13 for the XP-L HI version (this version) // calculated to get transition points at level 65 and 125 -#define RAMP_LENGTH 150 // first 65 steps copied from FW3A #define PWM1_LEVELS 1,1,2,2,3,3,4,4,5,6,7,8,9,10,12,13,14,15,17,19,20,22,24,26,29,31,34,36,39,42,45,48,51,55,59,62,66,70,75,79,84,89,93,99,104,110,115,121,127,134,140,147,154,161,168,176,184,192,200,209,217,226,236,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 // remaining steps from this command: // level_calc.py ninth 3 150 7135 1 1.4 110.1 7135 15 1 1644.16 FET 1 10 4500 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,17,18,19,20,21,22,23,25,26,27,29,30,32,34,35,37,39,41,43,46,48,50,53,55,58,61,64,67,70,73,77,81,84,88,92,97,101,106,110,115,120,126,131,137,143,149,156,162,169,177,184,192,200,208,217,226,235,245,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM3_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,13,21,28,35,43,51,60,68,77,87,96,106,117,127,138,150,161,173,186,199,212,226,240,255 -#define MAX_1x7135 65 -#define MAX_Nx7135 125 -#define HALFSPEED_LEVEL 14 -#define QUARTERSPEED_LEVEL 8 +#define MAX_1x7135 65 +#define MAX_Nx7135 125 +#define HALFSPEED_LEVEL 14 +#define QUARTERSPEED_LEVEL 8 +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL MAX_Nx7135 // safe limit max regulated power // 20 46 72 98 [125] -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#define SIMPLE_UI_CEIL MAX_Nx7135 -#define SIMPLE_UI_STEPS 5 +#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR +#define SIMPLE_UI_CEIL MAX_Nx7135 +#define SIMPLE_UI_STEPS 5 // regulate down faster when the FET is active, slower otherwise #define THERM_FASTER_LEVEL 130 // throttle back faster when high @@ -45,18 +47,19 @@ #undef BLINK_AT_RAMP_MIDDLE #undef BLINK_AT_RAMP_CEIL -// too big, remove stuff to make room +// enable extra features +#define USE_SMOOTH_STEPS + +// too big, turn off extra features +#undef USE_MOMENTARY_MODE +#undef USE_TACTICAL_MODE #undef USE_SOS_MODE -#undef USE_RAMP_AFTER_MOON_CONFIG -#undef USE_RAMP_SPEED_CONFIG -#undef USE_VOLTAGE_CORRECTION +//#undef USE_RAMP_AFTER_MOON_CONFIG +//#undef USE_RAMP_SPEED_CONFIG +//#undef USE_VOLTAGE_CORRECTION //#undef USE_2C_STYLE_CONFIG //#undef USE_TACTICAL_STROBE_MODE +//#ifdef USE_LOWPASS_WHILE_ASLEEP +//#undef USE_LOWPASS_WHILE_ASLEEP +//#endif -// reduce size a bit -#ifdef USE_LOWPASS_WHILE_ASLEEP -#undef USE_LOWPASS_WHILE_ASLEEP -#endif - -// too big, turn off extra features -#undef USE_TACTICAL_MODE diff --git a/spaghetti-monster/anduril/cfg-ff-rot66g2.h b/spaghetti-monster/anduril/cfg-ff-rot66g2.h index dca180d..04aac53 100644 --- a/spaghetti-monster/anduril/cfg-ff-rot66g2.h +++ b/spaghetti-monster/anduril/cfg-ff-rot66g2.h @@ -18,6 +18,9 @@ #endif #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) +// the button is *not* visible while main LEDs are on +#undef USE_INDICATOR_LED_WHILE_RAMPING + // ramp shape is different than original ROT66 // 1x7135: 150 lm // Nx7135: 1200 lm diff --git a/spaghetti-monster/anduril/cfg-fw3a.h b/spaghetti-monster/anduril/cfg-fw3a.h index 1802f9b..53c4135 100644 --- a/spaghetti-monster/anduril/cfg-fw3a.h +++ b/spaghetti-monster/anduril/cfg-fw3a.h @@ -21,12 +21,12 @@ #define HALFSPEED_LEVEL 15 #define QUARTERSPEED_LEVEL 6 -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL MAX_Nx7135 +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL MAX_Nx7135 // 10, 30, 50, [70], 90, 110, 130 -#define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 7 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 // safe limit ~20% power // 20 40 60 80 100 -- cgit v1.2.3 From 05670fd2095d2f51b9b656751c0da9c13a7e1dbf Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sat, 28 Oct 2023 09:03:21 -0600 Subject: converted noctigon-k1-sbt90 to new API and switched to dynamic PWM (but it's not tested on hardware, since I have none) --- hwdef-Noctigon_K1-SBT90.h | 144 ------------------ hwdef-noctigon-k1-sbt90.h | 177 ++++++++++++++++++++++ spaghetti-monster/anduril/cfg-noctigon-k1-sbt90.h | 61 ++++++-- 3 files changed, 226 insertions(+), 156 deletions(-) delete mode 100644 hwdef-Noctigon_K1-SBT90.h create mode 100644 hwdef-noctigon-k1-sbt90.h diff --git a/hwdef-Noctigon_K1-SBT90.h b/hwdef-Noctigon_K1-SBT90.h deleted file mode 100644 index 9d91c1c..0000000 --- a/hwdef-Noctigon_K1-SBT90.h +++ /dev/null @@ -1,144 +0,0 @@ -// Noctigon K1-SBT90.2 driver layout (attiny1634) -// Copyright (C) 2019-2023 Selene ToyKeeper -// SPDX-License-Identifier: GPL-3.0-or-later -#pragma once - -/* - * (mostly the same as KR4 driver) - * - * Pin / Name / Function - * 1 PA6 FET PWM (direct drive) (PWM1B) - * 2 PA5 R: red aux LED (PWM0B) - * 3 PA4 G: green aux LED - * 4 PA3 B: blue aux LED - * 5 PA2 (none) - * 6 PA1 (none) - * 7 PA0 (none) - * 8 GND GND - * 9 VCC VCC - * 10 PC5 (none) - * 11 PC4 (none) - * 12 PC3 RESET - * 13 PC2 (none) - * 14 PC1 SCK - * 15 PC0 (none) PWM0A - * 16 PB3 main LED PWM (linear) (PWM1A) - * 17 PB2 MISO / e-switch (PCINT10) - * 18 PB1 MOSI / battery voltage (ADC6) - * 19 PB0 Opamp power - * 20 PA7 (none) - * ADC12 thermal sensor - * - * Main LED power uses one pin to turn the Opamp on/off, - * and one pin to control Opamp power level. - * Main brightness control uses the power level pin, with 4 kHz 10-bit PWM. - * The on/off pin is only used to turn the main LED on and off, - * not to change brightness. - * Also has a direct-drive FET for turbo. - */ - -#ifdef ATTINY -#undef ATTINY -#endif -#define ATTINY 1634 -#include - -#define PWM_CHANNELS 2 -#define PWM_BITS 10 // 0 to 1023 at 4 kHz, not 0 to 255 at 16 kHz -#define PWM_TOP 1023 - -#define SWITCH_PIN PB2 // pin 17 -#define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt -#define SWITCH_PCIE PCIE1 // PCIE1 is for PCINT[11:8] -#define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] -#define SWITCH_PORT PINB // PINA or PINB or PINC -#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] - -#define PWM1_PIN PB3 // pin 16, Opamp reference -#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 - -#define PWM2_PIN PA6 // pin 1, DD FET PWM -#define PWM2_LVL OCR1B // OCR1B is the output compare register for PA6 - -#define LED_ENABLE_PIN PB0 // pin 19, Opamp power -#define LED_ENABLE_PORT PORTB // control port for PB0 - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// TODO: calibrate this -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 256 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif - -#define TEMP_CHANNEL 0b00001111 - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - // enable output ports - // Opamp level and Opamp on/off - DDRB = (1 << PWM1_PIN) - | (1 << LED_ENABLE_PIN); - // DD FET PWM, aux R/G/B - DDRA = (1 << PWM2_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // WGM1[3:0]: 0,0,1,1: PWM, Phase Correct, 10-bit (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) - TCCR1A = (1< + +#define HWDEF_C_FILE hwdef-noctigon-kr4.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +// channel modes: +// * 0. linear + DD FET stacked +// * 1+. aux RGB +#define NUM_CHANNEL_MODES (1 + NUM_RGB_AUX_CHANNEL_MODES) +enum CHANNEL_MODES { + CM_MAIN = 0, + RGB_AUX_ENUMS +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 +// no args +//#define USE_CHANNEL_MODE_ARGS +//#define CHANNEL_MODE_ARGS 0,0,0,0,0,0,0,0 + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // linear ramp +#define PWM2_DATATYPE uint8_t // DD FET ramp + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP ICR1 // holds the TOP value for variable-resolution PWM +#define PWM_TOP_INIT 255 // highest value used in top half of ramp +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +// linear channel +#define CH1_PIN PB3 // pin 16, Opamp reference +#define CH1_PWM OCR1A // OCR1A is the output compare register for PB3 +#define CH1_ENABLE_PIN PB0 // pin 19, Opamp power +#define CH1_ENABLE_PORT PORTB // control port for PB0 + +// DD FET channel +#define CH2_PIN PA6 // pin 1, DD FET PWM +#define CH2_PWM OCR1B // OCR1B is the output compare register for PA6 + +// e-switch +#define SWITCH_PIN PB2 // pin 17 +#define SWITCH_PCINT PCINT10 // pin 17 pin change interrupt +#define SWITCH_PCIE PCIE1 // PCIE1 is for PCINT[11:8] +#define SWITCH_PCMSK PCMSK1 // PCMSK1 is for PCINT[11:8] +#define SWITCH_PORT PINB // PINA or PINB or PINC +#define SWITCH_PUE PUEB // pullup group B +#define PCINT_vect PCINT1_vect // ISR for PCINT[11:8] + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 +// pin to ADC mappings are in DS table 19-4 +#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 +// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 +#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D +// DS tables 19-3, 19-4 +// Bit 7 6 5 4 3 2 1 0 +// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 +// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 +// divided by ... +// REFS[1:0] = 1, 0 for internal 1.1V reference +// other bits reserved +#define ADMUX_VOLTAGE_DIVIDER 0b10000110 +#define ADC_PRSCL 0x07 // clk/128 + +// TODO: calibrate this +// Raw ADC readings at 4.4V and 2.2V +// calibrate the voltage readout here +// estimated / calculated values are: +// (voltage - D1) * (R2/(R2+R1) * 1024 / 1.1) +// D1, R1, R2 = 0, 330, 100 +#ifndef ADC_44 +//#define ADC_44 981 // raw value at 4.40V +#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 +#endif +#ifndef ADC_22 +//#define ADC_22 489 // raw value at 2.20V +#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 +#endif + +#define TEMP_CHANNEL 0b00001111 + +// this light has aux LEDs under the optic +#define AUXLED_R_PIN PA5 // pin 2 +#define AUXLED_G_PIN PA4 // pin 3 +#define AUXLED_B_PIN PA3 // pin 4 +#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC +#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC +#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC + +inline void hwdef_setup() { + // enable output ports + // Opamp level and Opamp on/off + DDRB = (1 << CH1_PIN) + | (1 << CH1_ENABLE_PIN); + // DD FET PWM, aux R/G/B + DDRA = (1 << CH2_PIN) + | (1 << AUXLED_R_PIN) + | (1 << AUXLED_G_PIN) + | (1 << AUXLED_B_PIN) + ; + + // configure PWM + // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter + // pre-scale for timer: N = 1 + // WGM1[3:0]: 1,0,1,0: PWM, Phase Correct, adjustable (DS table 12-5) + // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) + // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) + // COM1B[1:0]: 1,0: PWM OC1B in the normal direction (DS table 12-4) + TCCR1A = (1<> 7; // enable timer overflow interrupt so DSM can work - DSM_INTCTRL |= DSM_OVF_bm; + DSM_INTCTRL = DSM_OVF_bm; // reset phase when turning on if (! was_on) PWM_CNT = 0; @@ -107,6 +107,10 @@ ISR(DSM_vect) { ch2_dsm += (ch2_dsm_lvl & 0x007f); ch2_pwm = (ch2_dsm_lvl >> 7) + (ch2_dsm > 0x7f); ch2_dsm &= 0x7f; + + // clear the interrupt flag to indicate it was handled + // as per: https://onlinedocs.microchip.com/pr/GUID-C37FFBA8-82C6-4339-A2B1-ABD9A0F6C162-en-US-8/index.html?GUID-C2A2BEFD-158F-413D-B9D4-0F0556AA79BD + DSM_INTFLAGS = DSM_OVF_bm; } diff --git a/hwdef-blf-lt1-t1616.h b/hwdef-blf-lt1-t1616.h index cc6d065..a28ee0f 100644 --- a/hwdef-blf-lt1-t1616.h +++ b/hwdef-blf-lt1-t1616.h @@ -65,19 +65,20 @@ enum channel_modes_e { // timer interrupt for DSM #define DSM_vect TCA0_OVF_vect #define DSM_INTCTRL TCA0.SINGLE.INTCTRL +#define DSM_INTFLAGS TCA0.SINGLE.INTFLAGS #define DSM_OVF_bm TCA_SINGLE_OVF_bm // warm LEDs uint16_t ch1_dsm_lvl; uint8_t ch1_pwm, ch1_dsm; #define CH1_PIN PB1 -#define CH1_PWM TCA0.SINGLE.CMP1 // CMP1 is the output compare register for PB1 +#define CH1_PWM TCA0.SINGLE.CMP1BUF // CMP1 is the output compare register for PB1 // cold LEDs uint16_t ch2_dsm_lvl; uint8_t ch2_pwm, ch2_dsm; #define CH2_PIN PB0 -#define CH2_PWM TCA0.SINGLE.CMP0 // CMP0 is the output compare register for PB0 +#define CH2_PWM TCA0.SINGLE.CMP0BUF // CMP0 is the output compare register for PB0 // lighted button #define AUXLED_PIN PIN5_bp @@ -106,6 +107,7 @@ inline void hwdef_setup() { // Outputs VPORTB.DIR = PIN0_bm // cool white | PIN1_bm // warm white + // | PIN2_bm // for testing on LT1S Pro, disable red channel | PIN5_bm; // aux LED //VPORTC.DIR = ...; @@ -121,7 +123,7 @@ inline void hwdef_setup() { //PORTB.PIN0CTRL = PORT_PULLUPEN_bm; // cold tint channel //PORTB.PIN1CTRL = PORT_PULLUPEN_bm; // warm tint channel - PORTB.PIN2CTRL = PORT_PULLUPEN_bm; + PORTB.PIN2CTRL = PORT_PULLUPEN_bm; // comment out for testing on LT1S Pro PORTB.PIN3CTRL = PORT_PULLUPEN_bm; PORTB.PIN4CTRL = PORT_PULLUPEN_bm; //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED diff --git a/hwdef-sofirn-lt1s-pro.h b/hwdef-sofirn-lt1s-pro.h index 97de7d7..ae6b3bf 100644 --- a/hwdef-sofirn-lt1s-pro.h +++ b/hwdef-sofirn-lt1s-pro.h @@ -96,10 +96,11 @@ enum channel_modes_e { inline void hwdef_setup() { // set up the system clock to run at 10 MHz instead of the default 3.33 MHz - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, + CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); //VPORTA.DIR = ...; - // Outputs: + // Outputs VPORTB.DIR = PIN0_bm // warm white | PIN1_bm // cool white | PIN2_bm // red diff --git a/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h b/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h index 24a7c7c..fc02619 100644 --- a/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h +++ b/spaghetti-monster/anduril/cfg-blf-lantern-t1616.h @@ -17,9 +17,14 @@ // channel modes... // CM_CH1, CM_CH2, CM_BOTH, CM_BLEND, CM_AUTO -#define DEFAULT_CHANNEL_MODE CM_AUTO +#define DEFAULT_CHANNEL_MODE CM_AUTO +#define DEFAULT_BLINK_CHANNEL CM_BOTH + +#define CONFIG_WAITING_CHANNEL CM_BOTH +#define CONFIG_BLINK_CHANNEL CM_BOTH + +// blink numbers on the main LEDs by default (but allow user to change it) #define DEFAULT_BLINK_CHANNEL CM_BOTH -#define USE_CHANNEL_MODE_ARGS // how much to increase total brightness at middle tint // (0 = 100% brightness, 64 = 200% brightness) @@ -30,13 +35,13 @@ // delta-sigma modulated PWM (0b0HHHHHHHHLLLLLLL = 0, 8xHigh, 7xLow bits) // (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) // level_calc.py 3.333 1 150 7135 32 0.2 600 --pwm 32640 -#define PWM1_LEVELS 32,35,38,41,45,50,55,61,67,74,82,91,100,110,121,133,146,160,175,192,209,227,247,268,291,314,340,366,395,424,456,489,524,560,599,639,681,726,772,820,871,924,979,1036,1096,1158,1222,1289,1359,1431,1506,1584,1664,1747,1834,1923,2015,2111,2209,2311,2416,2524,2636,2751,2870,2992,3118,3247,3380,3518,3659,3803,3952,4105,4262,4423,4589,4759,4933,5111,5294,5482,5674,5871,6073,6279,6491,6707,6928,7155,7386,7623,7865,8113,8365,8624,8888,9157,9432,9713,10000,10292,10591,10895,11206,11523,11846,12175,12511,12853,13202,13557,13919,14287,14663,15045,15434,15830,16233,16644,17061,17486,17919,18358,18805,19260,19723,20193,20671,21156,21650,22152,22662,23180,23706,24241,24784,25335,25895,26464,27041,27627,28222,28826,29439,30060,30691,31332,31981,32640 +#define PWM1_LEVELS 4,35,38,41,45,50,55,61,67,74,82,91,100,110,121,133,146,160,175,192,209,227,247,268,291,314,340,366,395,424,456,489,524,560,599,639,681,726,772,820,871,924,979,1036,1096,1158,1222,1289,1359,1431,1506,1584,1664,1747,1834,1923,2015,2111,2209,2311,2416,2524,2636,2751,2870,2992,3118,3247,3380,3518,3659,3803,3952,4105,4262,4423,4589,4759,4933,5111,5294,5482,5674,5871,6073,6279,6491,6707,6928,7155,7386,7623,7865,8113,8365,8624,8888,9157,9432,9713,10000,10292,10591,10895,11206,11523,11846,12175,12511,12853,13202,13557,13919,14287,14663,15045,15434,15830,16233,16644,17061,17486,17919,18358,18805,19260,19723,20193,20671,21156,21650,22152,22662,23180,23706,24241,24784,25335,25895,26464,27041,27627,28222,28826,29439,30060,30691,31332,31981,32640 #define DEFAULT_LEVEL 75 #define MAX_1x7135 75 -#define HALFSPEED_LEVEL 1 // lowest level for tint ramping correction -#define QUARTERSPEED_LEVEL 1 -#undef USE_DYNAMIC_UNDERCLOCKING // makes huge bumps in the ramp +#define HALFSPEED_LEVEL 0 // always use tint ramping correction +#define QUARTERSPEED_LEVEL 2 // quarter speed at level 1, full speed at 2+ +//#undef USE_DYNAMIC_UNDERCLOCKING // makes huge bumps in the ramp #define USE_SET_LEVEL_GRADUALLY @@ -57,8 +62,10 @@ #define SIMPLE_UI_CEIL 150 #define SIMPLE_UI_STEPS 5 -// Allow 3C in Simple UI for switching between smooth and stepped ramping +// Allow 3C (or 6C) in Simple UI (toggle smooth or stepped ramping) #define USE_SIMPLE_UI_RAMPING_TOGGLE + +// allow Aux Config and Strobe Modes in Simple UI #define USE_EXTENDED_SIMPLE_UI #define USE_SOS_MODE diff --git a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h index aee9ba0..440a03d 100644 --- a/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h +++ b/spaghetti-monster/anduril/cfg-sofirn-lt1s-pro.h @@ -32,9 +32,6 @@ // blink numbers on the main LEDs by default (but allow user to change it) #define DEFAULT_BLINK_CHANNEL CM_RED -#define POLICE_COLOR_STROBE_CH1 CM_RED -#define POLICE_COLOR_STROBE_CH2 CM_WHITE - // how much to increase total brightness at middle tint // (0 = 100% brightness, 64 = 200% brightness) // seems unnecessary on this light @@ -74,18 +71,18 @@ #define RAMP_STYLE 1 // 0 = smooth, 1 = stepped // set floor and ceiling as far apart as possible // because this lantern isn't overpowered -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 150 +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 150 //#define RAMP_DISCRETE_FLOOR 17 // 17 50 83 116 150 -#define RAMP_DISCRETE_FLOOR 1 // 1 25 50 75 100 125 150 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 7 +#define RAMP_DISCRETE_FLOOR 1 // 1 25 50 75 100 125 150 +#define RAMP_DISCRETE_CEIL 150 +#define RAMP_DISCRETE_STEPS 7 // LT1S can handle heat well, so don't limit simple mode //#define SIMPLE_UI_FLOOR 10 // 10 45 80 115 150 -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL -#define SIMPLE_UI_STEPS RAMP_DISCRETE_STEPS +#define SIMPLE_UI_FLOOR 1 +#define SIMPLE_UI_CEIL 150 +#define SIMPLE_UI_STEPS 7 // Allow 3C (or 6C) in Simple UI (toggle smooth or stepped ramping) #define USE_SIMPLE_UI_RAMPING_TOGGLE @@ -106,6 +103,9 @@ #define USE_SOS_MODE_IN_BLINKY_GROUP #define USE_POLICE_COLOR_STROBE_MODE +#define POLICE_COLOR_STROBE_CH1 CM_RED +#define POLICE_COLOR_STROBE_CH2 CM_WHITE + #undef TACTICAL_LEVELS #define TACTICAL_LEVELS 120,30,(RAMP_SIZE+3) // high, low, police strobe -- cgit v1.2.3 From bcaf2686d9f0570dfbc508ddcac95ee55d501f48 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 29 Oct 2023 13:05:38 -0600 Subject: converted noctigon-dm11-boost to use PWM+DSM, and recalibrated timing for delays + smooth steps Anduril has gradually gotten faster over the years, apparently, so it needed longer delays to get accurate-ish timing for beacon and other modes. Adding DSM also changes the timing perceptibly, so I made it possible to calibrate the delay fudge factor on a per-build basis. --- hwdef-noctigon-dm11-boost.c | 63 +++++++++++++++++----- hwdef-noctigon-dm11-boost.h | 60 +++++++++++++-------- hwdef-noctigon-m44.h | 22 ++++---- .../anduril/cfg-noctigon-dm11-boost.h | 17 +++++- spaghetti-monster/anduril/smooth-steps.c | 4 +- spaghetti-monster/fsm-events.c | 8 +-- spaghetti-monster/fsm-events.h | 5 ++ 7 files changed, 126 insertions(+), 53 deletions(-) diff --git a/hwdef-noctigon-dm11-boost.c b/hwdef-noctigon-dm11-boost.c index 08e2798..932323a 100644 --- a/hwdef-noctigon-dm11-boost.c +++ b/hwdef-noctigon-dm11-boost.c @@ -1,11 +1,11 @@ // Noctigon DM11 (boost driver) PWM helper functions // Copyright (C) 2023 Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later - #pragma once #include "chan-rgbaux.c" + void set_level_zero(); void set_level_main(uint8_t level); @@ -22,6 +22,12 @@ Channel channels[] = { void set_level_zero() { + // disable timer overflow interrupt + // (helps improve button press handling from Off state) + DSM_INTCTRL &= ~DSM_OVF_bm; + + // turn off all LEDs + ch1_dsm_lvl = 0; CH1_PWM = 0; PWM_CNT = 0; // reset phase CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN ); // disable opamp @@ -30,28 +36,59 @@ void set_level_zero() { // single set of LEDs with single power channel, boost void set_level_main(uint8_t level) { - CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN ); // enable opamp - CH1_ENABLE_PORT2 |= (1 << CH1_ENABLE_PIN2); // enable PMIC + PWM_DATATYPE ch1 = PWM_GET(pwm1_levels, level); - PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); - // pulse frequency modulation, a.k.a. dynamic PWM - uint16_t top = PWM_GET16(pwm_tops, level); + // set delta-sigma soft levels + ch1_dsm_lvl = ch1; + + // set hardware PWM levels and init dsm loop + CH1_PWM = ch1_pwm = ch1 >> 7; + + // enable timer overflow interrupt so DSM can work + DSM_INTCTRL |= DSM_OVF_bm; - CH1_PWM = ch1_pwm; - // wait to sync the counter and avoid flashes - while(actual_level && (PWM_CNT > (top - 32))) {} - PWM_TOP = top; // force reset phase when turning on from zero // (because otherwise the initial response is inconsistent) if (! actual_level) PWM_CNT = 0; + + CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN ); // enable opamp + CH1_ENABLE_PORT2 |= (1 << CH1_ENABLE_PIN2); // enable PMIC } +// delta-sigma modulation of PWM outputs +// happens on each Timer overflow (every 512 cpu clock cycles) +// uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD) +ISR(DSM_vect) { + // set new hardware values first, + // for best timing (reduce effect of interrupt jitter) + CH1_PWM = ch1_pwm; + + // calculate next values, now that timing matters less + + // accumulate error + ch1_dsm += (ch1_dsm_lvl & 0x007f); + // next PWM = base PWM value + carry bit + ch1_pwm = (ch1_dsm_lvl >> 7) + (ch1_dsm > 0x7f); + // clear carry bit + ch1_dsm &= 0x7f; +} + + bool gradual_tick_main(uint8_t gt) { - PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE ch1 = PWM_GET(pwm1_levels, gt); + + // adjust multiple times based on current brightness + // (so it adjusts faster/coarser when bright, slower/finer when dim) + + // higher shift = slower/finer adjustments + const uint8_t shift = 9; // ((255 << 7) >> 9) = 63 max + uint8_t steps; - GRADUAL_ADJUST_SIMPLE(pwm1, CH1_PWM); + steps = ch1_dsm_lvl >> shift; + for (uint8_t i=0; i<=steps; i++) + GRADUAL_ADJUST_SIMPLE(ch1, ch1_dsm_lvl); - if ( (pwm1 == CH1_PWM) + if ((ch1 == ch1_dsm_lvl) ) { return true; // done } diff --git a/hwdef-noctigon-dm11-boost.h b/hwdef-noctigon-dm11-boost.h index 4453bc7..d56a5f5 100644 --- a/hwdef-noctigon-dm11-boost.h +++ b/hwdef-noctigon-dm11-boost.h @@ -31,7 +31,7 @@ * * Main LED power uses one pin to turn the Opamp on/off, * and one pin to control Opamp power level. - * Linear brightness control uses the power level pin, with dynamic PWM. + * Regulated brightness control uses the power level pin, with PWM+DSM. * The on/off pin is only used to turn the main LED on and off, * not to change brightness. */ @@ -62,35 +62,46 @@ enum CHANNEL_MODES { //#define CHANNEL_MODE_ARGS 0,0,0,0,0,0,0,0 -#define PWM_CHANNELS 1 // old, remove this +#define PWM_CHANNELS 1 // old, remove this -#define PWM_BITS 16 // dynamic 16-bit, but never goes over 255 -#define PWM_GET PWM_GET8 -#define PWM_DATATYPE uint16_t // is used for PWM_TOPS (which goes way over 255) -#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 -#define PWM1_DATATYPE uint8_t // regulated ramp +#define PWM_BITS 16 // 0 to 32640 (0 to 255 PWM + 0 to 127 DSM) at constant kHz +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // 15-bit PWM+DSM ramp #define PWM_TOP ICR1 // holds the TOP value for variable-resolution PWM -#define PWM_TOP_INIT 255 // highest value used in top half of ramp -#define PWM_CNT TCNT1 // for dynamic PWM, reset phase +#define PWM_TOP_INIT 255 +#define PWM_CNT TCNT1 // for checking / resetting phase +// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) +#define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry + +// timer interrupt for DSM +#define DSM_vect TIMER1_OVF_vect +#define DSM_INTCTRL TIMSK +#define DSM_OVF_bm (1< end of dynamic PWM range #define HALFSPEED_LEVEL 12 #define QUARTERSPEED_LEVEL 4 +#endif + +// delta-sigma modulated PWM (0b0HHHHHHHHLLLLLLL = 0, 8xHigh, 7xLow bits) +// level_calc.py 5.01 1 150 7135 0 0.2 2000 --pwm 32640 +// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) +#define PWM1_LEVELS 0,1,2,3,4,5,6,7,9,10,12,14,17,19,22,25,28,32,36,41,45,50,56,62,69,76,84,92,101,110,121,132,143,156,169,184,199,215,232,251,270,291,313,336,360,386,414,442,473,505,539,574,612,651,693,736,782,829,880,932,987,1045,1105,1168,1233,1302,1374,1449,1527,1608,1693,1781,1873,1969,2068,2172,2279,2391,2507,2628,2753,2883,3018,3158,3303,3454,3609,3771,3938,4111,4289,4475,4666,4864,5068,5280,5498,5724,5957,6197,6445,6701,6965,7237,7518,7808,8106,8413,8730,9056,9392,9737,10093,10459,10835,11223,11621,12031,12452,12884,13329,13786,14255,14737,15232,15741,16262,16798,17347,17911,18489,19082,19691,20314,20954,21609,22281,22969,23674,24397,25137,25895,26671,27465,28279,29111,29963,30835,31727,32640 +#define MIN_THERM_STEPDOWN 50 +#define DEFAULT_LEVEL 70 +#define MAX_1x7135 150 +// always run at 1/4th speed, because 4 kHz PWM is enough for this circuit +// and speed changes make a big visible bump +#define HALFSPEED_LEVEL 255 +#define QUARTERSPEED_LEVEL 255 -#define RAMP_SMOOTH_FLOOR 10 // low levels may be unreliable +#define RAMP_SMOOTH_FLOOR 1 // low levels may be unreliable #define RAMP_SMOOTH_CEIL 130 // 10, 30, 50, [70], 90, 110, 130 // Nichia B35 model: (0.56), 1.4, 8.4, 34.5, [102], 250, 500, 860, (1300) lm diff --git a/spaghetti-monster/anduril/smooth-steps.c b/spaghetti-monster/anduril/smooth-steps.c index d907bc1..b8664bd 100644 --- a/spaghetti-monster/anduril/smooth-steps.c +++ b/spaghetti-monster/anduril/smooth-steps.c @@ -23,12 +23,12 @@ void smooth_steps_iter() { uint8_t this = diff / smooth_steps_speed; if (!this) this = 1; set_level(actual_level + this); - nice_delay_ms(10); + nice_delay_ms(9); } else { // ramp-linear descent // (jump by 1 on each frame, frame rate gives constant total time) uint8_t diff = smooth_steps_start - smooth_steps_target; - uint16_t delay = 1 + (26 * smooth_steps_speed / diff); + uint16_t delay = 1 + (22 * smooth_steps_speed / diff); set_level(actual_level - 1); // TODO? if delay < one PWM cycle, this can look a little weird nice_delay_ms(delay); diff --git a/spaghetti-monster/fsm-events.c b/spaghetti-monster/fsm-events.c index ffa93d1..6987ae2 100644 --- a/spaghetti-monster/fsm-events.c +++ b/spaghetti-monster/fsm-events.c @@ -127,7 +127,7 @@ uint8_t nice_delay_ms(uint16_t ms) { uint8_t level = actual_level; // volatile, avoid repeat access if (level < QUARTERSPEED_LEVEL) { clock_prescale_set(clock_div_4); - _delay_loop_2(BOGOMIPS*90/100/4); + _delay_loop_2(BOGOMIPS*DELAY_FACTOR/100/4); } //else if (level < HALFSPEED_LEVEL) { // clock_prescale_set(clock_div_2); @@ -135,7 +135,7 @@ uint8_t nice_delay_ms(uint16_t ms) { //} else { clock_prescale_set(clock_div_1); - _delay_loop_2(BOGOMIPS*90/100); + _delay_loop_2(BOGOMIPS*DELAY_FACTOR/100); } // restore regular clock speed clock_prescale_set(clock_div_1); @@ -143,13 +143,13 @@ uint8_t nice_delay_ms(uint16_t ms) { // underclock MCU to save power clock_prescale_set(clock_div_4); // wait - _delay_loop_2(BOGOMIPS*90/100/4); + _delay_loop_2(BOGOMIPS*DELAY_FACTOR/100/4); // restore regular clock speed clock_prescale_set(clock_div_1); #endif // ifdef USE_RAMPING #else // wait - _delay_loop_2(BOGOMIPS*90/100); + _delay_loop_2(BOGOMIPS*DELAY_FACTOR/100); #endif // ifdef USE_DYNAMIC_UNDERCLOCKING // run pending system processes while we wait diff --git a/spaghetti-monster/fsm-events.h b/spaghetti-monster/fsm-events.h index 10d3317..9692163 100644 --- a/spaghetti-monster/fsm-events.h +++ b/spaghetti-monster/fsm-events.h @@ -54,6 +54,11 @@ uint8_t push_event(uint8_t ev_type); // only for use by PCINT_inner() // TODO: Maybe move these to their own file... // ... this probably isn't the right place for delays. +#ifndef DELAY_FACTOR +// adjust the timing of delays, lower = shorter delays +// 90 = 90% delay, 10% for other things +#define DELAY_FACTOR 92 +#endif inline void interrupt_nice_delays(); uint8_t nice_delay_ms(uint16_t ms); //uint8_t nice_delay_s(); -- cgit v1.2.3 From 4aec487ea7d03e9554ebbe8f50e72235bf6f2e6e Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Sun, 29 Oct 2023 13:19:38 -0600 Subject: applied new delay factor to other DSM builds, and some new DSM_* defines --- hwdef-blf-lt1-t1616.h | 2 ++ hwdef-blf-lt1.c | 10 +++++----- hwdef-blf-lt1.h | 11 +++++++++-- hwdef-emisar-d4k-3ch.c | 12 ++++++++++-- hwdef-emisar-d4k-3ch.h | 10 +++++++++- hwdef-noctigon-m44.h | 2 ++ 6 files changed, 37 insertions(+), 10 deletions(-) diff --git a/hwdef-blf-lt1-t1616.h b/hwdef-blf-lt1-t1616.h index a28ee0f..7c1f10b 100644 --- a/hwdef-blf-lt1-t1616.h +++ b/hwdef-blf-lt1-t1616.h @@ -68,6 +68,8 @@ enum channel_modes_e { #define DSM_INTFLAGS TCA0.SINGLE.INTFLAGS #define DSM_OVF_bm TCA_SINGLE_OVF_bm +#define DELAY_FACTOR 90 // less time in delay() because more time spent in interrupts + // warm LEDs uint16_t ch1_dsm_lvl; uint8_t ch1_pwm, ch1_dsm; diff --git a/hwdef-blf-lt1.c b/hwdef-blf-lt1.c index 8a8af52..8a4c0e1 100644 --- a/hwdef-blf-lt1.c +++ b/hwdef-blf-lt1.c @@ -52,7 +52,7 @@ Channel channels[] = { void set_level_zero() { // disable timer 0 overflow interrupt // (helps improve button press handling from Off state) - TIMSK &= ~(1 << TOIE0); + DSM_INTCTRL &= ~DSM_OVF_bm; // turn off all LEDs ch1_dsm_lvl = 0; @@ -72,14 +72,14 @@ void set_hw_levels(PWM_DATATYPE ch1, PWM_DATATYPE ch2) { CH1_PWM = ch1_pwm = ch1 >> 7; CH2_PWM = ch2_pwm = ch2 >> 7; - // enable timer 0 overflow interrupt so DSM can work - TIMSK |= (1 << TOIE0); + // enable timer overflow interrupt so DSM can work + DSM_INTCTRL |= DSM_OVF_bm; } // delta-sigma modulation of PWM outputs -// happens on each Timer0 overflow (every 512 cpu clock cycles) +// happens on each Timer overflow (every 512 cpu clock cycles) // uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD) -ISR(TIMER0_OVF_vect) { +ISR(DSM_vect) { // set new hardware values first, // for best timing (reduce effect of interrupt jitter) CH1_PWM = ch1_pwm; diff --git a/hwdef-blf-lt1.h b/hwdef-blf-lt1.h index 8fce09f..b113fd4 100644 --- a/hwdef-blf-lt1.h +++ b/hwdef-blf-lt1.h @@ -56,6 +56,13 @@ enum channel_modes_e { #define PWM_TOP_INIT 255 #define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry +// timer interrupt for DSM +#define DSM_vect TIMER0_OVF_vect +#define DSM_INTCTRL TIMSK +#define DSM_OVF_bm (1< 1, 2 => 8, 3 => 64...) TCCR0A = PHASE; - // enable timer 0 overflow interrupt for DSM purposes - //TIMSK |= (1 << TOIE0); // moved to hwdef.c functions instead + // enable timer overflow interrupt for DSM purposes + //DSM_INTCTRL |= DSM_OVF_bm; // moved to hwdef.c functions instead // configure e-switch PORTB = (1 << SWITCH_PIN); // e-switch is the only input diff --git a/hwdef-emisar-d4k-3ch.c b/hwdef-emisar-d4k-3ch.c index ba6643d..e35af08 100644 --- a/hwdef-emisar-d4k-3ch.c +++ b/hwdef-emisar-d4k-3ch.c @@ -78,6 +78,10 @@ StatePtr channel_3H_modes[NUM_CHANNEL_MODES] = { }; void set_level_zero() { + // disable timer overflow interrupt + // (helps improve button press handling from Off state) + DSM_INTCTRL &= ~DSM_OVF_bm; + // turn off all LEDs MAIN2_ENABLE_PORT &= ~(1 << MAIN2_ENABLE_PIN); LED3_ENABLE_PORT &= ~(1 << LED3_ENABLE_PIN ); @@ -123,14 +127,18 @@ void set_hw_levels(PWM_DATATYPE main2, // brightness, 0 to DSM_TOP MAIN2_PWM_LVL = main2_pwm = main2 >> 7; LED3_PWM_LVL = led3_pwm = led3 >> 7; LED4_PWM_LVL = led4_pwm = led4 >> 7; + + // enable timer overflow interrupt so DSM can work + DSM_INTCTRL |= DSM_OVF_bm; + // force phase reset PWM_CNT = PWM_CNT2 = 0; } // delta-sigma modulation of PWM outputs -// happens on each Timer0 overflow (every 512 cpu clock cycles) +// happens on each Timer overflow (every 512 cpu clock cycles) // uses 8-bit pwm w/ 7-bit dsm (0b 0PPP PPPP PDDD DDDD) -ISR(TIMER0_OVF_vect) { +ISR(DSM_vect) { // set new hardware values first, // for best timing (reduce effect of interrupt jitter) MAIN2_PWM_LVL = main2_pwm; diff --git a/hwdef-emisar-d4k-3ch.h b/hwdef-emisar-d4k-3ch.h index 581f51c..2e83fbe 100644 --- a/hwdef-emisar-d4k-3ch.h +++ b/hwdef-emisar-d4k-3ch.h @@ -94,6 +94,13 @@ enum channel_modes_e { // (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) #define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry +// timer interrupt for DSM +#define DSM_vect TIMER0_OVF_vect +#define DSM_INTCTRL TIMSK +#define DSM_OVF_bm (1< - -#define PWM_CHANNELS 1 -#define PWM_BITS 10 // 0 to 1023 at 4 kHz, not 0 to 255 at 16 kHz -#define PWM_TOP 1023 - -#define SWITCH_PIN PA7 // pin 20 -#define SWITCH_PCINT PCINT7 // pin 20 pin change interrupt -#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] -#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] -#define SWITCH_PORT PINA // PINA or PINB or PINC - -#define PWM1_PIN PB3 // pin 16, Opamp reference -#define PWM1_LVL OCR1A // OCR1A is the output compare register for PB3 - -#define LED_ENABLE_PIN PB0 // pin 19, Opamp power -#define LED_ENABLE_PORT PORTB // control port for PB0 - -#define LED2_ENABLE_PIN PC0 // pin 15, boost PMIC enable -#define LED2_ENABLE_PORT PORTC // control port for PC0 - - -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB1 // Pin 18 / PB1 / ADC6 -// pin to ADC mappings are in DS table 19-4 -#define VOLTAGE_ADC ADC6D // digital input disable pin for PB1 -// DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 -#define VOLTAGE_ADC_DIDR DIDR1 // DIDR channel for ADC6D -// DS tables 19-3, 19-4 -// Bit 7 6 5 4 3 2 1 0 -// REFS1 REFS0 REFEN ADC0EN MUX3 MUX2 MUX1 MUX0 -// MUX[3:0] = 0, 1, 1, 0 for ADC6 / PB1 -// divided by ... -// REFS[1:0] = 1, 0 for internal 1.1V reference -// other bits reserved -#define ADMUX_VOLTAGE_DIVIDER 0b10000110 -#define ADC_PRSCL 0x07 // clk/128 - -// Raw ADC readings at 4.4V and 2.2V -// calibrate the voltage readout here -// estimated / calculated values are: -// (voltage - D1) * (R2/(R2+R1) * 256 / 1.1) -// D1, R1, R2 = 0, 330, 100 -#ifndef ADC_44 -//#define ADC_44 981 // raw value at 4.40V -#define ADC_44 967 // manually tweaked so 4.16V will blink out 4.2 -#endif -#ifndef ADC_22 -//#define ADC_22 489 // raw value at 2.20V -#define ADC_22 482 // manually tweaked so 4.16V will blink out 4.2 -#endif - -// this light has aux LEDs under the optic -#define AUXLED_R_PIN PA5 // pin 2 -#define AUXLED_G_PIN PA4 // pin 3 -#define AUXLED_B_PIN PA3 // pin 4 -#define AUXLED_RGB_PORT PORTA // PORTA or PORTB or PORTC -#define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC -#define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC - -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead -inline void hwdef_setup() { - // enable output ports - // boost PMIC on/off - DDRC = (1 << LED2_ENABLE_PIN); - // Opamp level and Opamp on/off - DDRB = (1 << PWM1_PIN) - | (1 << LED_ENABLE_PIN); - // aux R/G/B - DDRA = (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - ; - - // configure PWM - // Setup PWM. F_pwm = F_clkio / 2 / N / TOP, where N = prescale factor, TOP = top of counter - // pre-scale for timer: N = 1 - // WGM1[3:0]: 0,0,1,1: PWM, Phase Correct, 10-bit (DS table 12-5) - // CS1[2:0]: 0,0,1: clk/1 (No prescaling) (DS table 12-6) - // COM1A[1:0]: 1,0: PWM OC1A in the normal direction (DS table 12-4) - // COM1B[1:0]: 0,0: PWM OC1B disabled (DS table 12-4) - TCCR1A = (1< + +#define HWDEF_C_FILE hwdef-noctigon-dm11-boost.c + +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +// channel modes: +// * 0. main LEDs +// * 1+. aux RGB +#define NUM_CHANNEL_MODES (1 + NUM_RGB_AUX_CHANNEL_MODES) +enum CHANNEL_MODES { + CM_MAIN = 0, + RGB_AUX_ENUMS +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 +// no args +//#define USE_CHANNEL_MODE_ARGS +//#define CHANNEL_MODE_ARGS 0,0,0,0,0,0,0,0 + + +#define PWM_CHANNELS 1 // old, remove this + +#define PWM_BITS 16 // 0 to 32640 (0 to 255 PWM + 0 to 127 DSM) at constant kHz +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // 15-bit PWM+DSM ramp + +#define PWM_TOP ICR1 // holds the TOP value for variable-resolution PWM +#define PWM_TOP_INIT 255 +#define PWM_CNT TCNT1 // for checking / resetting phase +// (max is (255 << 7), because it's 8-bit PWM plus 7 bits of DSM) +#define DSM_TOP (255<<7) // 15-bit resolution leaves 1 bit for carry + +// timer interrupt for DSM +#define DSM_vect TIMER1_OVF_vect +#define DSM_INTCTRL TIMSK +#define DSM_OVF_bm (1< + +#define HWDEF_C_FILE hwdef-emisar-d4.c + +// channel modes +// * 0. FET+7135 stacked +#define NUM_CHANNEL_MODES 1 +enum CHANNEL_MODES { + CM_MAIN = 0, +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN + +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b00000001 + + +#define PWM_CHANNELS 2 // old, remove this + +#define PWM_BITS 8 // attiny85 only supports up to 8 bits +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define PWM_DATATYPE2 uint16_t +#define PWM1_DATATYPE uint8_t // little FET ramp +#define PWM2_DATATYPE uint8_t // big FET ramp + +#define PWM_TOP_INIT 255 // highest value used in top half of ramp + +// 1x7135 channel +#define CH1_PIN PB4 // pin 3, 1x7135 PWM +#define CH1_PWM OCR1B // OCR1B is the output compare register for PB4 + +// DD FET channel +#define CH2_PIN PB0 // pin 5, FET PWM +#define CH2_PWM OCR0A // OCR0A is the output compare register for PB0 + +// lighted button +#define AUXLED_PIN PB2 // pin 7 + +// e-switch +#ifndef SWITCH_PIN +#define SWITCH_PIN PB3 // pin 2 +#define SWITCH_PCINT PCINT3 // pin 2 pin change interrupt +#endif + +#define ADC_PRSCL 0x07 // clk/128 + +// average drop across diode on this hardware +#ifndef VOLTAGE_FUDGE_FACTOR +#define VOLTAGE_FUDGE_FACTOR 7 // add 0.35V +#endif + +#define FAST 0xA3 // fast PWM both channels +#define PHASE 0xA1 // phase-correct PWM both channels + + +inline void hwdef_setup() { + // configure PWM channels + DDRB = (1 << CH1_PIN) + | (1 << CH2_PIN); + + // configure PWM channels + TCCR0B = 0x01; // pre-scaler for timer (1 => 1, 2 => 8, 3 => 64...) + TCCR0A = PHASE; + + // Second PWM counter is ... weird + TCCR1 = _BV (CS10); + GTCCR = _BV (COM1B1) | _BV (PWM1B); + OCR1C = PWM_TOP_INIT; // Set ceiling value to maximum + + // configure e-switch + PORTB = (1 << SWITCH_PIN); // e-switch is the only input + PCMSK = (1 << SWITCH_PIN); // pin change interrupt uses this pin +} + + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h b/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h index fef1af6..1ca5008 100644 --- a/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h +++ b/spaghetti-monster/anduril/cfg-mateminco-mt35-mini.h @@ -1,44 +1,42 @@ // Mateminco MT35 Mini / Astrolux FT03 -// Copyright (C) 2022-2023 (FIXME) +// Copyright (C) 2022-2023 (original author TBD), Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once #define MODEL_NUMBER "0531" -#include "hwdef-Mateminco_MT35-Mini.h" +#include "hwdef-mateminco-mt35-mini.h" // ATTINY: 85 -// this light should be fine running a bit hotter than most -#undef DEFAULT_THERM_CEIL -#define DEFAULT_THERM_CEIL 55 - // the button lights up #define USE_INDICATOR_LED // the button is visible while main LEDs are on #define USE_INDICATOR_LED_WHILE_RAMPING -// enable blinking aux LEDs -#define TICK_DURING_STANDBY -#define STANDBY_TICK_SPEED 3 // every 0.128 s +#define RAMP_SIZE 150 -#define RAMP_LENGTH 150 // level_calc.py fifth 2 150 7135 1 1 120 FET 1 10 2000 #define PWM1_LEVELS 1,2,2,3,4,5,6,7,8,9,11,13,14,16,18,21,23,26,28,31,35,38,41,45,49,53,58,63,67,73,78,84,90,96,102,109,116,124,131,139,147,156,165,174,184,194,204,215,226,237,249,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0 #define PWM2_LEVELS 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,20,21,22,24,25,27,28,30,31,33,35,36,38,40,42,43,45,47,49,51,53,55,57,59,62,64,66,68,71,73,75,78,80,83,86,88,91,94,96,99,102,105,108,111,114,117,120,124,127,130,134,137,140,144,148,151,155,159,162,166,170,174,178,182,186,190,195,199,203,208,212,217,221,226,231,235,240,245,250,255 -#define DEFAULT_LEVEL 46 -#define MAX_1x7135 52 -#define HALFSPEED_LEVEL 20 -#define QUARTERSPEED_LEVEL 10 -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 112 -#define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 7 +#define DEFAULT_LEVEL 46 +#define MAX_1x7135 52 +#define HALFSPEED_LEVEL 20 +#define QUARTERSPEED_LEVEL 10 + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 112 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 // safe limit ~33% power -#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR -#define SIMPLE_UI_CEIL RAMP_LENGTH -#define SIMPLE_UI_STEPS 5 +#define SIMPLE_UI_FLOOR RAMP_DISCRETE_FLOOR +#define SIMPLE_UI_CEIL RAMP_DISCRETE_CEIL +#define SIMPLE_UI_STEPS 5 + +// this light should be fine running a bit hotter than most +#undef DEFAULT_THERM_CEIL +#define DEFAULT_THERM_CEIL 55 // stop panicking at ~40% power #define THERM_FASTER_LEVEL 120 @@ -54,10 +52,14 @@ // Allow 3C in Simple UI for switching between smooth and stepped ramping #define USE_SIMPLE_UI_RAMPING_TOGGLE +// enable extra features +#define USE_SMOOTH_STEPS + // too big, turn off extra features -//#undef USE_SOS_MODE +#undef USE_TACTICAL_MODE +#undef USE_SOS_MODE //#undef USE_RAMP_AFTER_MOON_CONFIG //#undef USE_RAMP_SPEED_CONFIG //#undef USE_VOLTAGE_CORRECTION //#undef USE_2C_STYLE_CONFIG -#undef USE_TACTICAL_MODE + -- cgit v1.2.3 From 02b2bb3929fb4bc60edccfa32ff695e25cd2ae4f Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 30 Oct 2023 09:26:03 -0600 Subject: build.sh: use busybox-compatible grep args --- bin/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build.sh b/bin/build.sh index a6169d1..499b5bd 100755 --- a/bin/build.sh +++ b/bin/build.sh @@ -48,7 +48,7 @@ function run () { } run $CPP $OTHERFLAGS $CPPFLAGS -o foo.cpp $PROGRAM.c -grep --text -E -v '^#|^$' foo.cpp > $PROGRAM.cpp ; rm foo.cpp +grep -a -E -v '^#|^$' foo.cpp > $PROGRAM.cpp ; rm foo.cpp run $CC $OTHERFLAGS $CFLAGS -o $PROGRAM.o -c $PROGRAM.c run $CC $OFLAGS $LDFLAGS -o $PROGRAM.elf $PROGRAM.o run $OBJCOPY $OBJCOPYFLAGS $PROGRAM.elf $PROGRAM.hex -- cgit v1.2.3 From 1e60feec749739ee917e4c9dc8b144b3ac1946be Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Mon, 30 Oct 2023 10:12:50 -0600 Subject: converted thefreeman-lin16dac to new API, but unsure if it works since I it's very uncommon hardware I don't have (also, there are some obvious things needing fixing, but I'd need hardware to calibrate it correctly) --- hwdef-thefreeman-lin16dac.c | 92 +++++++++++++++++ hwdef-thefreeman-lin16dac.h | 111 +++++++++++++-------- spaghetti-monster/anduril/MODELS | 1 + .../anduril/cfg-thefreeman-lin16dac.h | 62 +++++++----- 4 files changed, 201 insertions(+), 65 deletions(-) create mode 100644 hwdef-thefreeman-lin16dac.c diff --git a/hwdef-thefreeman-lin16dac.c b/hwdef-thefreeman-lin16dac.c new file mode 100644 index 0000000..07c7f9e --- /dev/null +++ b/hwdef-thefreeman-lin16dac.c @@ -0,0 +1,92 @@ +// thefreeman linear t1616 DAC driver helper functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "chan-aux.c" + +void set_level_zero(); + +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // main LEDs + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, + AUX_CHANNELS +}; + + +void set_level_zero() { + DAC_LVL = 0; // DAC off + DAC_VREF = V055; // low Vref + HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); // HDR off + + // prevent post-off flash + //IN_NFET_ENABLE_PORT |= (1 << IN_NFET_ENABLE_PIN); + //delay_4ms(IN_NFET_DELAY_TIME/4); + //IN_NFET_ENABLE_PORT &= ~(1 << IN_NFET_ENABLE_PIN); + + // turn off opamp last + OPAMP_ENABLE_PORT &= ~(1 << OPAMP_ENABLE_PIN); // Opamp off +} + +// single set of LEDs with 1 regulated power channel +// and low/high HDR plus low/high Vref as different "gears" +void set_level_main(uint8_t level) { + #if 0 // unsure if this helps anything + uint8_t noflash = 0; + + // when turning on from off, try to prevent a flash + if ((! actual_level) && (level < HDR_ENABLE_LEVEL_MIN)) { + noflash = 1; + } + #endif + + // Opamp on first, to give it a few extra microseconds to spin up + OPAMP_ENABLE_PORT |= (1 << OPAMP_ENABLE_PIN); + + // pre-load ramp data so it can be assigned faster later + PWM_DATATYPE dac_lvl = PWM_GET(pwm1_levels, level); + PWM_DATATYPE dac_vref = PWM_GET(pwm_tops, level); + + // enable HDR on top half of ramp + if (level >= (HDR_ENABLE_LEVEL_MIN-1)) + HDR_ENABLE_PORT |= (1 << HDR_ENABLE_PIN); + else + HDR_ENABLE_PORT &= ~(1 << HDR_ENABLE_PIN); + + #if 0 + if (noflash) { + // wait for flash prevention to finish + delay_4ms(OPAMP_ON_DELAY/4); + } + #endif + + // set these in successive clock cycles to avoid getting out of sync + // (minimizes ramp bumps when changing gears) + DAC_LVL = dac_lvl; + DAC_VREF = dac_vref; +} + +bool gradual_tick_main(uint8_t gt) { + // if HDR and Vref "engine gear" is the same, do a small adjustment... + // otherwise, simply jump to the next ramp level + // and let set_level() handle any gear changes + + PWM_DATATYPE dac_next = PWM_GET(pwm1_levels, gt); + PWM_DATATYPE vref_next = PWM_GET(pwm_tops, gt); + + // different gear = full adjustment + if (vref_next != DAC_VREF) return true; // let parent set_level() for us + + // same gear = small adjustment + GRADUAL_ADJUST_SIMPLE(dac_next, DAC_LVL); + if (dac_next == DAC_LVL) return true; // done + + return false; // not done yet +} + diff --git a/hwdef-thefreeman-lin16dac.h b/hwdef-thefreeman-lin16dac.h index 36e3929..c0d0638 100644 --- a/hwdef-thefreeman-lin16dac.h +++ b/hwdef-thefreeman-lin16dac.h @@ -1,5 +1,5 @@ // thefreeman's Linear 16 driver using DAC control -// Copyright (C) 2021-2023 (FIXME) +// Copyright (C) 2021-2023 thefreeman, Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once @@ -12,41 +12,68 @@ * Read voltage from VCC pin, has PFET so no drop */ -#define LAYOUT_DEFINED - -#ifdef ATTINY -#undef ATTINY -#endif #define ATTINY 1616 #include -#define PWM_CHANNELS 1 -#define USE_DYN_PWM // dynamic frequency and speed +#define HWDEF_C_FILE hwdef-thefreeman-lin16dac.c -#ifndef SWITCH_PIN -#define SWITCH_PIN PIN4_bp -#define SWITCH_PORT VPORTB.IN -#define SWITCH_ISC_REG PORTB.PIN2CTRL -#define SWITCH_VECT PORTB_PORT_vect -#define SWITCH_INTFLG VPORTB.INTFLAGS -#endif +// allow using aux LEDs as extra channel modes +#include "chan-aux.h" + +// channel modes: +// * 0. main LEDs +// * 1+. aux RGB +#define NUM_CHANNEL_MODES 2 +enum CHANNEL_MODES { + CM_MAIN = 0, + CM_AUX +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 -#define PWM1_LVL DAC0.DATA // use this for DAC voltage output -// PWM parameters of both channels are tied together because they share a counter -#define PWM1_TOP VREF.CTRLA // holds the TOP value for for variable-resolution PWM +#define PWM_CHANNELS 1 // old, remove this -// For enabling / disabling the HDR high-range channel -#define LED_ENABLE_PIN PIN3_bp -#define LED_ENABLE_PORT PORTB_OUT -#define LED_ENABLE_PIN_LEVEL_MIN 35 -#define LED_ENABLE_PIN_LEVEL_MAX 150 +#define PWM_BITS 8 // 8-bit DAC +#define PWM_GET PWM_GET8 +#define PWM_DATATYPE uint8_t +#define PWM_DATATYPE2 uint16_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint8_t // main LED ramp +// main LED outputs +#define DAC_LVL DAC0.DATA // 0 to 255, for 0V to Vref +#define DAC_VREF VREF.CTRLA // 0.55V or 2.5V +#define PWM_TOP_INIT 255 // highest value used in top half of ramp (unused?) +// Vref values +#define V055 16 +#define V11 17 +#define V25 18 +#define V43 19 +#define V15 20 + +// Opamp enable // For turning on and off the op-amp -#define LED2_ENABLE_PIN PIN7_bp -#define LED2_ENABLE_PORT PORTA_OUT -#define LED2_ON_DELAY 80 // how many ms to delay turning on the lights after enabling the channel +#define OPAMP_ENABLE_PIN PIN7_bp +#define OPAMP_ENABLE_PORT PORTA_OUT +// how many ms to delay turning on the lights after enabling the channel +// (FIXME: 80 is long enough it's likely to cause bugs elsewhere, +// as events stack up unhandled for 5 consecutive WDT ticks) +#define OPAMP_ON_DELAY 80 + +// HDR +// turns on HDR FET for the high current range +#define HDR_ENABLE_PIN PIN3_bp +#define HDR_ENABLE_PORT PORTB_OUT + +// e-switch +#define SWITCH_PIN PIN4_bp +#define SWITCH_PORT VPORTB.IN +#define SWITCH_ISC_REG PORTB.PIN2CTRL +#define SWITCH_VECT PORTB_PORT_vect +#define SWITCH_INTFLG VPORTB.INTFLAGS // average drop across diode on this hardware #ifndef VOLTAGE_FUDGE_FACTOR @@ -54,22 +81,21 @@ #endif // lighted button -#ifndef AUXLED_PIN -#define AUXLED_PIN PIN5_bp -#define AUXLED_PORT PORTB -#endif +#define AUXLED_PIN PIN5_bp +#define AUXLED_PORT PORTB -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead inline void hwdef_setup() { // set up the system clock to run at 10 MHz instead of the default 3.33 MHz - // TODO: for this DAC controlled-light, try to decrease the clock speed or use the ULP - _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); - - VPORTA.DIR = PIN6_bm | PIN7_bm; - VPORTB.DIR = PIN3_bm; + // (it'll get underclocked to 2.5 MHz later) + // TODO: maybe run even slower? + _PROTECTED_WRITE( CLKCTRL.MCLKCTRLB, + CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm ); + + VPORTA.DIR = PIN6_bm // DAC + | PIN7_bm; // Opamp + VPORTB.DIR = PIN3_bm; // HDR //VPORTC.DIR = 0b00000000; // enable pullups on the input pins to reduce power @@ -84,9 +110,10 @@ inline void hwdef_setup() { PORTB.PIN0CTRL = PORT_PULLUPEN_bm; PORTB.PIN1CTRL = PORT_PULLUPEN_bm; - PORTB.PIN2CTRL = PORT_PULLUPEN_bm; + PORTB.PIN2CTRL = PORT_PULLUPEN_bm; //PORTB.PIN3CTRL = PORT_PULLUPEN_bm; // HDR channel selection - PORTB.PIN4CTRL = PORT_PULLUPEN_bm | PORT_ISC_BOTHEDGES_gc; // switch + PORTB.PIN4CTRL = PORT_PULLUPEN_bm + | PORT_ISC_BOTHEDGES_gc; // e-switch //PORTB.PIN5CTRL = PORT_PULLUPEN_bm; // Aux LED PORTC.PIN0CTRL = PORT_PULLUPEN_bm; @@ -97,10 +124,14 @@ inline void hwdef_setup() { // set up the DAC // https://ww1.microchip.com/downloads/en/DeviceDoc/ATtiny1614-16-17-DataSheet-DS40002204A.pdf // DAC ranges from 0V to (255 * Vref) / 256 - VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc + // also VREF_DAC0REFSEL_0V55_gc and VREF_DAC0REFSEL_1V1_gc and VREF_DAC0REFSEL_2V5_gc + VREF.CTRLA |= VREF_DAC0REFSEL_2V5_gc; VREF.CTRLB |= VREF_DAC0REFEN_bm; DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; DAC0.DATA = 255; // set the output voltage } + +#define LAYOUT_DEFINED + diff --git a/spaghetti-monster/anduril/MODELS b/spaghetti-monster/anduril/MODELS index 4195ed0..f4e9fdf 100644 --- a/spaghetti-monster/anduril/MODELS +++ b/spaghetti-monster/anduril/MODELS @@ -76,6 +76,7 @@ Model Name MCU 0716 wurkkos-fc13 attiny1616 0717 wurkkos-ts11 attiny1616 1618 gchart-fet1-t1616 attiny1616 +1630 thefreeman-lin16dac attiny1616 1631 thefreeman-boost21-6a attiny1616 1632 thefreeman-boost-fwaa attiny1616 diff --git a/spaghetti-monster/anduril/cfg-thefreeman-lin16dac.h b/spaghetti-monster/anduril/cfg-thefreeman-lin16dac.h index 2e155ec..20d2bf5 100644 --- a/spaghetti-monster/anduril/cfg-thefreeman-lin16dac.h +++ b/spaghetti-monster/anduril/cfg-thefreeman-lin16dac.h @@ -3,7 +3,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later #pragma once -#define MODEL_NUMBER "0000" // TBD +#define MODEL_NUMBER "1630" #include "hwdef-thefreeman-lin16dac.h" // ATTINY: 1616 @@ -15,35 +15,47 @@ // lockout: blinking (3) #define INDICATOR_LED_DEFAULT_MODE ((3<<2) + 1) -#undef BLINK_AT_RAMP_MIDDLE - -// We're abusing the Dynamic PWM functionality to set the VREF instead of PWM TOP. -// We don't want the Gradual functionality to mess with the PWM_TOP value. -#ifdef USE_SET_LEVEL_GRADUALLY -#undef USE_SET_LEVEL_GRADUALLY -#endif - // level_calc.py ninth 2 150 7135 1 0.03 6.4 7135 1 6.3 1600 -#define RAMP_LENGTH 150 -#define USE_DYN_PWM - -// PWM1: DAC Data, PWM Tops: VREF selector -#define PWM1_LEVELS 25,25,33,41,41,50,58,66,75,83,92,108,117,133,150,167,192,209,234,58,64,71,80,90,99,110,121,134,149,163,180,198,218,241,1,1,1,1,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,5,5,6,6,7,7,8,8,9,10,11,11,12,13,14,15,16,18,19,20,22,23,25,26,28,30,32,34,36,39,41,44,47,50,53,56,59,63,67,71,75,79,84,89,94,100,105,112,118,124,131,139,146,154,163,172,181,191,201,212,223,234,246,57,60,63,66,69,73,76,80,84,88,93,97,102,107,112,117,123,129,135,141,147,154,161,169,176,184,193,201,210,220,229,239,250,255 -#define PWM_TOPS 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18 - -#define MAX_1x7135 34 -#define HALFSPEED_LEVEL 14 -#define QUARTERSPEED_LEVEL 6 - -#define RAMP_SMOOTH_FLOOR 1 -#define RAMP_SMOOTH_CEIL 120 +#define RAMP_SIZE 150 + +// 4 ramp segments: +// - low 0.55V +// - low 2.5V +// - high 0.55V +// - high 2.5V +// PWM1: DAC Data +// FIXME: ramp stalls with 8 duplicate levels in a row +// (maybe use 1.1V Vref during that part of the ramp?) +#define PWM1_LEVELS 25, 25, 33, 41, 41, 50, 58, 66, 75, 83, 92,108,117,133,150,167,192,209,234, \ + 58, 64, 71, 80, 90, 99,110,121,134,149,163,180,198,218,241, \ + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 11, 12, 13, 14, 15, 16, 18, 19, 20, 22, 23, 25, 26, 28, 30, 32, 34, 36, 39, 41, 44, 47, 50, 53, 56, 59, 63, 67, 71, 75, 79, 84, 89, 94,100,105,112,118,124,131,139,146,154,163,172,181,191,201,212,223,234,246, \ + 57, 60, 63, 66, 69, 73, 76, 80, 84, 88, 93, 97,102,107,112,117,123,129,135,141,147,154,161,169,176,184,193,201,210,220,229,239,250,255 +// PWM Tops: VREF selector (0.55V=16,1.1V=17, 2.5V=18, 4.3V=19, 1.5V=20) +#define PWM_TOPS 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, \ + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, \ + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 + +#define MAX_1x7135 34 +#define HDR_ENABLE_LEVEL_MIN 35 // bottom level of top half of the ramp +#define HALFSPEED_LEVEL 255 // always run at 1/4th speed +#define QUARTERSPEED_LEVEL 255 // because DAC doesn't use PWM + +#define RAMP_SMOOTH_FLOOR 1 +#define RAMP_SMOOTH_CEIL 120 // 10, 28, 46, [65], 83, 101, 120 -#define RAMP_DISCRETE_FLOOR 10 -#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL -#define RAMP_DISCRETE_STEPS 7 +#define RAMP_DISCRETE_FLOOR 10 +#define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#define RAMP_DISCRETE_STEPS 7 // stop panicking at ~30% power #define THERM_FASTER_LEVEL 123 // enable 2 click turbo #define DEFAULT_2C_STYLE 1 + +// don't blink mid-ramp +#ifdef BLINK_AT_RAMP_MIDDLE +#undef BLINK_AT_RAMP_MIDDLE +#endif + -- cgit v1.2.3 From 8d04ac9c19a825ac7d4919dd061ba08338145219 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 31 Oct 2023 11:40:00 -0600 Subject: restored original smooth-steps-downward timing; it was just a little bit imbalanced after recent changes --- spaghetti-monster/anduril/smooth-steps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/smooth-steps.c b/spaghetti-monster/anduril/smooth-steps.c index d896251..d907bc1 100644 --- a/spaghetti-monster/anduril/smooth-steps.c +++ b/spaghetti-monster/anduril/smooth-steps.c @@ -28,7 +28,7 @@ void smooth_steps_iter() { // ramp-linear descent // (jump by 1 on each frame, frame rate gives constant total time) uint8_t diff = smooth_steps_start - smooth_steps_target; - uint16_t delay = 1 + (24 * smooth_steps_speed / diff); + uint16_t delay = 1 + (26 * smooth_steps_speed / diff); set_level(actual_level - 1); // TODO? if delay < one PWM cycle, this can look a little weird nice_delay_ms(delay); -- cgit v1.2.3 From 75e2290da9505a4e631e0debf65bdf2da2029e16 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 31 Oct 2023 11:42:00 -0600 Subject: converted fw3x-lume1 to new API, I think (needs testing on actual hardware, and ideally tweaking to improve performance) --- hwdef-fw3x-lume1.c | 60 ++++++++++ hwdef-fw3x-lume1.h | 170 +++++++++++++++++------------ hwdef-noctigon-kr4.c | 1 - hwdef-noctigon-kr4.h | 2 +- spaghetti-monster/anduril/cfg-fw3x-lume1.h | 22 +--- 5 files changed, 168 insertions(+), 87 deletions(-) create mode 100644 hwdef-fw3x-lume1.c diff --git a/hwdef-fw3x-lume1.c b/hwdef-fw3x-lume1.c new file mode 100644 index 0000000..2f31ed0 --- /dev/null +++ b/hwdef-fw3x-lume1.c @@ -0,0 +1,60 @@ +// FW3X Lume1 PWM helper functions +// Copyright (C) 2023 Selene ToyKeeper +// SPDX-License-Identifier: GPL-3.0-or-later +#pragma once + +#include "chan-rgbaux.c" + +void set_level_zero(); + +void set_level_main(uint8_t level); +bool gradual_tick_main(uint8_t gt); + + +Channel channels[] = { + { // channel 1 only + .set_level = set_level_main, + .gradual_tick = gradual_tick_main + }, + RGB_AUX_CHANNELS +}; + + +void set_level_zero() { + CH1_PWM = 0; + CH2_PWM = 0; + PWM_CNT = 0; // reset phase + CH1_ENABLE_PORT &= ~(1 << CH1_ENABLE_PIN); // disable regulator +} + +// single set of LEDs with 2 stacked power channels, regulated + DD FET +void set_level_main(uint8_t level) { + CH1_ENABLE_PORT |= (1 << CH1_ENABLE_PIN); // enable regulator + + PWM_DATATYPE ch1_pwm = PWM_GET(pwm1_levels, level); + PWM_DATATYPE ch2_pwm = PWM_GET(pwm2_levels, level); + + CH1_PWM = ch1_pwm; + CH2_PWM = ch2_pwm; + + // force reset phase when turning on from zero + // (for faster, more consistent initial response) + if (! actual_level) PWM_CNT = 0; +} + +bool gradual_tick_main(uint8_t gt) { + // 150/150 is full FET + zero regulated, + // 149/150 is zero FET + full regulated, + // so don't try to gradually adjust between + if ((RAMP_SIZE == actual_level) || (gt >= RAMP_SIZE-1)) { + set_level(gt + 1); + return true; + } + + PWM_DATATYPE pwm1 = PWM_GET(pwm1_levels, gt); + GRADUAL_ADJUST_SIMPLE(pwm1, CH1_PWM); + + if (pwm1 == CH1_PWM) return true; // done + return false; // not done yet +} + diff --git a/hwdef-fw3x-lume1.h b/hwdef-fw3x-lume1.h index f2e9141..c03248b 100644 --- a/hwdef-fw3x-lume1.h +++ b/hwdef-fw3x-lume1.h @@ -1,5 +1,5 @@ // lume1 Driver Rev B for FW3x driver layout (attiny1634) -// Copyright (C) 2020-2023 (FIXME) +// Copyright (C) 2020-2023 LoneOceans, Selene ToyKeeper // SPDX-License-Identifier: GPL-3.0-or-later #pragma once @@ -8,9 +8,9 @@ * * Pin / Name / Function in Lume1 Rev B * 1 PA6 Regulated PWM (PWM1B) - * 2 PA5 R red aux LED (PWM0B) - * 3 PA4 G green aux LED - * 4 PA3 B blue aux LED + * 2 PA5 R: red aux LED (PWM0B) + * 3 PA4 G: green aux LED + * 4 PA3 B: blue aux LED * 5 PA2 e-switch (PCINT2) * 6 PA1 Jumper 1 * 7 PA0 Jumper 2 @@ -30,36 +30,57 @@ * ADC12 internal thermal sensor (not used for lume1) * * Main LED power uses one pin as a global Buck Boost Enable, and - * one pin to control the power level via PWM. Another pin is used - * for FET control. + * one pin to control the power level via PWM. + * Another pin is used for DD FET control. */ -#ifdef ATTINY -#undef ATTINY -#endif #define ATTINY 1634 #include -#define PWM_CHANNELS 2 -// Added for Lume1 Buck Boost Driver -#define PWM_BITS 10 // 0 to 1023 at 3.9 kHz, not 0 to 255 at 15.6 kHz -#define PWM_TOP 1023 +#define HWDEF_C_FILE hwdef-fw3x-lume1.c -#define SWITCH_PIN PA2 // pin 5 -#define SWITCH_PCINT PCINT2 // pin 5 pin change interrupt -#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] -#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] -#define SWITCH_PORT PINA // PINA or PINB or PINC +// allow using aux LEDs as extra channel modes +#include "chan-rgbaux.h" + +// channel modes: +// * 0. main LEDs +// * 1+. aux RGB +#define NUM_CHANNEL_MODES (1 + NUM_RGB_AUX_CHANNEL_MODES) +enum CHANNEL_MODES { + CM_MAIN = 0, + RGB_AUX_ENUMS +}; + +#define DEFAULT_CHANNEL_MODE CM_MAIN -#define PWM1_PIN PA6 // pin 1, Buck Boost CTRL pin or 7135-eqv PWM -#define PWM1_LVL OCR1B // OCR1A is the output compare register for PA6 +// right-most bit first, modes are in fedcba9876543210 order +#define CHANNEL_MODES_ENABLED 0b0000000000000001 -#define PWM2_PIN PB3 // pin 16, FET PWM Pin, but only used as on (1023) or off (0) -#define PWM2_LVL OCR1A // OCR1A is the output compare register for PB3 + +#define PWM_CHANNELS 2 // old, remove this // Added for Lume1 Buck Boost Driver -#define LED_ENABLE_PIN PA7 // pin 20, BuckBoost Enable -#define LED_ENABLE_PORT PORTA // control port for PA7 +#define PWM_BITS 16 // 0 to 1023 at 3.9 kHz, not 0 to 255 at 15.6 kHz +#define PWM_GET PWM_GET16 +#define PWM_DATATYPE uint16_t +#define PWM_DATATYPE2 uint32_t // only needs 32-bit if ramp values go over 255 +#define PWM1_DATATYPE uint16_t // regulated ramp +#define PWM2_DATATYPE uint16_t // DD FET ramp + +// PWM parameters of both channels are tied together because they share a counter +#define PWM_TOP ICR1 // holds the TOP value for variable-resolution PWM +#define PWM_TOP_INIT 1023 +#define PWM_CNT TCNT1 // for dynamic PWM, reset phase + +// regulated channel +#define CH1_PIN PA6 // pin 1, Buck Boost CTRL pin or 7135-eqv PWM +#define CH1_PWM OCR1B // OCR1B is the output compare register for PA6 +#define CH1_ENABLE_PIN PA7 // pin 20, BuckBoost Enable +#define CH1_ENABLE_PORT PORTA // control port for PA7 + +// DD FET channel +#define CH2_PIN PB3 // pin 16, FET PWM Pin, but only used as on (1023) or off (0) +#define CH2_PWM OCR1A // OCR1A is the output compare register for PB3 /* // For Jumpers X1 to X4, no SW support yet #define JUMPER1_PIN PA1 @@ -68,8 +89,17 @@ #define JUMPER4_PIN PC4 */ -#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened -#define VOLTAGE_PIN PB0 // Pin 19 PB0 ADC5 +// e-switch +#define SWITCH_PIN PA2 // pin 5 +#define SWITCH_PCINT PCINT2 // pin 5 pin change interrupt +#define SWITCH_PCIE PCIE0 // PCIE0 is for PCINT[7:0] +#define SWITCH_PCMSK PCMSK0 // PCMSK0 is for PCINT[7:0] +#define SWITCH_PORT PINA // PINA or PINB or PINC +#define SWITCH_PUE PUEA // pullup group A +#define PCINT_vect PCINT0_vect // ISR for PCINT[7:0] + +#define USE_VOLTAGE_DIVIDER // use a dedicated pin, not VCC, because VCC input is flattened +#define VOLTAGE_PIN PB0 // Pin 19 PB0 ADC5 // pin to ADC mappings are in DS table 19-4 #define VOLTAGE_ADC ADC5D // digital input disable pin for PB1 // DIDR0/DIDR1 mappings are in DS section 19.13.5, 19.13.6 @@ -119,52 +149,54 @@ #define AUXLED_RGB_DDR DDRA // DDRA or DDRB or DDRC #define AUXLED_RGB_PUE PUEA // PUEA or PUEB or PUEC -// with so many pins, doing this all with #ifdefs gets awkward... -// ... so just hardcode it in each hwdef file instead // For lume1 driver, no SW support for Auxillary Jumpers X1 to X4 yet! inline void hwdef_setup() { - // enable output ports in Data Direction Registers - // FET PWM Pin - DDRB = (1 << PWM2_PIN); - // Main PWM, Buck Boost Enable Pin, aux R/G/B - DDRA = (1 << PWM1_PIN) - | (1 << LED_ENABLE_PIN) - | (1 << AUXLED_R_PIN) - | (1 << AUXLED_G_PIN) - | (1 << AUXLED_B_PIN) - ; - //DDRB&=~(1< 7C" to change aux LED settings) +- Changed RGB button behavior: While torch is on, use low mode below a + configured level for real-time voltage color display, instead of always + using high mode +- Fixed bug: Channel change could stick when activating a config menu from + battcheck (the blink function changed the channel, then the config menu + saved it, then the blink function restored it, then the config menu restored + it to the value it saved, which was wrong) +- Documented ramp 6C, ramp 4C, ramp 4H, lockout 3H, battcheck 3C, and post-off + voltage display config +- @emisar-d4v2: Added the rest of the aux RGB colors as channel modes, and set + aux "white" as the mode it uses to blink out numbers (0113, 0114, 0115, + 0123) +- @wurkkos-ts10: Converted to multi-channel, and gave it a new ramp with + better low modes (0714) +- @wurkkos-ts25: Converted to multi-channel, and gave it a smoother ramp + (0715) +- @wurkkos: Added Wurkkos FC13 and TS11 (0716, 0717) + +# 2023-04-29 + +- Changed lockout mode: + - Fixed manual memory timer and tint + - Added 3H for next channel (to change channels without unlocking, was + possible before but needed to be updated for the new channel system) + - Made 3H+ use mem level instead of lowest moon (this is needed for + making the channel discernible, and also helps make aux LED controls + stand out more) +- @emisar, @noctigon: Added Extended Simple UI to Hank's config, so a few more + features are allowed in simple mode +- @emisar-d4v2, @noctigon-kr4: Slightly smaller ROM size +- @emisar-d4sv2: Converted to multi-channel, and updated it to use dynamic PWM + for a smoother ramp with lower lows (0133, 0134) +- @noctigon-kr4: Converted to multi-channel (0211, 0212, 0213, 0214) +- @noctigon-kr4: Don't blink at top of regulated power (0211, 0213, 0214) + +# 2023-04-28 + +- Added voltage display (by color) on RGB aux LEDs after turning the main LEDs + off +- Changed RGB aux: Always preview in high mode while changing color or pattern +- Changed default RGB aux color in lockout mode: Uses blinking voltage, + instead of blinking disco (unless model-specific config defines a different + default) +- Changed tactical mode default config: only use 2-color strobe if it's on + main LEDs, not aux LEDs +- @emisar-d4v2: Smoother ramp (0113, 0114) +- @emisar-d4v2: Added hidden channel modes for RGB aux LEDs (0113, 0114, 0115) + +# 2023-04-27 + +- Changed channel mode menu to preview channels during configuration +- Changed tactical mode default config: use 2-color police strobe if it + exists, instead of single-color strobe +- Fixed unnecessary flickering when changing channel modes from/to the same + value +- Fixed sleep voltage measurement on attiny1616 +- @noctigon-kr4-tintramp: Converted to multi-channel, renamed to + noctigon-kr4-2ch (0215) + +# 2023-04-25 + +- Fixed old old bug(s) with voltage measurement while asleep, while also + adding other improvements: + - Fixed oscillating RGB aux colors while asleep in voltage mode, mostly. + Some much smaller oscillations are still possible, but the primary issue + has been fixed, I think. + - Fixed old old bug which could cause spurious low-voltage warnings while + asleep (previously required a messy code workaround). + - Reduced avg standby power by ~15uA. + - Now measures voltage every 1s instead of 8s while asleep. + - Changed RGB aux behavior: Puts aux LEDs in high mode for 3 seconds after + light goes to sleep (much easier to see the voltage this way) + (this change was obsoleted soon by a better post-off voltage display) + - Broke sleep voltage measurement on attiny1616 (oops) +- Changed internal details for how gradual ramping works +- @emisar-d4sv2-tintramp: Converted to multi-channel, renamed to emisar-2ch. + (0135) +- @sofirn-lt1s-pro: Updated to use today's new code internals (0623) + +# 2023-04-19 + +- Added stepped tint ramping +- Documented new channel modes system +- @sofirn-lt1s-pro: Added white-only auto-tint mode (0623) + +# Older: TODO + +- Need to import old commit logs as changelog items + + + + -- cgit v1.2.3 From bb81bf19fa16b3f5c3419a4c0be23e41b7507ced Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Tue, 31 Oct 2023 15:40:45 -0600 Subject: slightly longer smooth-off animation, to make on and off feel symmetrical --- spaghetti-monster/anduril/smooth-steps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spaghetti-monster/anduril/smooth-steps.c b/spaghetti-monster/anduril/smooth-steps.c index d907bc1..9631e41 100644 --- a/spaghetti-monster/anduril/smooth-steps.c +++ b/spaghetti-monster/anduril/smooth-steps.c @@ -28,7 +28,7 @@ void smooth_steps_iter() { // ramp-linear descent // (jump by 1 on each frame, frame rate gives constant total time) uint8_t diff = smooth_steps_start - smooth_steps_target; - uint16_t delay = 1 + (26 * smooth_steps_speed / diff); + uint16_t delay = 1 + (30 * smooth_steps_speed / diff); set_level(actual_level - 1); // TODO? if delay < one PWM cycle, this can look a little weird nice_delay_ms(delay); -- cgit v1.2.3