Anduril ... 2?

This is necessary so that the light blinks out the correct battery voltage. By default it might be off by up to 0.2 V.

is the Anduril firmware the same in the FWAA w SST-20, as in the FWAA w 219c?

I ask because I will probably end up modding the LEDs to 219b, regardless which one I buyā€¦

I know it makes a difference in some of the other Anduril lightsā€¦ that the 219c and E21a models have power limits that are different than for some of the other LEDs.

Iā€™ve got the SST20 4k, 219c 3k and 219c 4k and the UI is the same on all three.

Ok thank youā€¦I was trying functions only from the ON sections and I didnā€™t see the upper part

Anyone know which anduril 2 hex file I need to flash a d4v2 with kr4 driver? Thanks!

Yes, the file for the KR4. The code for the lit button has also been incorporated into it.

Does anyone know if there is a possibility to update the Lumintop X9L (with SBT90.2) firmware to Anduril 2? Is there a ready made hex file to download? Also, has anyone removed the driver retaining ring? Is the cables long enough to twist the driver around and put a clamp on the chip to reprogram it? The bezel is glued so it may not be easy / possible to unsolder the cables from the MCPCB.

I didnā€™t follow the whole thread so iā€™m askingā€¦

Is there a way to set A2 to a simple on/off mode, and is it fool proof - like you can long click or go click happy without upsetting anything?

Thank you.

Yes, tactical mode (only on when holding the switch, remove power to leave that mode). Otherwise: no.

Iā€™ve noticed a couple of behaviours with my DT8 that Iā€™m not sure are expected. The light was bought about 3 weeks ago.

1. Hybrid memory

With hybrid memory enabled on a 2-minute timer, and my memorised mode set to the bottom of the ramp (i.e. turn the light on with a 1H and then 10C to save the level), I would expect the behaviour to be the following given my understanding of hybrid mode:

1. Turn the light on and ramp to a high value.
2. Turn the light off.
3. Turn the light on within 2 minutes, light goes to the high ramped value.
4. Wait more than 2 minutes.
5. Turn the light on, moonlight
6. Turn the light off
7. Turn the light on, moonlight.

However, what I see happen is the following:

1. Turn the light on and ramp to a high value.
2. Turn the light off.
3. Turn the light on within 2 minutes, light goes to the high ramped value.
4. Wait more than 2 minutes.
5. Turn the light on, moonlight
6. Turn the light off
7. Turn the light on, high ramped value.

That is to say, the first time I turn on after the 2 minutes has elapsed the light starts on the memorised moonlight level, but subsequent off->on switches go back to the value that I ramped to.

Is that behaviour expected? It seems inconsistent with my understanding of how hybrid mode works.

2. Momentary Turbo

Occasionally, with the light on, if I enter momentary turbo (3H) the light doesnā€™t return to the value that it was at before the momentary turbo - it sometimes ends up at some other higher value. Usually it returns to the original value, but occasionally (say, 10% of the time) it ends up dropping back to something else. Unfortunately I canā€™t reproduce this reliably so I donā€™t know what the trigger is, but has anyone else noticed this behaviour?

Since Iā€™m interested in keeping up-to-date, I figured Iā€™d set up a custom build with all my preferences baked in instead of having to reconfigure every time. I also prefer Anduril 2ā€™s original behavior without USE_2C_MAX_TURBO, which isnā€™t a runtime configuration option, so I have to build from a modified source tree anyways for the Emisar/Noctigon lights I have.

ā€”

However, it doesnā€™t look like itā€™s possible to enable the auto-lockout timer by default via a configuration #define - could this be changed?

My guess (not compile-tested) would be the following: modify lockout-mode.h, replacingā€¦

uint8_t autolock_time = 0;

ā€¦withā€¦

#ifndef AUTOLOCK_TIME
#define AUTOLOCK_TIME 0 // autolock time in minutes, 0 = disabled
#endif
uint8_t autolock_time = AUTOLOCK_TIME;

EDIT 2021-7-12: Iā€™ve proposed the autolock change as a merge request on Launchpad

ā€”

Iā€™m also enabling a slower Noctigon KR4 ramp near moonlight, which for me significantly improves how easy it is to pick a specific low brightness, inspired by kr4 slow bottom ramp, default 10 min autolock by mkong1 Ā· Pull Request #18 Ā· mkong1/anduril Ā· GitHub which was referenced at Reddit - Dive into anything - perhaps this should be considered an official default?

#define HALFSPEED_LEVEL 14
#define QUARTERSPEED_LEVEL 6

EDIT 2021-7-12: Disregard this, Iā€™ve implemented this properly below.

ā€”

Regardless, thank you for Anduril 2 - I love it! I like the configuration change to turbo mode (ramp ceiling has meaning now). I could see why others donā€™t though, hence maybe making it a runtime configuration option. Regardless, Iā€™m happy with custom builds, and thereā€™s something really nice about having the power to modify and reflash flashlight firmware :slight_smile:

HALFSPEED_LEVEL and QUARTERSPEED_LEVEL are for dynamic underclocking. Or do they slow the ramping speed as well ?

Thatā€™s a fair point. I hadnā€™t realized HALFSPEED_LEVEL and QUARTERSPEED_LEVEL were for dynamic underclocking, so in hindsight this might have unexpected effects elsewhere.

It does appear to slow down ramping at lower brightness levels, and Anduril itself doesnā€™t appear to have any specific code for setting the ramp speed outside of USE_SET_LEVEL_GRADUALLY (which code says is only for thermal regulation). After reading through spaghetti-monster.txt, my understanding is that slowing down the EV_tick rate from the default of roughly 62.5 Hz affects EV_click1_hold as well (ā€œThis event is sent once per timer tick as long as the button is heldā€), which reduces the frequency with which the following code in ramp-mode.c is called that actually ramps up or down:

memorized_level = nearest_level((int16_t)actual_level + (step_size * ramp_direction));

An immediate side-effect of this I see is the earlier if-condition of (arg % HOLD_TIMEOUT != 0) in ramp-mode.c for discrete ramping, potentially resulting in slowing down the discrete ramp stepping too (ā€œthe ā€˜argā€™ value indicates how many timer ticks since the button state went from ā€˜pressā€™ to ā€˜holdā€™.ā€).

If itā€™s more proper to add ā€œniceā€ delays directly in ramp-mode.c, thatā€™s fine! Iā€™m still learning how Anduril and the overarching FSM project work.

EDIT: It looks like another option would be to add delays to smooth ramping by mimicking the stepped ramp delay, as noted here for the D4V2 with KR4 driver: https://reddit.com/r/flashlight/comments/o3qrf2/d4v2_ramp_is_too_fast_can_it_be_fixed_with_a/h2g9vj4?context=3

That would be extra code compared to adjusting the dynamic underclocking, and Iā€™m not sure which approach is more ā€œproper.ā€

You can set autolock to a default time. See here: Anduril ... 2? - #696 by trakcon

Thanks for the heads up! Thatā€™s pretty close to what Iā€™m currently doing, and itā€™s good to have it documented here, too.

In hindsight, I should have been more clear that Iā€™m asking if ToyKeeper would be willing to consider making the default value of autolock_time configurable via #define AUTOLOCK_TIME or such, much like how RAMP_STYLE is handled in ramp-mode.h.

This is not at all required, itā€™d merely make it more convenient to update.

EDIT 2021-7-12: Iā€™ve proposed the autolock change as a merge request on Launchpad

ā€”

For context, my current workflow with it being a modification to lockout-mode.h looks like this:

cd anduril2/ToyKeeper/spaghetti-monster/anduril/
make clean
bzr revert ā€”no-backup version.h
bzr revert ā€”no-backup lockout-mode.h # Revert patch for lockout-mode.h
bzr pull
patch ā€œlockout-mode.hā€ ā€œ[other directory]/autolock-10min-by-default.patchā€ # Apply patch for lockout-mode.h
make all

Iā€™ve already created digitalcircuit-cfg.h (modeled after hank-cfg.h) which is #included by cfg-emisar-d4sv2-digitalcircuit-w2.h and cfg-noctigon-kr4-nofet-digitalcircuit-e21a-2700k.h. Both of my custom cfg~~[ā€¦].h files also #include the original official cfg~~[ā€¦].h files, meaning thereā€™s no conflicts with fetching source updates and Iā€™ll get all changes that I donā€™t specifically override (I #undef any conflicting #defines).

With #define AUTOLOCK_TIME, there would be no need to revert a patch (that could break if lockout-mode.h is modified) then apply it again after updating.

ā€”

Pie-in-the-sky would be a way to read out the temperature calibration value so I could compile that in too, no need to redo it on every flash. Iā€™ll look into this at some point. If any flashlight manufacturer precalibrates their temperature sensor, it could be useful to have an official way to bake in the offset and disable factory-reset auto-calibration, too.

Separating out the ā€œpie-in-the-skyā€ comment at the end of my last post, this is a third, larger but hopefully more universally useful change idea:
Make Anduril 2 able to ā€œdisplayā€ saved configuration values/clicks

Ever configure a flashlight, make some changes you like, but not write them down elsewhere, so by the time you flash a new firmware version in 5 months you donā€™t remember the ramp ceiling, floor, temperature limit, autolock timer, etc? Enter the configuration menu, but instead of clicking when itā€™s ā€œbuzzingā€, click-and-hold to cause the light to blink out the current value using the same technique as the blinky mode for displaying voltage/temperature.

For things like the hybrid memorized level timer, this allows canceling if someone entered it then wished to exit (a zero value doesnā€™t cancel changes, unlike most other configuration entries).

This would also add a way to read temperature offset for anyone who flashes new firmware often.

ā€”

More concretely, this would involve modifying number_entry_state() in config-mode.c to handle else if (event == EV_click1_hold_release) { [ā€¦], switching to displaying the current configuration value, which would be passed up through config_state_base() from any function that calls it.

For almost all entries (ramp floor/ceiling, discrete ramp steps, temperature limit, autolock timer, etc), itā€™d blink the number of times you clicked to get the same config value. Example: a ramp ceiling configured to 120 down from 150 would blink 3 times, pause, then blink 1 time - same technique as displaying voltage/temperature, blink_num() from fsm-misc.c.

For temperature calibration (not limit), itā€™d blink the current internal temperature offset value therm_cal_offset, since the number of clicks to calibrate is relative to the current temperature (knowing youā€™d click 20 times when itā€™s currently 20 degrees Celsius isnā€™t new/useful information).

Additionally, functions that call config_state_base() would need some indication that the new value shouldnā€™t be saved, e.g. by setting number_entry_value to the maximum uint8_t value, #define CONFIG_CANCELED 255 (Iā€™m unsure if clicking 255 times is used anywhere).

(Zero canā€™t be used as itā€™s a valid option for the hybrid memory configuration menu.)

ā€”

I might be able to implement this with enough fumbling about, but it seemed wise to float the idea here first to see if itā€™d be a good idea, if thereā€™s concerns about code size, etc. As Iā€™m very new to FSM and Andurilā€™s codebase, I may be overlooking potential pitfalls.

EDIT 2021-7-12:
I overlooked that config_state_base() handles multiple configuration entries. Itā€™d need to have the full list of current configuration values passed into it as an array of some sort.

This sounds more memory/storage intensive; if possible, feedback on this design would be appreciated before attempting these larger changes.

EDIT 2021-7-13:
Alternatively, another function pointer could be passed in to config_state_base() (perhaps loadfunc) that would fetch the current configuration value for a given step number. Iā€™m not sure which is more program data and RAM efficient given the constraints of low-cost microcontrollers.

ā€”

Aside, I hope Iā€™m not annoying anyone with these replies. Iā€™m excited about Anduril 2 and having two flashlights running it.

I like this idea.

I just tested this by measuring the ramp duration with my scope at 10MHz (no underclocking), 5MHz (halfspeed), and 2.5MHz (quarterspeed), no change in the speed of the ramp whether itā€™s smooth or stepped ramp.

But I think this would be very a useful option to have because this would be much quicker than modifying the ramp which is time consuming, especially for drivers with extremely low moonlight like I making.

Thank you for testing this with your scope! I guess I tricked myself into thinking the underclocking had made a change.

Iā€™ve implemented a new version inspired by the stepped-ramping delay code for slowing down smooth ramping - if/when youā€™ve got the time and interest, would you give it a try?
Merge [ā€¦] anduril2_opt_ramp_low_slower into lp:~toykeeper/flashlight-firmware/anduril2

As noted on the merge request, Iā€™m unsure if this is the best approach - Iā€™m happy for ToyKeeper to modify it, request changes, or go about it entirely differently. The alternative of modifying the ramp with level_calc.py might unnecessarily inflate the number of identical levels (e.g. when customizing ramp floor).

For my KR4-nofet custom test build atop this change, Iā€™ve put a #define RAMP_SMOOTH_HALFSPEED_LEVEL 14 which seems decent, though other values are likely fine, too.

Iā€™ve also submitted for review the #define DEFAULT_AUTOLOCK_TIME feature I had mentioned earlier.

EDIT 2021-7-12:

Tinkering with level-calc.py, I uncommented the pwm_max question and tried recreating the KR4 ramp according to the comment in cfg-noctigon-kr4-nofet.h, and the cubic ramp actually would provide greater control in the lowest power levels as well:

With that in mind, Iā€™m wondering if ToyKeeper or Hank intentionally opted to remove some of the levels near the bottom of the ramp.

It works as described, exactly 2 and 4 times the ramp duration :+1: