E-switch UI Development / FSM

The FW3A has 8 7135s.

It does have 8. 1 in a single channel and 7 in the other channel. It is a 1+7+fet driver. If starting at 1 level moon there is a blip fairly quickly, then another and then ramp top.

It may be just a terminology difference, but here’s how I’ve been using the words:

  • Frame: One timer tick, or about 16ms. There are ~62 frames per second.
  • Blip: Turning off for less than one frame, as a visual indication that something happened. For example, when passing a reference point on the ramp.
  • Blink: Turning on (or going to a brighter level) for a short time, to indicate that something happened. For example, when entering or exiting lockout mode.
  • Buzz / flicker: Switching between two brightness levels quickly (but still slow enough to clearly see). Similar to a strobe, but nowhere near as intense. This is used to indicate that the light is waiting for input from the user.
  • Strobe: Turning on and off completely at a speed of ~4 Hz to ~100 Hz. This is used to irritate people.

Anduril on the FW3A does up to four blips while ramping up from the lowest to highest level. Hold from off, and these blips may happen:

  • At ~0.4s, to indicate the button has been held long enough to count as a “hold” instead of a “click”. Let go immediately to stay at the floor level, or keep holding to ramp up.
  • At ~1.5s, when going from 1x7135 chip to 1+7x7135. Happens at ~130 lm.
  • At ~2.5s, when going from 8x7135 to 8+FET. Happens at ~900 lm.
  • At the top end of the ramp, to indicate the ceiling has been reached.

However, depending on where the floor and ceiling are configured, the two middle ones may or may not actually happen. Or they may be at exactly the same level as another blip, in which case only one happens. In the default configuration, the 8x7135 to FET blip is the same level as the ceiling, so only one happens.

It also buzzes or flickers in the ramp config mode, to tell the user when they can click to enter a new value. It goes for 3 seconds, or until the user stops clicking for at least 3 seconds. Each click is confirmed by a blink.

Unrelated question: I'm trying to set double click from off to turbo instead of max ramp.

I've taken this line from the double click from on section of the code: "set_level(MAX_LEVEL);"

And I've added it to the double click from off section of the code, to change it from this:

" else if (event == EV_2clicks) { set_state(steady_state, MAX_LEVEL); return MISCHIEF_MANAGED;

To this: " else if (event == EV_2clicks) { set_state(steady_state, MAX_LEVEL); set_level(MAX_LEVEL); return MISCHIEF_MANAGED;"

This seems to work, but I don't understand why. And I couldn't find any other references to MAX_LEVEL in the main code, though now that I think of it it's probably in FSM somewhere.. hmm.

Anyway, is this the correct implementation?

Adding a set_level(MAX_LEVEL) right after changing the state works right now, but it’s not guaranteed to work in the future. The reason why it works is due to a quirk of the execution order:

  1. set_state() tells FSM to replace the top of the state stack with something new.
  2. FSM handles this immediately, causing the new state’s EV_enter handler to be called.
  3. steady_state :: EV_enter calculates the brightness to use by calling nearest_level() . It also activates this brightness level.
  4. Control returns to the old state for just a moment, where it calls set_level() and overrides what steady_state just did.

But this isn’t guaranteed, because at some point the lower-level code might be changed to defer the EV_enter event handler until after the old state returns. Events are asynchronous, so their exact timing should not be expected to happen with any particular order or timing. It behaves in a synchronous manner in this case, but it might not always be that way. FSM probably should do this instead:

  1. set_state() tells FSM to replace the top of the stack, so FSM puts this change into the queue to handle later.
  2. off_state()’s code finishes running and returns.
  3. FSM handles the state change event. off_state :: EV_exit gets called, then steady_state :: EV_enter, in that order.

So it might instead be cleaner or safer to remove or change the clause which checks the brightness while entering the steady state. Like, if the EV_enter parameter happens to equal turbo, go to that directly instead of using nearest_level() to verify the values. This would work even if I fix FSM to make it queue state changes instead of doing them immediately.

Some recent updates which are now published:

  • Added a compile-time option to select between press-on and release-on, and between release-off and timeout-off. This determines when the light responds to a single click to turn the light on or off… responding at button press, at button release, or at the event timeout. This has been requested quite a bit.
  • Changed the default turn-on timing from press-on to release-on. This makes it easier to tell when to let go for staying at the lowest level, because the light doesn’t turn on before then. (when compiled with press-on, it’ll still have the moon timing hint)
  • Made the button release timeout a bit faster, so the light should turn off a bit sooner after one click. Also, any multi-click events need to be done slightly faster, but it should still be easy to do. The timing now matches Olight’s products instead of ZebraLight. (went from ~384ms to ~288ms, or from 24 frames to 18 frames)
  • Added a user-configurable runtime option to switch between automatic memory (default) and manual memory. Some people call this “no memory” or “forced preset”. In manual mode, one click from off turns on at the same level each time, regardless of what level it was in during the previous session. To configure it:
    • Turn the light on and ramp to the desired level, then click 5 times. This enables manual memory and saves the current brightness level.
    • To go back to automatic memory, turn the light on then click 5 times… but hold the last click. So, click-click-click-click-hold.
  • Added support for the Fireflies E01.
  • Added support for the BLF LT1 lantern. Included in this is support for tint ramping.
  • Rewrote thermal regulation. It doesn’t seem to need the hard turbo drop option any more, and it’s much more stable when it reaches its ideal level.
  • Made ramp-able strobe modes auto-reverse like the regular ramping mode. So, after holding to adjust, releasing and holding again within a second goes the other way.
  • Enabled fancy (2-level) momentary moon by default in lockout mode. The second click uses the other ramp floor. So if you need a bit more (or less) light during lockout, it’s available.
  • Made momentary mode support strobes. To do this, go to a strobe mode, turn the light off, then start up momentary mode. Or, to do a regular momentary mode, go to a regular ramp level, then turn the light off, then start up momentary mode. Basically, it’ll do momentary in whatever mode you were just using, as long as it was a ramp or a strobe-group mode. Momentary strobes are useful for light painting.
  • Made candle mode a little more calm but also able to burn a bit brighter sometimes.
  • Fixed a tiny bug in lightning mode (it didn’t use the top 7 ramp levels before).

New builds are up in the usual place. I count 19 different build targets now.

If anyone has the ability to reflash easily, testing is appreciated. :slight_smile:

Thank you!


First off, thanks for the insight on double click turbo from off. I’ll admit this is a bit like sorcery to me, so it’s gonna take me a few re-reads to parse out and fully understand what you’re talking about.

Secondly, I finally got around to flashing my FW3A last night. I wanted fancy moon lockout mode. Before I built the hex I thought… I should probably merge the latest fsm just in case. And then when I went to enable fancy moon I seen it was already enabled by default! Took me by surprise, I had to make sure I didn’t mix up my files. I figured you had enabled it by default now, which is pretty cool.

But then this morning, I just read your change log here, and DANG! I was literally sitting on my couch with my FW3A, giggling as I tried every new feature that I didn’t even realize I flashed last night haha.

You’re the best, and your changes to the code have solved many problems. Most recently one friend had been bothered by the thermal regulation on his D4, does this solve that thermal problem as well? Or alleviate it? I suppose I’ll flash it to test it for you best I can as well.

Also another friend had been confused by the ramp in strobe modes, but now that is much more intuitive, thanks!

Of course momentary strobes seem fun, and candle and lightning mode are already awesome, but it’s nice to see them receiving tweaks.

I don’t have much use for the button mode timing options and such, I’ll just trust your opinion on the defaults, but I’m glad the option is there.

Anywho, I guess I’m one of the first to test your newest revision haha. I’ll let you know if I find any trouble!

Sorry if this is a bit too flattering, but honestly, thank you for your hard work. You rock!

Edit: ah, it seems I merged before your final revision. I don’t have the use_Manual_memory enabled apparently. Well I guess I know what’s next, I’ll be reflashing this FW3A lol

Two days ago I flashed Anduril build from 22-05, on Sofirn Q8 and now we have a new one, with even more features. I guess I’m flashing it again :slight_smile: Thanks for the update ToyKeeper!
I configured thermal stepdown to 45 degrees, but flashlight temperature goes up to 52 degrees by it’s own readings. Sadly battery of my IR thermometer died and can’t check body temperature on the fly. Anyway I like the idea about manual memory and 2 more lockout. I had no problems with shortened button release timeout, at least by now.
I wonder how hard is to flash firmware on PL47 and E07. It has 7 pins on the driver spring’s side, I assume they are used for that, am I right?

I love manual memory!
Thank you TK!!!

But I’ve got a very important question:
Does removing power reset manual memory?

I should probably make another option for this. It has come up a couple times. Normally, people can make double-click-from-off-to-turbo work by setting the ceiling level as high as it can go… but some have wanted a lower ceiling while having the shortcut go to full power instead of the ceiling.

I’m not really sure. I still need to take apart a sacrificial D4 to reflash it and run thermal tests… or fix the last one I killed this way. It works on FW3A though, which has fairly similar behavior.

Thanks! I don’t want to merge this stuff into trunk until a few people have tried it.

Sorry for the rapid churn. At least the Q8 is easy to flash. :slight_smile:

It’ll run at turbo for at least a few seconds even if it’s too hot. After that, the results depend on how fast it can reach a stable level. Regardless, I expect it’ll typically exceed the temperature limit for a short time initially before it settles at the desired temperature.

If you have the right pogo pin adapter, flashing a PL47 is really easy. E07 may require unsoldering the aux LED board though, since it can interfere with reflashing. I’d definitely try it first, but if it doesn’t work, the aux LED board is probably the reason why.

I hope I can get someone to make the pogo pin adapters available commercially, because they’re really useful and most new BLF-related lights coming out support it now.

No. It saves the manual memory info to eeprom. So if manual memory is enabled, loosening/tightening the tailcap won’t go to the default 1x7135 level. That’s only available while using automatic memory. However, you could save that level to the manual memory slot, or configure the stepped ramp so one of the steps hits that level exactly…

Here is a comparison of the new candle mode vs the old

The way you implemented it is great, I don’t want to reset light config every time I.change battery. :slight_smile:

I played around with the new update and I love it! Finally Anduril works the way I prefer - release-on, release-off, no moonlight and no delays. :slight_smile:
Did not run into any bugs. Just one note: muggle mode still does press-on, timeout-off.

My favourite Anduril feature: The short blink on moonlight which was very good on the ROT66 is almost unnoticeable in the FWA3 completely missing it’s point. It that fixed in this new “update”?

Ive played around with the candle modes for a while, and im still trying to get used to the FW3A version with the higher brightness fluctuations. Ive been a heavy user of it since the D4S pretty much came out but I havent flashed my D4S in probably 7-8 months. The FW3A is definitely more flame like and realistic, but sometimes it subjectively feels too active.

Either way, FSM and Anduril are amazingly functional pieces of code and theres no way I could have written them myself so no complaints.

Oh yeah, I didn’t change muggle mode. I should probably put that on the todo list.

You mean the moon timing hint?

At some point in the past few months, I increased the duration of that to make it a bit more visible… but it’s still hard to see on some lights. It went from 8ms to 12ms, but that’s still pretty quick. It can’t really get much longer without interfering with other things, since each frame is only 16ms long.

When using “B_TIMING_ON = B_RELEASE_T” (turn on at button release instead of button press), the moon timing hint is gone entirely. It serves no purpose with release-on timing, because the LED doesn’t even light up until it has been long enough to count as a “hold”. So this helps on lights where the timing hint is hard to see.

Yes. Strange it works nicely on the ROT66 but not on the FWA3.

Hi ToyKeeper, IRL software tester here to let you know that I haven’t noticed any issues with the latest version of Andúril (yet!)

I have only been messing with it for around 10 minutes, but so far I am loving the release-on behaviour. Moonlight is much easier to land on now, without accidentally blasting a few hundred to a few thousand lumens instead.

Momentary and reverse ramping strobes are a brilliant addition. I need to have a go at light painting now that I have a good enough excuse. The new, calmer candle mode looks really good too. I use candle a lot, and I don’t think that’s going to change any time soon.

That 2 level lockout functionality is brilliant. Moonlight is rarely sufficient in my normal use, so I was somewhat discouraged from using lockout. Now I have it so that I can single click for momentary moon, or double click for momentary 60 lumens. Perfect! On those occasions where I just quickly need some light, lockout is no longer a hindrance.

I noticed that the ability to switch between automatic and manual memory was enabled by default too. When I was reading about the changes I though you meant it would be disabled, however sure enough I was able to set the fully regulated level on my D4S as the level that the flashlight always switches on into with a single click. I wasn’t sure I’d like this, but it’s really growing on me quickly. I like having the ability to swap between automatic and manual memory on the fly, too.

All in all, fantastic update TK! I haven’t tried tearing a light apart to flash it yet (D4S with flashing holes is ez mode), but I might have to give it a go with my FW3A at some point. :smiley: