From 7cb4fe0944b839f28dfd96a88a772cd6a8b58019 Mon Sep 17 00:00:00 2001 From: Selene ToyKeeper Date: Thu, 2 Nov 2023 17:16:25 -0600 Subject: reorganized project files (part 1) (just moved files, didn't change the contents yet, and nothing will work without updating #includes and build scripts and stuff) --- ui/rampingios/Makefile | 7 + ui/rampingios/build-all.sh | 13 + ui/rampingios/rampingios-v3.html | 501 +++++ ui/rampingios/rampingios-v3.md | 262 +++ ui/rampingios/rampingios-v3.txt | 324 +++ ui/rampingios/rampingiosv3-ui.png | Bin 0 -> 240749 bytes ui/rampingios/rampingiosv3.c | 1253 +++++++++++ ui/rampingios/rampingiosv3.svg | 4113 +++++++++++++++++++++++++++++++++++++ 8 files changed, 6473 insertions(+) create mode 100644 ui/rampingios/Makefile create mode 100755 ui/rampingios/build-all.sh create mode 100644 ui/rampingios/rampingios-v3.html create mode 100644 ui/rampingios/rampingios-v3.md create mode 100644 ui/rampingios/rampingios-v3.txt create mode 100644 ui/rampingios/rampingiosv3-ui.png create mode 100644 ui/rampingios/rampingiosv3.c create mode 100644 ui/rampingios/rampingiosv3.svg (limited to 'ui/rampingios') diff --git a/ui/rampingios/Makefile b/ui/rampingios/Makefile new file mode 100644 index 0000000..8db198e --- /dev/null +++ b/ui/rampingios/Makefile @@ -0,0 +1,7 @@ +all: + ./build-all.sh + +clean: + rm -f *.hex cfg-*.h *~ *.elf *.o + +.phony: clean diff --git a/ui/rampingios/build-all.sh b/ui/rampingios/build-all.sh new file mode 100755 index 0000000..106dc15 --- /dev/null +++ b/ui/rampingios/build-all.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +cp -av ../anduril/cfg-emisar*.h . + +UI=rampingiosv3 + +for TARGET in cfg-*.h ; do + NAME=$(echo "$TARGET" | perl -ne '/cfg-(.*).h/ && print "$1\n";') + echo "===== $NAME =====" + echo ../../../bin/build.sh 85 "$UI" "-DCONFIGFILE=${TARGET}" + ../../../bin/build.sh 85 "$UI" "-DCONFIGFILE=${TARGET}" + mv -f "$UI".hex "$UI".$NAME.hex +done diff --git a/ui/rampingios/rampingios-v3.html b/ui/rampingios/rampingios-v3.html new file mode 100644 index 0000000..f72d1ec --- /dev/null +++ b/ui/rampingios/rampingios-v3.html @@ -0,0 +1,501 @@ + + + + + + + RampingIOS V3 Manual :: Phil! Gold + + + + + + + + + + + + + + + + + + + +
+

Tue, 28 Aug 2018

+ +
+

RampingIOS V3 Manual

+ +
+ +

+ + + + +
RampingIOS V3 UI diagram
+

+ +

The Emisar D4S flashlights use a firmware named RampingIOS +V3. (The Emisar D4, D1, and D1S +all use RampingIOS V2.) There's not really a manual; the +only thing we get is the diagram on the right. It's reasonably +comprehensive, but there's a fair amount of detail it merely summarizes, +so I thought a textual manual would be nice.

+ +

The Emisar D4S only works when the head and tailcap are tightened fully. +You can physically lock it out--prevent it from turning on +accidentally--by simply loosening the tailcap a small amount. A quarter +turn will do it.

+ +

Emisar lights are known for their ramping interfaces. Rather than have a +small number of distinct brightness levels, they can vary their brightness +anywhere between their lowest and highest levels, like a light on a +dimmer. The D4S is in ramping mode by default, but it also has a stepped +mode that can be configured to be closer to how non-ramping lights work.

+ +

Each mode--ramping and stepped--can have differently-configured brightness +floors and ceilings.

+ +

The driver for the D4S has two different chipsets. At low brightness +levels, a fairly-efficient but low-power chipset (called a 7135) is +used. These lowest brightness levels are called the "regulated levels". +Each regulated level will always be the same brightness regardless of how +much charge the battery has. Above a particular brightness level, the +light switches over to a less-efficient but high-power chipset (called a +FET). These levels are called "direct-drive". The brightness of the +direct-drive levels is directly related to the battery's charge level; the +more charged the battery, the brighter the levels. The light is at its +most efficient, in terms of power used for every lumen generated, at the +brightest regulated level. When the light is first powered by tightening +the tailcap, it will default to this level.

+ +

At higher brightness levels, the light's LEDs generate a lot of heat. If +the light exceeds its configured maximum temperature, it will begin +dimming itself automatically until the temperature drops below the allowed +maximum.

+ +

The D4S has a set of cyan-colored auxiliary LEDs that can be on when the +main LEDs are off. You can configure the behavior of the aux LEDs.

+ +

Basic Usage

+ +

The default mode for the light is ramping mode. Triple-pressing the +button (3 clicks) while the light is on will toggle between ramping +and stepped mode.

+ +

While the light is off, press and release the button (1 click) to turn +it on. It will turn on at the last-used brightness level. (This is +called "mode memory".) Immediately after loosening and tightening the +tailcap (or after changing the battery), the memorized level will be the +light's max regulated level.

+ +

When the light is on, 1 click will turn it off. The current brightness +level will be memorized for future use. There's a fraction of a second +delay between pressing the button and the light actually turning off. +That's because of the way the light processes input; it's waiting to make +sure you're only going to press the button once (since multiple presses +will trigger other actions).

+ +

When the light is on, holding the button down will brighten the light. In +ramping mode, the brightness will increase gradually ("ramping up"). In +stepped mode, the light will jump through increasing brightness levels. +If you press, release, and then hold the button, it will begin dimming. +In ramping mode, the brightness will decrease gradually ("ramping +down"). In stepped mode, the light will jump through decreasing +brightness levels. While the light is changing, if you release the button +and immediately hold it again, the direction (dimming or brightening) will +switch.

+ +

In ramping mode, while the light is ramping, it'll briefly blink off and +on again at two different brightness levels: the maximum regulated level +and the brightness ceiling.

+ +

While the light is off, double-pressing the button (2 clicks) will +immediately jump to the brightness ceiling.

+ +

While the light is on, 2 clicks will jump to the maximum brightness +level, regardless of the configured brightness ceiling. Another two +clicks will go back to the previous brightness level.

+ +

While the light is off, if you hold the button the light will turn on at +its lowest level. If you continue holding the button, the light will +begin brightening from there.

+ +
Configuration Menus
+ +

The light has several different configuration modes. Each of those modes +works more or less the same way. The mode will have a series of menu +items that it will go through. For each menu item, the light will first +blink a number of times corresponding to the item number (first, second, +etc.) After that, the light will begin fluttering on and off fairly +quickly. While the light is fluttering, you can click the button a number +of times; the light will count the number of button presses and use that +number as its new configuration for that menu item. After a short period +of time, the fluttering will stop and the light will move on to the next +menu item. After the light has gone through all of the menu items, it +will return to whatever mode it was in before entering the configuration +mode.

+ +

If you don't press the button during a particular menu item's fluttering, +that item will remain unchanged.

+ +
Configuring the Basic Modes
+ +

While the light is on, 4 clicks will enter ramping or stepped +configuration mode, depending on which mode the light was in before the 4 +clicks.

+ +

For ramping mode, there are two menu options:

+ +
    +
  1. Brightness floor (default 1/150)
  2. +
  3. Brightness ceiling (default 150/150)
  4. +
+ +

During the floor configuration, press the button equal to the number of +ramping levels (out of 150) at which the floor should be. To set the +lowest possible floor, click the button once.

+ +

The ceiling is configured similarly, but you press the button equal to the +number of steps away from maximum brightness. To set the highest possible +ceiling (at max brightness), click the button once.

+ +

For stepped mode, there are three menu options:

+ +
    +
  1. Brightness floor (default 20/150)
  2. +
  3. Brightness ceiling (default 120/150)
  4. +
  5. Number of steps (default 7)
  6. +
+ +

Other Modes

+ +

The other modes largely involve multiple clicks from off. Most of them +are not generally needed for everyday use, but they supplement the light's +basic operations.

+ +
BattCheck/TempCheck Modes
+ +

From off, 3 clicks will enter "BattCheck" mode, which blinks out the +current battery voltage. First it blinks the number of volts, then it +pauses, then it blinks out the tenths of volts. Thus, if the battery were +at 3.5 volts, the light would blink three times, pause, then five times. +For zeroes, it gives a very short blink.

+ +

A fully-charged lithium-ion battery is 4.2 volts. The light considers 2.8 +volts to be an empty battery and won't turn on if the battery is at or +below 2.8 volts.

+ +

The voltage sequence will continue blinking until you turn off the light +with a single click.

+ +

While the light is in BattCheck mode, 2 clicks will enter TempCheck +mode. Instead of blinking out the battery voltage, the light will start +blinking out its current temperature in degrees Celsius, first the tens +digit then the units digit. Like BattCheck mode, the light will continue +blinking out the temperature until you turn it off with a single click.

+ +

While the light is in TempCheck mode, 4 clicks will enter thermal +configuration mode. See the thermal configuration mode documentation +below for how that works.

+ +
Tactical Mode
+ +

From off, 4 clicks will enter "tactical" or "momentary" mode. The +light will flash once to show that it's entered the mode. The auxiliary +LEDs will turn off (if they were on). In tactical mode, the light will +turn on at its memorized brightness for as long as the button is being +held down. It will turn off as soon as the button is released.

+ +

There's no button press combination that will exit tactical mode. To exit +it, you will have to partially unscrew and retighten the tailcap.

+ +
Lockout Mode
+ +

From off, 6 clicks will enter lockout mode. The light will flash +twice to show that it's entered the mode. There's a separate aux LED mode +for lockout mode, so you can tell whether the light is in lockout or not.

+ +

In lockout mode, pressing the button will turn on the light at its lowest +brightness ("moonlight mode") for as long as the button is held down.

+ +

Another 6 clicks will exit lockout mode. The light will flash twice to +show that it's left the mode.

+ +

While in lockout mode, 3 clicks will cycle through the various +settings for the aux LEDs in lockout mode. The four modes are, in order: +low, high, blink (on high), and off. The default mode is blink.

+ +

Remember that loosening the tailcap a quarter turn will also lock out the +light. Using the 6 clicks is called "electronic lockout", while turning +the tailcap is "physical lockout".

+ +
Aux LED Configuration
+ +

From off, 7 clicks will cycle to the next aux LED mode. The four +modes are, in order: low, high, blink (on high), and off. The default +mode is low.

+ +
Beacon Mode
+ +

From off, 8 clicks will enter beacon mode. In beacon mode, the light +will blink on and off every few seconds.

+ +

By default, the light will blink every two seconds. To change the timing, +use 4 clicks while in beacon mode. The light will enter a one-item +menu. During the flickering for input, press the button a number of times +equal to the number of seconds between blinks.

+ +

1 click will exit beacon mode.

+ +
Thermal Configuration Mode
+ +

From off, 10 clicks will enter thermal configuration mode.

+ +

The menu items here are:

+ +
    +
  1. Current temperature (every click is one degree Celsius)
  2. +
  3. Temperature ceiling (every click is one degree above 30°C)
  4. +
+ +

The "current temperature" item can be used to adjust the calibration of +the light's temperature sensor. To use it, make sure the light has been +off long enough that all of its components have cooled (or warmed) to the +ambient temperature. Check the ambient temperature using a thermometer +you trust. Go to thermal configuration mode, and enter the current +temperature by clicking the button a number of times equal to the +temperature in degrees Celsius. (If it's 22°C, click the button 22 +times.)

+ +

You can check the default calibration by entering TempCheck mode from a +room-temperature light. The D4Ss are supposed to go through a temperature +calibration at the factory, so hopefully most of them won't need manual +thermal calibration.

+ +

The temperature ceiling is simply the highest temperature the light should +be allowed to reach. Once it hits its temperature ceiling, it will +progressively dim itself until the temperature stabilizes below the +ceiling. Note that the number of clicks in that menu option is added to +30 to reach the actual ceiling. (Thus, you can't set a ceiling below +31°C.) The maximum allowed ceiling is 70°C.

+ +

The default temperature ceiling is 45°C.

+ + +
+ + + +

+
Phil! Gold
+ + + + diff --git a/ui/rampingios/rampingios-v3.md b/ui/rampingios/rampingios-v3.md new file mode 100644 index 0000000..bc0e2b7 --- /dev/null +++ b/ui/rampingios/rampingios-v3.md @@ -0,0 +1,262 @@ +RampingIOS V3 Manual + +This Markdown-formatted manual was contributed by phil_g under a +Creative Commons CC0 waiver: + http://aperiodic.net/phil/archives/Geekery/rampingios-v3.html + https://creativecommons.org/publicdomain/zero/1.0/ + + +
+ + + + +
RampingIOS V3 UI diagram
+
+ +The Emisar [D4S][emisar-d4s] flashlights use a firmware named RampingIOS +V3. (The Emisar [D4][emisar-d4], [D1][emisar-d1], and [D1S][emisar-d1s] +all use [RampingIOS V2][rampingios-v2].) There's not really a manual; the +only thing we get is the diagram on the right. It's reasonably +comprehensive, but there's a fair amount of detail it merely summarizes, +so I thought a textual manual would be nice. + + [emisar-d4]: https://intl-outdoor.com/emisar-d4-high-power-led-flashlight-p-921.html + [emisar-d1]: https://intl-outdoor.com/emisar-d1-mini-thrower-p-922.html + [emisar-d1s]: https://intl-outdoor.com/emisar-d1s-thrower-p-926.html + [emisar-d4s]: https://intl-outdoor.com/emisar-d4s-26650-high-power-led-flashlight-p-932.html + [rampingios-v2]: http://aperiodic.net/phil/archives/Geekery/rampingios-v2.html + +The Emisar D4S only works when the head and tailcap are tightened fully. +You can physically lock it out--prevent it from turning on +accidentally--by simply loosening the tailcap a small amount. A quarter +turn will do it. + +Emisar lights are known for their ramping interfaces. Rather than have a +small number of distinct brightness levels, they can vary their brightness +anywhere between their lowest and highest levels, like a light on a +dimmer. The D4S is in ramping mode by default, but it also has a stepped +mode that can be configured to be closer to how non-ramping lights work. + +Each mode--ramping and stepped--can have differently-configured brightness +floors and ceilings. + +The driver for the D4S has two different chipsets. At low brightness +levels, a fairly-efficient but low-power chipset (called a *7135*) is +used. These lowest brightness levels are called the "*regulated levels*". +Each regulated level will always be the same brightness regardless of how +much charge the battery has. Above a particular brightness level, the +light switches over to a less-efficient but high-power chipset (called a +*FET*). These levels are called "*direct-drive*". The brightness of the +direct-drive levels is directly related to the battery's charge level; the +more charged the battery, the brighter the levels. The light is at its +most efficient, in terms of power used for every lumen generated, at the +brightest regulated level. When the light is first powered by tightening +the tailcap, it will default to this level. + +At higher brightness levels, the light's LEDs generate a lot of heat. If +the light exceeds its configured maximum temperature, it will begin +dimming itself automatically until the temperature drops below the allowed +maximum. + +The D4S has a set of cyan-colored auxiliary LEDs that can be on when the +main LEDs are off. You can configure the behavior of the aux LEDs. + +#### Basic Usage + +The default mode for the light is ramping mode. Triple-pressing the +button (**3 clicks**) while the light is on will toggle between ramping +and stepped mode. + +While the light is off, press and release the button (**1 click**) to turn +it on. It will turn on at the last-used brightness level. (This is +called "*mode memory*".) Immediately after loosening and tightening the +tailcap (or after changing the battery), the memorized level will be the +light's max regulated level. + +When the light is on, 1 click will turn it off. The current brightness +level will be memorized for future use. There's a fraction of a second +delay between pressing the button and the light actually turning off. +That's because of the way the light processes input; it's waiting to make +sure you're only going to press the button once (since multiple presses +will trigger other actions). + +When the light is on, holding the button down will brighten the light. In +ramping mode, the brightness will increase gradually ("*ramping up*"). In +stepped mode, the light will jump through increasing brightness levels. +If you press, release, and then hold the button, it will begin dimming. +In ramping mode, the brightness will decrease gradually ("*ramping +down*"). In stepped mode, the light will jump through decreasing +brightness levels. While the light is changing, if you release the button +and immediately hold it again, the direction (dimming or brightening) will +switch. + +In ramping mode, while the light is ramping, it'll briefly blink off and +on again at two different brightness levels: the maximum regulated level +and the brightness ceiling. + +While the light is off, double-pressing the button (**2 clicks**) will +immediately jump to the brightness ceiling. + +While the light is on, **2 clicks** will jump to the maximum brightness +level, regardless of the configured brightness ceiling. Another two +clicks will go back to the previous brightness level. + +While the light is off, if you hold the button the light will turn on at +its lowest level. If you continue holding the button, the light will +begin brightening from there. + +##### Configuration Menus + +The light has several different configuration modes. Each of those modes +works more or less the same way. The mode will have a series of menu +items that it will go through. For each menu item, the light will first +blink a number of times corresponding to the item number (first, second, +etc.) After that, the light will begin fluttering on and off fairly +quickly. While the light is fluttering, you can click the button a number +of times; the light will count the number of button presses and use that +number as its new configuration for that menu item. After a short period +of time, the fluttering will stop and the light will move on to the next +menu item. After the light has gone through all of the menu items, it +will return to whatever mode it was in before entering the configuration +mode. + +If you don't press the button during a particular menu item's fluttering, +that item will remain unchanged. + +##### Configuring the Basic Modes + +While the light is on, **4 clicks** will enter ramping or stepped +configuration mode, depending on which mode the light was in before the 4 +clicks. + +For ramping mode, there are two menu options: + + 1. Brightness floor (default 1/150) + 2. Brightness ceiling (default 150/150) + +During the floor configuration, press the button equal to the number of +ramping levels (out of 150) at which the floor should be. To set the +lowest possible floor, click the button once. + +The ceiling is configured similarly, but you press the button equal to the +number of steps away from maximum brightness. To set the highest possible +ceiling (at max brightness), click the button once. + +For stepped mode, there are three menu options: + + 1. Brightness floor (default 20/150) + 2. Brightness ceiling (default 120/150) + 3. Number of steps (default 7) + +#### Other Modes + +The other modes largely involve multiple clicks from off. Most of them +are not generally needed for everyday use, but they supplement the light's +basic operations. + +##### BattCheck/TempCheck Modes + +From off, **3 clicks** will enter "BattCheck" mode, which blinks out the +current battery voltage. First it blinks the number of volts, then it +pauses, then it blinks out the tenths of volts. Thus, if the battery were +at 3.5 volts, the light would blink three times, pause, then five times. +For zeroes, it gives a very short blink. + +A fully-charged lithium-ion battery is 4.2 volts. The light considers 2.8 +volts to be an empty battery and won't turn on if the battery is at or +below 2.8 volts. + +The voltage sequence will continue blinking until you turn off the light +with a single click. + +While the light is in BattCheck mode, **2 clicks** will enter TempCheck +mode. Instead of blinking out the battery voltage, the light will start +blinking out its current temperature in degrees Celsius, first the tens +digit then the units digit. Like BattCheck mode, the light will continue +blinking out the temperature until you turn it off with a single click. + +While the light is in TempCheck mode, **4 clicks** will enter thermal +configuration mode. See the thermal configuration mode documentation +below for how that works. + +##### Tactical Mode + +From off, **4 clicks** will enter "tactical" or "momentary" mode. The +light will flash once to show that it's entered the mode. The auxiliary +LEDs will turn off (if they were on). In tactical mode, the light will +turn on at its memorized brightness for as long as the button is being +held down. It will turn off as soon as the button is released. + +There's no button press combination that will exit tactical mode. To exit +it, you will have to partially unscrew and retighten the tailcap. + +##### Lockout Mode + +From off, **6 clicks** will enter lockout mode. The light will flash +twice to show that it's entered the mode. There's a separate aux LED mode +for lockout mode, so you can tell whether the light is in lockout or not. + +In lockout mode, pressing the button will turn on the light at its lowest +brightness ("*moonlight mode*") for as long as the button is held down. + +Another 6 clicks will exit lockout mode. The light will flash twice to +show that it's left the mode. + +While in lockout mode, **3 clicks** will cycle through the various +settings for the aux LEDs in lockout mode. The four modes are, in order: +low, high, blink (on high), and off. The default mode is blink. + +Remember that loosening the tailcap a quarter turn will also lock out the +light. Using the 6 clicks is called "*electronic lockout*", while turning +the tailcap is "*physical lockout*". + +##### Aux LED Configuration + +From off, **7 clicks** will cycle to the next aux LED mode. The four +modes are, in order: low, high, blink (on high), and off. The default +mode is low. + +##### Beacon Mode + +From off, **8 clicks** will enter beacon mode. In beacon mode, the light +will blink on and off every few seconds. + +By default, the light will blink every two seconds. To change the timing, +use **4 clicks** while in beacon mode. The light will enter a one-item +menu. During the flickering for input, press the button a number of times +equal to the number of seconds between blinks. + +1 click will exit beacon mode. + +##### Thermal Configuration Mode + +From off, **10 clicks** will enter thermal configuration mode. + +The menu items here are: + + 1. Current temperature (every click is one degree Celsius) + 2. Temperature ceiling (every click is one degree *above 30°C*) + +The "current temperature" item can be used to adjust the calibration of +the light's temperature sensor. To use it, make sure the light has been +off long enough that all of its components have cooled (or warmed) to the +ambient temperature. Check the ambient temperature using a thermometer +you trust. Go to thermal configuration mode, and enter the current +temperature by clicking the button a number of times equal to the +temperature in degrees Celsius. (If it's 22°C, click the button 22 +times.) + +You can check the default calibration by entering TempCheck mode from a +room-temperature light. The D4Ss are supposed to go through a temperature +calibration at the factory, so hopefully most of them won't need manual +thermal calibration. + +The temperature ceiling is simply the highest temperature the light should +be allowed to reach. Once it hits its temperature ceiling, it will +progressively dim itself until the temperature stabilizes below the +ceiling. Note that the number of clicks in that menu option is added to +*30* to reach the actual ceiling. (Thus, you can't set a ceiling below +31°C.) The maximum allowed ceiling is 70°C. + +The default temperature ceiling is 45°C. diff --git a/ui/rampingios/rampingios-v3.txt b/ui/rampingios/rampingios-v3.txt new file mode 100644 index 0000000..4598a76 --- /dev/null +++ b/ui/rampingios/rampingios-v3.txt @@ -0,0 +1,324 @@ +RampingIOS V3 Manual +http://aperiodic.net/phil/archives/Geekery/rampingios-v3.html + +Tue, 28 Aug 2018 +9:47AM | Geekery | # + + +RampingIOS V3 Manual +-------------------- + +[rampingiosv3-ui.png] RampingIOS V3 UI diagram + +The Emisar D4S flashlights use a firmware named RampingIOS V3. (The Emisar D4, +D1, and D1S all use RampingIOS V2.) There's not really a manual; the only thing +we get is the diagram on the right. It's reasonably comprehensive, but there's +a fair amount of detail it merely summarizes, so I thought a textual manual +would be nice. + +The Emisar D4S only works when the head and tailcap are tightened fully. You +can physically lock it out--prevent it from turning on accidentally--by simply +loosening the tailcap a small amount. A quarter turn will do it. + +Emisar lights are known for their ramping interfaces. Rather than have a small +number of distinct brightness levels, they can vary their brightness anywhere +between their lowest and highest levels, like a light on a dimmer. The D4S is +in ramping mode by default, but it also has a stepped mode that can be +configured to be closer to how non-ramping lights work. + +Each mode--ramping and stepped--can have differently-configured brightness +floors and ceilings. + +The driver for the D4S has two different chipsets. At low brightness levels, a +fairly-efficient but low-power chipset (called a 7135) is used. These lowest +brightness levels are called the "regulated levels". Each regulated level will +always be the same brightness regardless of how much charge the battery has. +Above a particular brightness level, the light switches over to a +less-efficient but high-power chipset (called a FET). These levels are called " +direct-drive". The brightness of the direct-drive levels is directly related to +the battery's charge level; the more charged the battery, the brighter the +levels. The light is at its most efficient, in terms of power used for every +lumen generated, at the brightest regulated level. When the light is first +powered by tightening the tailcap, it will default to this level. + +At higher brightness levels, the light's LEDs generate a lot of heat. If the +light exceeds its configured maximum temperature, it will begin dimming itself +automatically until the temperature drops below the allowed maximum. + +The D4S has a set of cyan-colored auxiliary LEDs that can be on when the main +LEDs are off. You can configure the behavior of the aux LEDs. + + +Basic Usage +----------- + +The default mode for the light is ramping mode. Triple-pressing the button (3 +clicks) while the light is on will toggle between ramping and stepped mode. + +While the light is off, press and release the button (1 click) to turn it on. +It will turn on at the last-used brightness level. (This is called "mode memory +".) Immediately after loosening and tightening the tailcap (or after changing +the battery), the memorized level will be the light's max regulated level. + +When the light is on, 1 click will turn it off. The current brightness level +will be memorized for future use. There's a fraction of a second delay between +pressing the button and the light actually turning off. That's because of the +way the light processes input; it's waiting to make sure you're only going to +press the button once (since multiple presses will trigger other actions). + +When the light is on, holding the button down will brighten the light. In +ramping mode, the brightness will increase gradually ("ramping up"). In stepped +mode, the light will jump through increasing brightness levels. If you press, +release, and then hold the button, it will begin dimming. In ramping mode, the +brightness will decrease gradually ("ramping down"). In stepped mode, the light +will jump through decreasing brightness levels. While the light is changing, if +you release the button and immediately hold it again, the direction (dimming or +brightening) will switch. + +In ramping mode, while the light is ramping, it'll briefly blink off and on +again at two different brightness levels: the maximum regulated level and the +brightness ceiling. + +While the light is off, double-pressing the button (2 clicks) will immediately +jump to the brightness ceiling. + +While the light is on, 2 clicks will jump to the maximum brightness level, +regardless of the configured brightness ceiling. Another two clicks will go +back to the previous brightness level. + +While the light is off, if you hold the button the light will turn on at its +lowest level. If you continue holding the button, the light will begin +brightening from there. + + +Configuration Menus +------------------- + +The light has several different configuration modes. Each of those modes works +more or less the same way. The mode will have a series of menu items that it +will go through. For each menu item, the light will first blink a number of +times corresponding to the item number (first, second, etc.) After that, the +light will begin fluttering on and off fairly quickly. While the light is +fluttering, you can click the button a number of times; the light will count +the number of button presses and use that number as its new configuration for +that menu item. After a short period of time, the fluttering will stop and the +light will move on to the next menu item. After the light has gone through all +of the menu items, it will return to whatever mode it was in before entering +the configuration mode. + +If you don't press the button during a particular menu item's fluttering, that +item will remain unchanged. + + +Configuring the Basic Modes + +While the light is on, 4 clicks will enter ramping or stepped configuration +mode, depending on which mode the light was in before the 4 clicks. + +For ramping mode, there are two menu options: + + 1. Brightness floor (default 1/150) + 2. Brightness ceiling (default 150/150) + +During the floor configuration, press the button equal to the number of ramping +levels (out of 150) at which the floor should be. To set the lowest possible +floor, click the button once. + +The ceiling is configured similarly, but you press the button equal to the +number of steps away from maximum brightness. To set the highest possible +ceiling (at max brightness), click the button once. + +For stepped mode, there are three menu options: + + 1. Brightness floor (default 20/150) + 2. Brightness ceiling (default 120/150) + 3. Number of steps (default 7) + + +Other Modes +----------- + +The other modes largely involve multiple clicks from off. Most of them are not +generally needed for everyday use, but they supplement the light's basic +operations. + + +BattCheck/TempCheck Modes + +From off, 3 clicks will enter "BattCheck" mode, which blinks out the current +battery voltage. First it blinks the number of volts, then it pauses, then it +blinks out the tenths of volts. Thus, if the battery were at 3.5 volts, the +light would blink three times, pause, then five times. For zeroes, it gives a +very short blink. + +A fully-charged lithium-ion battery is 4.2 volts. The light considers 2.8 volts +to be an empty battery and won't turn on if the battery is at or below 2.8 +volts. + +The voltage sequence will continue blinking until you turn off the light with a +single click. + +While the light is in BattCheck mode, 2 clicks will enter TempCheck mode. +Instead of blinking out the battery voltage, the light will start blinking out +its current temperature in degrees Celsius, first the tens digit then the units +digit. Like BattCheck mode, the light will continue blinking out the +temperature until you turn it off with a single click. + +While the light is in TempCheck mode, 4 clicks will enter thermal configuration +mode. See the thermal configuration mode documentation below for how that +works. + + +Tactical Mode + +From off, 4 clicks will enter "tactical" or "momentary" mode. The light will +flash once to show that it's entered the mode. The auxiliary LEDs will turn off +(if they were on). In tactical mode, the light will turn on at its memorized +brightness for as long as the button is being held down. It will turn off as +soon as the button is released. + +There's no button press combination that will exit tactical mode. To exit it, +you will have to partially unscrew and retighten the tailcap. + + +Lockout Mode + +From off, 6 clicks will enter lockout mode. The light will flash twice to show +that it's entered the mode. There's a separate aux LED mode for lockout mode, +so you can tell whether the light is in lockout or not. + +In lockout mode, pressing the button will turn on the light at its lowest +brightness ("moonlight mode") for as long as the button is held down. + +Another 6 clicks will exit lockout mode. The light will flash twice to show +that it's left the mode. + +While in lockout mode, 3 clicks will cycle through the various settings for the +aux LEDs in lockout mode. The four modes are, in order: low, high, blink (on +high), and off. The default mode is blink. + +Remember that loosening the tailcap a quarter turn will also lock out the +light. Using the 6 clicks is called "electronic lockout", while turning the +tailcap is "physical lockout". + + +Aux LED Configuration + +From off, 7 clicks will cycle to the next aux LED mode. The four modes are, in +order: low, high, blink (on high), and off. The default mode is low. + + +Beacon Mode + +From off, 8 clicks will enter beacon mode. In beacon mode, the light will blink +on and off every few seconds. + +By default, the light will blink every two seconds. To change the timing, use 4 +clicks while in beacon mode. The light will enter a one-item menu. During the +flickering for input, press the button a number of times equal to the number of +seconds between blinks. + +1 click will exit beacon mode. + + +Thermal Configuration Mode + +From off, 10 clicks will enter thermal configuration mode. + +The menu items here are: + + 1. Current temperature (every click is one degree Celsius) + 2. Temperature ceiling (every click is one degree above 30?C) + +The "current temperature" item can be used to adjust the calibration of the +light's temperature sensor. To use it, make sure the light has been off long +enough that all of its components have cooled (or warmed) to the ambient +temperature. Check the ambient temperature using a thermometer you trust. Go to +thermal configuration mode, and enter the current temperature by clicking the +button a number of times equal to the temperature in degrees Celsius. (If it's +22?C, click the button 22 times.) + +You can check the default calibration by entering TempCheck mode from a +room-temperature light. The D4Ss are supposed to go through a temperature +calibration at the factory, so hopefully most of them won't need manual thermal +calibration. + +The temperature ceiling is simply the highest temperature the light should be +allowed to reach. Once it hits its temperature ceiling, it will progressively +dim itself until the temperature stabilizes below the ceiling. Note that the +number of clicks in that menu option is added to 30 to reach the actual +ceiling. (Thus, you can't set a ceiling below 31?C.) The maximum allowed +ceiling is 70?C. + +The default temperature ceiling is 45?C. + + +Static + + * zsh prompt + * PGP + * SSH + * MTA + * tutorials + * config files + * desktop + * books I own + * stuff I'm giving away + * Dr. Who eps I have + * bookmarks + * photos + * about + +Directory + + * Root (143) + + Books (32) + + Events (7) + o Burning Man (3) + o Camping (2) + o PDF (2) + + Geekery (36) + o Test (3) + + General (24) + + Links (12) + o Slashdot (1) + + MTA (22) + + Recipes (4) + + Video Games (6) + o FFXI (1) + +Archive + + ?August? +Sun Mon Tue Wed Thu Fri Sat + 1 2 3 4 +5 6 7 8 9 10 11 +12 13 14 15 16 17 18 +19 20 21 22 23 24 25 +26 27 28 29 30 31 + + ?2018? + Months +Jan Feb Mar Apr May Jun +Jul Aug Sep Oct Nov Dec + +Search + +[ ] +Powered by Google + +Currently Reading + +Recent Books + +------------------------------------------------------------------------------- + +Copyright (C) 2018 Phil Gold + +Back to main page. + + * Valid HTML 4.01 + * Valid CSS 2 + * RSS syndication + * Valid RSS 1.0 + diff --git a/ui/rampingios/rampingiosv3-ui.png b/ui/rampingios/rampingiosv3-ui.png new file mode 100644 index 0000000..d02dbf6 Binary files /dev/null and b/ui/rampingios/rampingiosv3-ui.png differ diff --git a/ui/rampingios/rampingiosv3.c b/ui/rampingios/rampingiosv3.c new file mode 100644 index 0000000..e990a5a --- /dev/null +++ b/ui/rampingios/rampingiosv3.c @@ -0,0 +1,1253 @@ +/* + * RampingIOS V3: FSM-based version of RampingIOS V2 UI, with upgrades. + * + * Copyright (C) 2018-2019 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 . + */ + +/********* User-configurable options *********/ +// Anduril config file name (set it here or define it at the gcc command line) +//#define CONFIGFILE cfg-emisar-d4s.h + +#define USE_LVP // FIXME: won't build when this option is turned off + +// parameters for this defined below or per-driver +#define USE_THERMAL_REGULATION +#define DEFAULT_THERM_CEIL 45 // try not to get hotter than this +#define USE_TENCLICK_THERMAL_CONFIG // ten clicks from off -> thermal config mode + +// short blip when crossing from "click" to "hold" from off +// (helps the user hit moon mode exactly, instead of holding too long +// or too short) +#define MOON_TIMING_HINT +// short blips while ramping +#define BLINK_AT_RAMP_MIDDLE +//#define BLINK_AT_RAMP_FLOOR +#define BLINK_AT_RAMP_CEILING +//#define BLINK_AT_STEPS // whenever a discrete ramp mode is passed in smooth mode + +// ramp down via regular button hold if a ramp-up ended <1s ago +// ("hold, release, hold" ramps down instead of up) +#define USE_REVERSING + +// battery readout style (pick one) +#define BATTCHECK_VpT +//#define BATTCHECK_8bars // FIXME: breaks build +//#define BATTCHECK_4bars // FIXME: breaks build + +// enable beacon mode +#define USE_BEACON_MODE + +// make the ramps configurable by the user +#define USE_RAMP_CONFIG + +/***** specific settings for known driver types *****/ +#include "tk.h" +#include incfile(CONFIGFILE) + + +// thermal properties, if not defined per-driver +#ifndef MIN_THERM_STEPDOWN +#define MIN_THERM_STEPDOWN MAX_1x7135 // lowest value it'll step down to +#endif +#ifndef THERM_FASTER_LEVEL + #ifdef MAX_Nx7135 + #define THERM_FASTER_LEVEL MAX_Nx7135 // throttle back faster when high + #else + #define THERM_FASTER_LEVEL (RAMP_SIZE*4/5) // throttle back faster when high + #endif +#endif +#ifdef USE_THERMAL_REGULATION +#define USE_SET_LEVEL_GRADUALLY // isn't used except for thermal adjustments +#endif + + +/********* Configure SpaghettiMonster *********/ +#define USE_DELAY_ZERO +#define USE_RAMPING +#ifndef RAMP_LENGTH +#define RAMP_LENGTH 150 // default, if not overridden in a driver cfg file +#endif +#define USE_BATTCHECK +#define USE_IDLE_MODE // reduce power use while awake and no tasks are pending +#define USE_DYNAMIC_UNDERCLOCKING // cut clock speed at very low modes for better efficiency + +// try to auto-detect how many eeprom bytes +#define USE_EEPROM +#define EEPROM_BYTES_BASE 7 + +#ifdef USE_INDICATOR_LED +#define EEPROM_INDICATOR_BYTES 1 +#else +#define EEPROM_INDICATOR_BYTES 0 +#endif + +#ifdef USE_THERMAL_REGULATION +#define EEPROM_THERMAL_BYTES 2 +#else +#define EEPROM_THERMAL_BYTES 0 +#endif + +#define EEPROM_BYTES (EEPROM_BYTES_BASE+EEPROM_INDICATOR_BYTES+EEPROM_THERMAL_BYTES) + + +#include "spaghetti-monster.h" + + +// FSM states +uint8_t off_state(Event event, uint16_t arg); +// simple numeric entry config menu +uint8_t config_state_base(Event event, uint16_t arg, + uint8_t num_config_steps, + void (*savefunc)()); +#define MAX_CONFIG_VALUES 3 +uint8_t config_state_values[MAX_CONFIG_VALUES]; +// ramping mode and its related config mode +uint8_t steady_state(Event event, uint16_t arg); +#ifdef USE_RAMP_CONFIG +uint8_t ramp_config_state(Event event, uint16_t arg); +#endif +#ifdef USE_BATTCHECK +uint8_t battcheck_state(Event event, uint16_t arg); +#endif +#ifdef USE_THERMAL_REGULATION +#define USE_BLINK_NUM +uint8_t tempcheck_state(Event event, uint16_t arg); +uint8_t thermal_config_state(Event event, uint16_t arg); +#endif +#ifdef USE_BEACON_MODE +// beacon mode and its related config mode +uint8_t beacon_state(Event event, uint16_t arg); +uint8_t beacon_config_state(Event event, uint16_t arg); +#endif +// soft lockout +#define MOON_DURING_LOCKOUT_MODE +// if enabled, 2nd lockout click goes to the other ramp's floor level +//#define LOCKOUT_MOON_FANCY +uint8_t lockout_state(Event event, uint16_t arg); +// momentary / signalling mode +uint8_t momentary_state(Event event, uint16_t arg); + +// general helper function for config modes +uint8_t number_entry_state(Event event, uint16_t arg); +// return value from number_entry_state() +volatile uint8_t number_entry_value; + +void blink_confirm(uint8_t num); +#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) +void indicator_blink(uint8_t arg); +#endif + +// remember stuff even after battery was changed +void load_config(); +void save_config(); + +// default ramp options if not overridden earlier per-driver +#ifndef RAMP_SMOOTH_FLOOR + #define RAMP_SMOOTH_FLOOR 1 +#endif +#ifndef RAMP_SMOOTH_CEIL + #if PWM_CHANNELS == 3 + #define RAMP_SMOOTH_CEIL MAX_Nx7135 + #else + #define RAMP_SMOOTH_CEIL MAX_LEVEL - 30 + #endif +#endif +#ifndef RAMP_DISCRETE_FLOOR + #define RAMP_DISCRETE_FLOOR 20 +#endif +#ifndef RAMP_DISCRETE_CEIL + #define RAMP_DISCRETE_CEIL RAMP_SMOOTH_CEIL +#endif +#ifndef RAMP_DISCRETE_STEPS + #define RAMP_DISCRETE_STEPS 7 +#endif + +// mile marker(s) partway up the ramp +// default: blink only at border between regulated and FET +#ifdef BLINK_AT_RAMP_MIDDLE + #if PWM_CHANNELS >= 3 + #ifndef BLINK_AT_RAMP_MIDDLE_1 + #define BLINK_AT_RAMP_MIDDLE_1 MAX_Nx7135 + #ifndef BLINK_AT_RAMP_MIDDLE_2 + #define BLINK_AT_RAMP_MIDDLE_2 MAX_1x7135 + #endif + #endif + #else + #ifndef BLINK_AT_RAMP_MIDDLE_1 + #define BLINK_AT_RAMP_MIDDLE_1 MAX_1x7135 + #endif + #endif +#endif + +// brightness control +#ifndef DEFAULT_LEVEL +#define DEFAULT_LEVEL MAX_1x7135 +#endif +uint8_t memorized_level = DEFAULT_LEVEL; +// smooth vs discrete ramping +volatile uint8_t ramp_style = 0; // 0 = smooth, 1 = discrete +volatile uint8_t ramp_smooth_floor = RAMP_SMOOTH_FLOOR; +volatile uint8_t ramp_smooth_ceil = RAMP_SMOOTH_CEIL; +volatile uint8_t ramp_discrete_floor = RAMP_DISCRETE_FLOOR; +volatile uint8_t ramp_discrete_ceil = RAMP_DISCRETE_CEIL; +volatile uint8_t ramp_discrete_steps = RAMP_DISCRETE_STEPS; +uint8_t ramp_discrete_step_size; // don't set this + +#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) + #ifdef INDICATOR_LED_DEFAULT_MODE + uint8_t indicator_led_mode = INDICATOR_LED_DEFAULT_MODE; + #else + #ifdef USE_INDICATOR_LED_WHILE_RAMPING + //uint8_t indicator_led_mode = (1<<2) + 2; + uint8_t indicator_led_mode = (2<<2) + 1; + #else + uint8_t indicator_led_mode = (3<<2) + 1; + #endif + #endif +#endif + +// calculate the nearest ramp level which would be valid at the moment +// (is a no-op for smooth ramp, but limits discrete ramp to only the +// correct levels for the user's config) +uint8_t nearest_level(int16_t target); + +#ifdef USE_THERMAL_REGULATION +// brightness before thermal step-down +uint8_t target_level = 0; +#endif + +#ifdef USE_BEACON_MODE +// beacon timing +volatile uint8_t beacon_seconds = 2; +#endif + + +uint8_t off_state(Event event, uint16_t arg) { + // turn emitter off when entering state + if (event == EV_enter_state) { + set_level(0); + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode & 0x03); + #endif + // sleep while off (lower power use) + go_to_standby = 1; + 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; + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode & 0x03); + #endif + } + return EVENT_HANDLED; + } + #if defined(TICK_DURING_STANDBY) && defined(USE_INDICATOR_LED) + // blink the indicator LED, maybe + else if (event == EV_sleep_tick) { + if ((indicator_led_mode & 0b00000011) == 0b00000011) { + indicator_blink(arg); + } + 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 EVENT_HANDLED; + } + // hold: go to lowest level + else if (event == EV_click1_hold) { + #ifdef MOON_TIMING_HINT + if (arg == 0) { + // let the user know they can let go now to stay at moon + uint8_t temp = actual_level; + set_level(0); + delay_4ms(3); + set_level(temp); + } else + #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 + set_state(steady_state, 1); + } + return EVENT_HANDLED; + } + // hold, release quickly: go to lowest level (floor) + else if (event == EV_click1_hold_release) { + set_state(steady_state, 1); + 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 EVENT_HANDLED; + } + // 1 click: regular mode + else if (event == EV_1click) { + set_state(steady_state, memorized_level); + 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 EVENT_HANDLED; + } + // 2 clicks: highest mode (ceiling) + else if (event == EV_2clicks) { + set_state(steady_state, MAX_LEVEL); + return EVENT_HANDLED; + } + // 3 clicks (initial press): off, to prep for later events + else if (event == EV_click3_press) { + set_level(0); + 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 EVENT_HANDLED; + } + #endif + // 4 clicks: momentary + else if (event == EV_4clicks) { + blink_confirm(1); + set_state(momentary_state, 0); + return EVENT_HANDLED; + } + // 6 clicks: lockout mode + else if (event == EV_6clicks) { + blink_confirm(2); + set_state(lockout_state, 0); + return EVENT_HANDLED; + } + #ifdef USE_INDICATOR_LED + // 7 clicks: next aux LED mode + else if (event == EV_7clicks) { + blink_confirm(1); + uint8_t mode = (indicator_led_mode & 3) + 1; + #ifdef TICK_DURING_STANDBY + mode = mode & 3; + #else + mode = mode % 3; + #endif + #ifdef INDICATOR_LED_SKIP_LOW + if (mode == 1) { mode ++; } + #endif + indicator_led_mode = (indicator_led_mode & 0b11111100) | mode; + indicator_led(mode); + save_config(); + return EVENT_HANDLED; + } + #endif + // 8 clicks: beacon mode + else if (event == EV_8clicks) { + set_state(beacon_state, 0); + 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 EVENT_HANDLED; + } + #endif + return EVENT_NOT_HANDLED; +} + + +uint8_t steady_state(Event event, uint16_t arg) { + uint8_t mode_min = ramp_smooth_floor; + uint8_t mode_max = ramp_smooth_ceil; + uint8_t ramp_step_size = 1; + #ifdef USE_REVERSING + static int8_t ramp_direction = 1; + #endif + if (ramp_style) { + mode_min = ramp_discrete_floor; + mode_max = ramp_discrete_ceil; + ramp_step_size = ramp_discrete_step_size; + } + + // turn LED on when we first enter the mode + if ((event == EV_enter_state) || (event == EV_reenter_state)) { + // if we just got back from config mode, go back to memorized level + if (event == EV_reenter_state) { + arg = memorized_level; + } + // remember this level, unless it's moon or turbo + if ((arg > mode_min) && (arg < mode_max)) + memorized_level = arg; + // use the requested level even if not memorized + arg = nearest_level(arg); + #ifdef USE_THERMAL_REGULATION + target_level = arg; + #endif + set_level(arg); + #ifdef USE_REVERSING + ramp_direction = 1; + #endif + return EVENT_HANDLED; + } + // 1 click: off + else if (event == EV_1click) { + set_state(off_state, 0); + return EVENT_HANDLED; + } + // 2 clicks: go to/from highest level + else if (event == EV_2clicks) { + if (actual_level < MAX_LEVEL) { + #ifdef USE_THERMAL_REGULATION + target_level = MAX_LEVEL; + #endif + // true turbo, not the mode-specific ceiling + set_level(MAX_LEVEL); + } + else { + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + set_level(memorized_level); + } + return EVENT_HANDLED; + } + // 3 clicks: toggle smooth vs discrete ramping + else if (event == EV_3clicks) { + ramp_style = !ramp_style; + memorized_level = nearest_level(actual_level); + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #ifdef USE_SET_LEVEL_GRADUALLY + //set_level_gradually(lvl); + #endif + #endif + save_config(); + set_level(0); + delay_4ms(20/4); + set_level(memorized_level); + 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 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 EVENT_HANDLED; + } + #ifdef USE_REVERSING + // make it ramp down instead, if already at max + if ((arg <= 1) && (actual_level >= mode_max)) { + ramp_direction = -1; + } + memorized_level = nearest_level((int16_t)actual_level \ + + (ramp_step_size * ramp_direction)); + #else + memorized_level = nearest_level((int16_t)actual_level + ramp_step_size); + #endif + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + #if defined(BLINK_AT_RAMP_CEILING) || defined(BLINK_AT_RAMP_MIDDLE) + // only blink once for each threshold + if ((memorized_level != actual_level) && ( + 0 // for easier syntax below + #ifdef BLINK_AT_RAMP_MIDDLE_1 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_1) + #endif + #ifdef BLINK_AT_RAMP_MIDDLE_2 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_2) + #endif + #ifdef BLINK_AT_RAMP_CEILING + || (memorized_level == mode_max) + #endif + #if defined(USE_REVERSING) && defined(BLINK_AT_RAMP_FLOOR) + || (memorized_level == mode_min) + #endif + )) { + set_level(0); + delay_4ms(8/4); + } + #endif + #if defined(BLINK_AT_STEPS) + uint8_t foo = ramp_style; + ramp_style = 1; + uint8_t nearest = nearest_level((int16_t)actual_level); + ramp_style = foo; + // only blink once for each threshold + if ((memorized_level != actual_level) && + (ramp_style == 0) && + (memorized_level == nearest) + ) + { + set_level(0); + delay_4ms(8/4); + } + #endif + set_level(memorized_level); + return EVENT_HANDLED; + } + #if defined(USE_REVERSING) + // reverse ramp direction on hold release + else if (event == EV_click1_hold_release) { + #ifdef USE_REVERSING + ramp_direction = -ramp_direction; + #endif + return EVENT_HANDLED; + } + #endif + // click, hold: change brightness (dimmer) + else if (event == EV_click2_hold) { + #ifdef USE_REVERSING + ramp_direction = 1; + #endif + // ramp slower in discrete mode + if (ramp_style && (arg % HOLD_TIMEOUT != 0)) { + return EVENT_HANDLED; + } + // TODO? make it ramp up instead, if already at min? + memorized_level = nearest_level((int16_t)actual_level - ramp_step_size); + #ifdef USE_THERMAL_REGULATION + target_level = memorized_level; + #endif + #if defined(BLINK_AT_RAMP_FLOOR) || defined(BLINK_AT_RAMP_MIDDLE) + // only blink once for each threshold + if ((memorized_level != actual_level) && ( + 0 // for easier syntax below + #ifdef BLINK_AT_RAMP_MIDDLE_1 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_1) + #endif + #ifdef BLINK_AT_RAMP_MIDDLE_2 + || (memorized_level == BLINK_AT_RAMP_MIDDLE_2) + #endif + #ifdef BLINK_AT_RAMP_FLOOR + || (memorized_level == mode_min) + #endif + )) { + set_level(0); + delay_4ms(8/4); + } + #endif + #if defined(BLINK_AT_STEPS) + uint8_t foo = ramp_style; + ramp_style = 1; + uint8_t nearest = nearest_level((int16_t)actual_level); + ramp_style = foo; + // only blink once for each threshold + if ((memorized_level != actual_level) && + (ramp_style == 0) && + (memorized_level == nearest) + ) + { + set_level(0); + delay_4ms(8/4); + } + #endif + set_level(memorized_level); + return EVENT_HANDLED; + } + #if defined(USE_SET_LEVEL_GRADUALLY) || defined(USE_REVERSING) + else if (event == EV_tick) { + #ifdef USE_REVERSING + // un-reverse after 1 second + if (arg == TICKS_PER_SECOND) ramp_direction = 1; + #endif + #ifdef USE_SET_LEVEL_GRADUALLY + // make thermal adjustment speed scale with magnitude + if ((arg & 1) && (actual_level < THERM_FASTER_LEVEL)) { + return EVENT_HANDLED; // adjust slower when not a high mode + } + #ifdef THERM_HARD_TURBO_DROP + else if ((! (actual_level < THERM_FASTER_LEVEL)) + && (actual_level > gradual_target)) { + gradual_tick(); + } + else { + #endif + // [int(62*4 / (x**0.8)) for x in (1,2,4,8,16,32,64,128)] + //uint8_t intervals[] = {248, 142, 81, 46, 26, 15, 8, 5}; + // [int(62*4 / (x**0.9)) for x in (1,2,4,8,16,32,64,128)] + //uint8_t intervals[] = {248, 132, 71, 38, 20, 10, 5, 3}; + // [int(62*4 / (x**0.95)) for x in (1,2,4,8,16,32,64,128)] + uint8_t intervals[] = {248, 128, 66, 34, 17, 9, 4, 2}; + uint8_t diff; + static uint8_t ticks_since_adjust = 0; + ticks_since_adjust ++; + if (gradual_target > actual_level) diff = gradual_target - actual_level; + else { + diff = actual_level - gradual_target; + } + uint8_t magnitude = 0; + #ifndef THERM_HARD_TURBO_DROP + // if we're on a really high mode, drop faster + if (actual_level >= THERM_FASTER_LEVEL) { magnitude ++; } + #endif + while (diff) { + magnitude ++; + diff >>= 1; + } + uint8_t ticks_per_adjust = intervals[magnitude]; + if (ticks_since_adjust > ticks_per_adjust) + { + gradual_tick(); + ticks_since_adjust = 0; + } + //if (!(arg % ticks_per_adjust)) gradual_tick(); + #ifdef THERM_HARD_TURBO_DROP + } + #endif + #endif + return EVENT_HANDLED; + } + #endif + #ifdef USE_THERMAL_REGULATION + // overheating: drop by an amount proportional to how far we are above the ceiling + else if (event == EV_temperature_high) { + #if 0 + uint8_t foo = actual_level; + set_level(0); + delay_4ms(2); + set_level(foo); + #endif + #ifdef THERM_HARD_TURBO_DROP + if (actual_level > THERM_FASTER_LEVEL) { + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(THERM_FASTER_LEVEL); + #else + set_level(THERM_FASTER_LEVEL); + #endif + target_level = THERM_FASTER_LEVEL; + } else + #endif + if (actual_level > MIN_THERM_STEPDOWN) { + int16_t stepdown = actual_level - arg; + if (stepdown < MIN_THERM_STEPDOWN) stepdown = MIN_THERM_STEPDOWN; + else if (stepdown > MAX_LEVEL) stepdown = MAX_LEVEL; + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(stepdown); + #else + set_level(stepdown); + #endif + } + return EVENT_HANDLED; + } + // underheating: increase slowly if we're lower than the target + // (proportional to how low we are) + else if (event == EV_temperature_low) { + #if 0 + uint8_t foo = actual_level; + set_level(0); + delay_4ms(2); + set_level(foo); + #endif + if (actual_level < target_level) { + //int16_t stepup = actual_level + (arg>>1); + int16_t stepup = actual_level + arg; + if (stepup > target_level) stepup = target_level; + else if (stepup < MIN_THERM_STEPDOWN) stepup = MIN_THERM_STEPDOWN; + #ifdef USE_SET_LEVEL_GRADUALLY + set_level_gradually(stepup); + #else + set_level(stepup); + #endif + } + return EVENT_HANDLED; + } + #endif + return EVENT_NOT_HANDLED; +} + + +#ifdef USE_BATTCHECK +uint8_t battcheck_state(Event event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return EVENT_HANDLED; + } + // 2 clicks: tempcheck mode + else if (event == EV_2clicks) { + set_state(tempcheck_state, 0); + return EVENT_HANDLED; + } + return EVENT_NOT_HANDLED; +} +#endif + + +#ifdef USE_THERMAL_REGULATION +uint8_t tempcheck_state(Event event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + return EVENT_HANDLED; + } + // 4 clicks: thermal config mode + else if (event == EV_4clicks) { + push_state(thermal_config_state, 0); + return EVENT_HANDLED; + } + return EVENT_NOT_HANDLED; +} +#endif + + +#ifdef USE_BEACON_MODE +uint8_t beacon_state(Event event, uint16_t arg) { + // 1 click: off + if (event == EV_1click) { + set_state(off_state, 0); + 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 EVENT_HANDLED; + } + return EVENT_NOT_HANDLED; +} +#endif // #ifdef USE_BEACON_MODE + + +uint8_t lockout_state(Event event, uint16_t arg) { + #ifdef MOON_DURING_LOCKOUT_MODE + // momentary(ish) moon mode during lockout + // button is being held + if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) { + #ifdef LOCKOUT_MOON_LOWEST + // Use lowest moon configured + uint8_t lvl = ramp_smooth_floor; + if (ramp_discrete_floor < lvl) lvl = ramp_discrete_floor; + set_level(lvl); + #elif defined(LOCKOUT_MOON_FANCY) + uint8_t levels[] = { ramp_smooth_floor, ramp_discrete_floor }; + if ((event & 0x0f) == 2) { + set_level(levels[ramp_style^1]); + } else { + set_level(levels[ramp_style]); + } + #else + // Use moon from current ramp + set_level(nearest_level(1)); + #endif + } + // button was released + else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) { + set_level(0); + } + #endif + + // regular event handling + // conserve power while locked out + // (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 + if (event == EV_enter_state) { + indicator_led(indicator_led_mode >> 2); + } else + #endif + if (event == EV_tick) { + if (arg > TICKS_PER_SECOND*2) { + go_to_standby = 1; + #ifdef USE_INDICATOR_LED + indicator_led(indicator_led_mode >> 2); + #endif + } + 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 EVENT_HANDLED; + } + #endif + #ifdef USE_INDICATOR_LED + // 3 clicks: rotate through indicator LED modes (lockout mode) + else if (event == EV_3clicks) { + uint8_t mode = indicator_led_mode >> 2; + #ifdef TICK_DURING_STANDBY + mode = (mode + 1) & 3; + #else + mode = (mode + 1) % 3; + #endif + #ifdef INDICATOR_LED_SKIP_LOW + if (mode == 1) { mode ++; } + #endif + indicator_led_mode = (mode << 2) + (indicator_led_mode & 0x03); + indicator_led(mode); + save_config(); + return EVENT_HANDLED; + } + #endif + // 6 clicks: exit + else if (event == EV_6clicks) { + blink_confirm(1); + set_state(off_state, 0); + return EVENT_HANDLED; + } + + return EVENT_NOT_HANDLED; +} + + +uint8_t momentary_state(Event event, uint16_t arg) { + // TODO: momentary strobe here? (for light painting) + + // light up when the button is pressed; go dark otherwise + // button is being held + if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) { + set_level(memorized_level); + 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 EVENT_HANDLED; + } + + // Sleep, dammit! (but wait a few seconds first) + // (because standby mode uses such little power that it can interfere + // with exiting via tailcap loosen+tighten unless you leave power + // disconnected for several seconds, so we want to be awake when that + // happens to speed up the process) + else if ((event == EV_tick) && (actual_level == 0)) { + if (arg > TICKS_PER_SECOND*15) { // sleep after 15 seconds + go_to_standby = 1; // sleep while light is off + // TODO: lighted button should use lockout config? + } + return EVENT_HANDLED; + } + + return EVENT_NOT_HANDLED; +} + + +// ask the user for a sequence of numbers, then save them and return to caller +uint8_t config_state_base(Event event, uint16_t arg, + uint8_t num_config_steps, + void (*savefunc)()) { + static uint8_t config_step; + if (event == EV_enter_state) { + config_step = 0; + set_level(0); + return EVENT_HANDLED; + } + // advance forward through config steps + else if (event == EV_tick) { + if (config_step < num_config_steps) { + push_state(number_entry_state, config_step + 1); + } + else { + // TODO: blink out some sort of success pattern + savefunc(); + save_config(); + //set_state(retstate, retval); + pop_state(); + } + 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 EVENT_HANDLED; + } + //return EVENT_NOT_HANDLED; + // eat all other events; don't pass any through to parent + return EVENT_HANDLED; +} + +#ifdef USE_RAMP_CONFIG +void ramp_config_save() { + // parse values + uint8_t val; + if (ramp_style) { // discrete / stepped ramp + + val = config_state_values[0]; + if (val) { ramp_discrete_floor = val; } + + val = config_state_values[1]; + if (val) { ramp_discrete_ceil = MAX_LEVEL + 1 - val; } + + val = config_state_values[2]; + if (val) ramp_discrete_steps = val; + + } else { // smooth ramp + + val = config_state_values[0]; + if (val) { ramp_smooth_floor = val; } + + val = config_state_values[1]; + if (val) { ramp_smooth_ceil = MAX_LEVEL + 1 - val; } + + } +} + +uint8_t ramp_config_state(Event event, uint16_t arg) { + uint8_t num_config_steps; + num_config_steps = 2 + ramp_style; + return config_state_base(event, arg, + num_config_steps, ramp_config_save); +} +#endif // #ifdef USE_RAMP_CONFIG + + +#ifdef USE_THERMAL_REGULATION +void thermal_config_save() { + // parse values + uint8_t val; + + // calibrate room temperature + val = config_state_values[0]; + if (val) { + int8_t rawtemp = temperature - therm_cal_offset; + therm_cal_offset = val - rawtemp; + reset_thermal_history = 1; // invalidate all recent temperature data + } + + val = config_state_values[1]; + if (val) { + // set maximum heat limit + therm_ceil = 30 + val - 1; + } + if (therm_ceil > MAX_THERM_CEIL) therm_ceil = MAX_THERM_CEIL; +} + +uint8_t thermal_config_state(Event event, uint16_t arg) { + return config_state_base(event, arg, + 2, thermal_config_save); +} +#endif // #ifdef USE_THERMAL_REGULATION + + +#ifdef USE_BEACON_MODE +void beacon_config_save() { + // parse values + uint8_t val = config_state_values[0]; + if (val) { + beacon_seconds = val; + } +} + +uint8_t beacon_config_state(Event event, uint16_t arg) { + return config_state_base(event, arg, + 1, beacon_config_save); +} + +inline void beacon_mode_iter() { + // one iteration of main loop() + set_level(memorized_level); + nice_delay_ms(100); + set_level(0); + nice_delay_ms(((beacon_seconds) * 1000) - 100); +} +#endif // #ifdef USE_BEACON_MODE + + +uint8_t number_entry_state(Event event, uint16_t arg) { + static uint8_t value; + static uint8_t blinks_left; + static uint8_t entry_step; + static uint16_t wait_ticks; + if (event == EV_enter_state) { + value = 0; + blinks_left = arg; + entry_step = 0; + wait_ticks = 0; + return EVENT_HANDLED; + } + // advance through the process: + // 0: wait a moment + // 1: blink out the 'arg' value + // 2: wait a moment + // 3: "buzz" while counting clicks + // 4: save and exit + else if (event == EV_tick) { + // wait a moment + if ((entry_step == 0) || (entry_step == 2)) { + if (wait_ticks < TICKS_PER_SECOND/2) + wait_ticks ++; + else { + entry_step ++; + wait_ticks = 0; + } + } + // blink out the option number + else if (entry_step == 1) { + if (blinks_left) { + if ((wait_ticks & 31) == 10) { + set_level(RAMP_SIZE/4); + } + else if ((wait_ticks & 31) == 20) { + set_level(0); + } + else if ((wait_ticks & 31) == 31) { + blinks_left --; + } + wait_ticks ++; + } + else { + entry_step ++; + wait_ticks = 0; + } + } + else if (entry_step == 3) { // buzz while waiting for a number to be entered + wait_ticks ++; + // buzz for N seconds after last event + if ((wait_ticks & 3) == 0) { + set_level(RAMP_SIZE/6); + } + else if ((wait_ticks & 3) == 2) { + set_level(RAMP_SIZE/8); + } + // time out after 3 seconds + if (wait_ticks > TICKS_PER_SECOND*3) { + //number_entry_value = value; + set_level(0); + entry_step ++; + } + } + else if (entry_step == 4) { + number_entry_value = value; + pop_state(); + } + return EVENT_HANDLED; + } + // count clicks + else if (event == EV_click1_release) { + empty_event_sequence(); + if (entry_step == 3) { // only count during the "buzz" + value ++; + wait_ticks = 0; + // flash briefly + set_level(RAMP_SIZE/2); + delay_4ms(8/2); + set_level(0); + } + return EVENT_HANDLED; + } + return EVENT_NOT_HANDLED; +} + + +// find the ramp level closest to the target, +// using only the levels which are allowed in the current state +uint8_t nearest_level(int16_t target) { + // bounds check + // using int16_t here saves us a bunch of logic elsewhere, + // by allowing us to correct for numbers < 0 or > 255 in one central place + uint8_t mode_min = ramp_smooth_floor; + uint8_t mode_max = ramp_smooth_ceil; + if (ramp_style) { + mode_min = ramp_discrete_floor; + mode_max = ramp_discrete_ceil; + } + 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; + + uint8_t ramp_range = ramp_discrete_ceil - ramp_discrete_floor; + ramp_discrete_step_size = ramp_range / (ramp_discrete_steps-1); + uint8_t this_level = ramp_discrete_floor; + + for(uint8_t i=0; i>1)) + return this_level; + } + return this_level; +} + + +void blink_confirm(uint8_t num) { + for (; num>0; num--) { + set_level(MAX_LEVEL/4); + delay_4ms(10/4); + set_level(0); + delay_4ms(100/4); + } +} + + +#if defined(USE_INDICATOR_LED) && defined(TICK_DURING_STANDBY) +// beacon-like mode for the indicator LED +void indicator_blink(uint8_t arg) { + #define USE_FANCIER_BLINKING_INDICATOR + #ifdef USE_FANCIER_BLINKING_INDICATOR + + // fancy blink, set off/low/high levels here: + uint8_t seq[] = {0, 1, 2, 1, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0}; + indicator_led(seq[arg & 15]); + + #else // basic blink, 1/8th duty cycle + + if (! (arg & 7)) { + indicator_led(2); + } + else { + indicator_led(0); + } + + #endif +} +#endif + + +void load_config() { + if (load_eeprom()) { + ramp_style = eeprom[0]; + #ifdef USE_RAMP_CONFIG + ramp_smooth_floor = eeprom[1]; + ramp_smooth_ceil = eeprom[2]; + ramp_discrete_floor = eeprom[3]; + ramp_discrete_ceil = eeprom[4]; + ramp_discrete_steps = eeprom[5]; + #endif + #ifdef USE_BEACON_MODE + beacon_seconds = eeprom[6]; + #endif + #ifdef USE_THERMAL_REGULATION + therm_ceil = eeprom[EEPROM_BYTES_BASE]; + therm_cal_offset = eeprom[EEPROM_BYTES_BASE+1]; + #endif + #ifdef USE_INDICATOR_LED + indicator_led_mode = eeprom[EEPROM_BYTES_BASE+EEPROM_THERMAL_BYTES]; + #endif + } +} + +void save_config() { + eeprom[0] = ramp_style; + #ifdef USE_RAMP_CONFIG + eeprom[1] = ramp_smooth_floor; + eeprom[2] = ramp_smooth_ceil; + eeprom[3] = ramp_discrete_floor; + eeprom[4] = ramp_discrete_ceil; + eeprom[5] = ramp_discrete_steps; + #endif + #ifdef USE_BEACON_MODE + eeprom[6] = beacon_seconds; + #endif + #ifdef USE_THERMAL_REGULATION + eeprom[EEPROM_BYTES_BASE ] = therm_ceil; + eeprom[EEPROM_BYTES_BASE+1] = therm_cal_offset; + #endif + #ifdef USE_INDICATOR_LED + eeprom[EEPROM_BYTES_BASE+EEPROM_THERMAL_BYTES] = indicator_led_mode; + #endif + + save_eeprom(); +} + +void low_voltage() { + StatePtr state = current_state; + + // TODO: turn off aux LED(s) when power is really low + + if (0) {} // placeholder + + // in normal mode, step down or turn off + else if (state == steady_state) { + if (actual_level > 1) { + uint8_t lvl = (actual_level >> 1) + (actual_level >> 2); + set_level(lvl); + #ifdef USE_THERMAL_REGULATION + target_level = lvl; + #ifdef USE_SET_LEVEL_GRADUALLY + // not needed? + //set_level_gradually(lvl); + #endif + #endif + } + else { + set_state(off_state, 0); + } + } + // all other modes, just turn off when voltage is low + else { + set_state(off_state, 0); + } +} + + +void setup() { + // blink at power-on to let user know power is connected + set_level(RAMP_SIZE/8); + delay_4ms(3); + set_level(0); + + load_config(); + + push_state(off_state, 0); +} + + +void loop() { + + StatePtr state = current_state; + + if (0) {} + + #ifdef USE_BATTCHECK + else if (state == battcheck_state) { + battcheck(); + } + #endif + + #ifdef USE_BEACON_MODE + else if (state == beacon_state) { + beacon_mode_iter(); + } + #endif + + #ifdef USE_THERMAL_REGULATION + // TODO: blink out therm_ceil during thermal_config_state? + else if (state == tempcheck_state) { + blink_num(temperature); + nice_delay_ms(1000); + } + #endif + + #ifdef USE_IDLE_MODE + else { + // doze until next clock tick + idle_mode(); + } + #endif + +} diff --git a/ui/rampingios/rampingiosv3.svg b/ui/rampingios/rampingiosv3.svg new file mode 100644 index 0000000..bc9e6b3 --- /dev/null +++ b/ui/rampingios/rampingiosv3.svg @@ -0,0 +1,4113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + Ramps: + + + ThermalCfg + + + + + BeaconCfg + + + + + + Ramp + Ceil + Floor + + + Turbo + + + + + Mem + Regulated Hybrid -------------- Direct Drive + + + + + + + + + + + + Ramp + + Cfg + + + + + + Actions + 1 Fast Click + Hold + 3 Fast Clicks + Other Action + + + + 2 Fast Clicks + Click, Hold + RampingIOS V3 + + + + 7 Clicks + + + + OFF + + + + OFF + + + + + + + 4 Clicks + 4 Clicks + Click, Click, Hold + + 6 Clicks + + + + Smooth + + + + Ramp Cfg + + 4 Clicks + + + + 4 Clicks + + + + 1. Floor (click N times for level N)2. Ceiling (click N times for 1 + Turbo - N)3. Number of steps (stepped ramp only) + 1. Current temperature (click N times for N deg C)2. Temperature limit (click N times for 30 C + N) + 1. Beacon speed (click N times for N seconds per flash) + Thermal Cfg + Beacon Cfg + + 4 Clicks + + + + + + Stepped + + + + Tactical + + + BattCheck + + Lockout + + TempCheck + Beacon + + ThermalCfg + + + OFF + + + + + + + + + + + (momentary) + 3 Clicks + 4 Clicks + 6 Clicks + 8 Clicks + 10 Clicks + + + Aux LED + mode + next + + + + + + + + lockout LED + mode + next + 4 Clicks + 4 Clicks + 4 Clicks + + + + + -- cgit v1.2.3