diff options
| author | Selene ToyKeeper | 2023-11-02 17:16:25 -0600 |
|---|---|---|
| committer | Selene ToyKeeper | 2023-11-02 17:16:25 -0600 |
| commit | 7cb4fe0944b839f28dfd96a88a772cd6a8b58019 (patch) | |
| tree | 8d3b203f1650edc28b1f67e1589e3bc870b33fa6 /spaghetti-monster/spaghetti-monster.txt | |
| parent | added LICENSE (GPLv3) (diff) | |
| download | anduril-7cb4fe0944b839f28dfd96a88a772cd6a8b58019.tar.gz anduril-7cb4fe0944b839f28dfd96a88a772cd6a8b58019.tar.bz2 anduril-7cb4fe0944b839f28dfd96a88a772cd6a8b58019.zip | |
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)
Diffstat (limited to 'spaghetti-monster/spaghetti-monster.txt')
| -rw-r--r-- | spaghetti-monster/spaghetti-monster.txt | 325 |
1 files changed, 0 insertions, 325 deletions
diff --git a/spaghetti-monster/spaghetti-monster.txt b/spaghetti-monster/spaghetti-monster.txt deleted file mode 100644 index 434e1bc..0000000 --- a/spaghetti-monster/spaghetti-monster.txt +++ /dev/null @@ -1,325 +0,0 @@ -Spaghetti Monster: A UI toolkit library for flashlights -------------------------------------------------------- - -This toolkit takes care of most of the obnoxious parts of dealing with -tiny embedded chips and flashlight hardware, leaving you to focus on the -interface and user-visible features. - -For a quick start, look at the example UIs provided to see how things -are done. They are probably the most useful reference. However, other -details can be found here or in the FSM source code. - - -Why is it called Spaghetti Monster? - - This toolkit is a finite state machine, or FSM. Another thing FSM - stands for is Flying Spaghetti Monster. Source code tends to weave - into intricate knots like spaghetti, called spaghetti code, - particularly when the code isn't using appropriate abstractions for - the task it implements. - - Prior e-switch light code had a tendency to get pretty spaghetti-like, - and it made the code difficult to write, understand, and modify. So I - started from scratch and logically separated the hardware details from - the UI. This effectively put the spaghetti monster in a box, put it - on a leash, to make it behave and stay out of the way while we focus - on the user interface. - - Also, it's just kind of a fun name. :) - - -General concept: - - Spaghetti Monster (FSM) implements a stack-based finite state machine - with an event-handling system. - - Each FSM program should have a setup() function, a loop() function, - and at least one State: - - - The setup() function runs once each time power is connected. - - - The loop() function is called repeatedly whenever the system is - otherwise idle. Put your long-running tasks here, preferably with - consideration taken to allow for cooperative multitasking. - - - The States on the stack will be called whenever an event happens. - States are called in top-to-bottom order until a state returns an - "EVENT_HANDLED" signal. Only do quick tasks here. - - -Finite State Machine: - - Each "State" is simply a callback function which handles events. It - should return EVENT_HANDLED for each event type it does something - with, or EVENT_NOT_HANDLED otherwise. - - Transitions between states typically involve mapping an Event to a new - State, such as this: - - // 3 clicks: go to strobe modes - else if (event == EV_3clicks) { - set_state(strobe_state, 0); - return EVENT_HANDLED; - } - - It is strongly recommended that your State functions never do anything - which takes more than a few milliseconds... and certainly not longer - than 16ms. If you do this, the pending events may pile up to the - point where new events get thrown away. So, do only quick tasks in - the event handler, and do your longer-running tasks in the loop() - function instead. Preferably with precautions taken to allow for - cooperative multitasking. - - If your State function takes longer than one WDT tick (16ms) once in a - while, the system won't break. Several events can be queued. But be - sure not to do it very often. - - Several state management functions are provided: - - - set_state(new_state, arg): Replace the current state on the stack. - Send 'arg' to the new state for its init event. - - - push_state(new_state, arg): Add a new state to the stack, leaving - the current state below it. Send 'arg' to the new state for its - init event. - - - pop_state(): Get rid of (and return) the top-most state. Re-enter - the state below. - - -Event types: - - Event types are defined in fsm-events.h. You may want to adjust these - to fit your program, but the defaults are: - - State transitions: - - - EV_enter_state: Sent to each new State once when it goes onto - the stack. The 'arg' is whatever you define it to be. - - - EV_leave_state: Sent to a state immediately before it is removed - from the stack. - - - EV_reenter_state: If a State gets pushed on top of this one, and - then it pops off, a re-enter Event happens. This should handle - things like consuming the return value of a nested input handler - State. - - Time passing: - - - EV_tick: This happens once per clock tick, which is 16ms or - 62.5Hz by default. The 'arg' is the number of ticks since - entering the state. When 'arg' exceeds 65535, it wraps around - to 32768. - - - EV_sleep_tick: This happens every 0.5s during standby, if - enabled at compile time. The 'arg' is the number of ticks since - entering the state. When 'arg' exceeds 65535, it wraps around - to 32768. - - LVP and thermal regulation: - - - EV_voltage_low: Sent whenever the input power drops below the - VOLTAGE_LOW threshold. Minimum of VOLTAGE_WARNING_SECONDS - between events. - - - EV_temperature_high: Sent whenever the MCU's projected temperature - is higher than therm_ceil. Minimum of one second between events. - The 'arg' indicates how far the temperature exceeds the limit. - - - EV_temperature_low: Sent whenever the MCU's projected temperature - is lower than (therm_ceil - THERMAL_WINDOW_SIZE). Minimum of - one second between events. The 'arg' indicates how far the - temperature exceeds the limit. - - Button presses: - - Button events can be referred to either by pre-defined symbols, or - by teasing out the flags manually. The structure of a button - event is as follows: - - - Bit 7: 1 for button events, 0 otherwise. - - - Bit 6: 1 for a "timeout" event (signals the end of a - sequence), or 0 otherwise. - - - Bit 5: 1 for a "hold" event, 0 otherwise. This flag is only - necessary because, without it, it would be impossible to - distinguish between "click, click, timeout" and "click, hold, - release". - - - Bit 4: 1 if button is currently pressed, 0 otherwise. Button - release events look just like button press events, except this - is not set. - - - Bits 0,1,2,3: Counter for how many clicks there have been. - The first click is 1, second is 2, and it goes up to 15 clicks - in a row. Clicks after 15 are coded as 15. - - The pre-defined button event symbols are like the following: - - - EV_click1_press: The user pressed the button, but no time has - passed since then. - - - EV_click1_release: The user pressed and released the button, - but no time has passed since then. - - - EV_click1_complete: The user clicked the e-switch, released - it, and enough time passed that no more clicks were detected. - (a.k.a. EV_1click) - - - EV_click1_hold: The user pressed the button, and continued - holding it long enough to count as a "hold" event. This event - is sent once per timer tick as long as the button is held, and - the 'arg' value indicates how many timer ticks since the - button state went from 'press' to 'hold'. - - - EV_click1_hold_release: The button was released at the end of - a "hold" event. This is the end of the input sequence, - because no timeout period is used after a hold. - - It's worth noting that a "hold" event can only happen at the - end of an input sequence, and the sequence will reset to empty - after the hold is released. - - If the user pressed the button more than once, events follow the - same pattern. These are the same as above, except with a full - short-press and release first. - - - EV_click2_press - - EV_click2_release - - EV_click2_complete (a.k.a. EV_2clicks) - - EV_click2_hold - - EV_click2_hold_release - - Each of the above patterns continues up to 15 clicks. - - To match entire categories of events, use the bitmasks provided. - For example, to match button events where the button is down or - the button is up, the code would look like this: - - if ((event & (B_CLICK | B_PRESS)) == (B_CLICK | B_PRESS)) { - // button is down (can be a press event or a hold event) - } - else if ((event & (B_CLICK | B_PRESS)) == (B_CLICK)) { - // button was just released - } - - In theory, you could also define your own arbitrary event types, and - emit() them as necessary, and handle them in State functions the same - as any other event. - - -Cooperative multitasking: - - Since we don't have true preemptive multitasking, the best we can do - is cooperative multitasking. In practice, this means: - - - Declare global variables as volatile if they can be changed by an - event handler. This keeps the compiler from caching the value and - causing incorrect behavior. - - - Don't put long-running tasks into State functions. Each State - will get called at least once every 16ms for a clock tick, so they - should not run for longer than 16ms. - - - Put long-running tasks into loop() instead. - - - For long delay() calls, use nice_delay_ms(). This allows the MCU - to process events while we wait. It also automatically aborts if - it detects a state change, and returns a different value. - - In many cases, it shouldn't be necessary to do anything more than - this, but sometimes it will also be a good idea to check the - return value and abort the current task: - - if (! nice_delay_ms(mydelay)) break; - - - In general, try to do small amounts of work and then return - control to other parts of the program. Keep doing small amounts - and yielding until a task is done, instead of trying to do it all - at once. - - -Persistent data in EEPROM: - - To save data which lasts after a battery change, use the eeprom - functions. Define an eeprom style (or two) at the top, define how - many bytes to allocate, and then use the relevant functions as - appropriate. - - - USE_EEPROM / USE_EEPROM_WL: Enable the eeprom-related functions. - With "WL", it uses wear-levelling. Without, it does not. Note: - Wear levelling is not necessarily better -- it uses more ROM, and - it writes more bytes per save(). So, use it only for a few bytes - which change frequently -- not for many bytes or infrequent - changes. - - - EEPROM_BYTES N / EEPROM_WL_BYTES N: Allocate N bytes for the - eeprom data. - - - load_eeprom() / load_eeprom_wl(): Load the stored data into the - eeprom[] or eeprom_wl[] arrays. - Returns 1 if data was found, 0 otherwise. - - - save_eeprom() / save_eeprom_wl(): Save the eeprom[] or eeprom_wl[] - array data to persistent storage. The WL version erases all old - values and writes new ones in a different part of the eeprom - space. The non-WL version updates values in place, and does not - overwrite values which didn't change. - - Note that all interrupts will be disabled during eeprom operations. - - -Useful #defines: - - A variety of things can be #defined before including - spaghetti-monster.h in your program. This allows you to tweak the - behavior and set options to fit your needs: - - - FSM_something_LAYOUT: Select a driver type from tk-attiny.h. This - controls how many power channels there are, which pins they're on, - and what other driver features are available. - - - USE_LVP: Enable low-voltage protection. - - - VOLTAGE_LOW: What voltage should LVP trigger at? Defaults to 29 (2.9V). - - - VOLTAGE_FUDGE_FACTOR: Add this much to the voltage measurements, - to compensate for voltage drop across the reverse-polarity - diode. - - - VOLTAGE_WARNING_SECONDS: How long to wait between LVP events. - - - USE_THERMAL_REGULATION: Enable thermal regulation - - - DEFAULT_THERM_CEIL: Set the temperature limit to use by default - when the user hasn't configured anything. - - - USE_RAMPING: Enable smooth ramping helpers. - - - RAMP_LENGTH: Pick a pre-defined ramp by length. Defined sizes - are 50, 75, and 150 levels. - - - USE_DELAY_4MS, USE_DELAY_MS, USE_DELAY_ZERO: Enable the delay_4ms, - delay_ms(), and delay_zero() functions. Useful for timing-related - activities. - - - HOLD_TIMEOUT: How many clock ticks before a "press" event becomes - a "hold" event? - - - RELEASE_TIMEOUT: How many clock ticks before a "release" event - becomes a "click" event? Basically, the maximum time between - clicks in a double-click or triple-click. - - - USE_BATTCHECK: Enable the battcheck function. Also define one of - the following to select a display style: - - - BATTCHECK_VpT: Volts, pause, tenths. - - BATTCHECK_4bars: Blink up to 4 times. - - BATTCHECK_6bars: Blink up to 6 times. - - BATTCHECK_8bars: Blink up to 8 times. - - - ... and many others. Will try to document them over time, but - they can be found by searching for pretty much anything in - all-caps in the fsm-*.[ch] files. |
