messing with timers again; working on sticky keys
parent
f2acad70a4
commit
58255dc29b
|
@ -20,7 +20,7 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "../../../../../firmware/lib/data-types/list.h"
|
||||
#include "../../../../../firmware/lib/timer.h"
|
||||
#include "../../../../../firmware/lib/usb.h"
|
||||
#include "../../../../../firmware/lib/usb/usage-page/keyboard.h"
|
||||
#include "../../../../../firmware/lib/layout/key-functions.h"
|
||||
|
@ -113,13 +113,15 @@ static _layout_t PROGMEM _layout;
|
|||
* A collection of flags pertaining to the operation of `...exec_key()`
|
||||
*
|
||||
* Struct members:
|
||||
* - stick_current: TODO: probably just want 'tick_keypresses'?
|
||||
* - `tick_keypresses`: A predicate indicating whether or not to "tick"
|
||||
* keypresses on this run of the function (see the documentation in
|
||||
* ".../firmware/lib/timer.h" for more precisely what this means)
|
||||
* - This is useful for defining things like sticky keys, if, e.g., you
|
||||
* want to make it so that you can press more than one and have none of
|
||||
* them release until the press of the next normal key.
|
||||
*/
|
||||
static struct {
|
||||
bool stick_current : 1;
|
||||
bool stick_press : 1;
|
||||
bool stick_release : 1;
|
||||
bool unstick_all : 1;
|
||||
bool tick_keypresses : 1;
|
||||
} _flags;
|
||||
|
||||
|
||||
|
|
|
@ -31,11 +31,14 @@ void kb__layout__exec_key(bool pressed, uint8_t row, uint8_t column) {
|
|||
// we've previously set
|
||||
static uint8_t pressed_layer[OPT__KB__ROWS][OPT__KB__COLUMNS];
|
||||
|
||||
// TODO: keep track of sticky keys
|
||||
|
||||
void (*function)(void);
|
||||
uint8_t layer;
|
||||
|
||||
// - add 1 to the stack size because we spend the first iteration checking
|
||||
// to see if we need to release on a previously stored layer
|
||||
// - add 1 to the stack size in order to peek out of bounds on the last
|
||||
// iteration (if we get that far), so that layer 0 is our default (see
|
||||
// the documentation for ".../firmware/lib/layout/layer-stack.h")
|
||||
for (uint8_t i=0; i < layer_stack__size()+1+1; i++) { // i = offset+1
|
||||
if (i == 0)
|
||||
if (!pressed)
|
||||
|
@ -60,11 +63,10 @@ void kb__layout__exec_key(bool pressed, uint8_t row, uint8_t column) {
|
|||
|
||||
(*function)();
|
||||
|
||||
// TODO: implement sticky keys
|
||||
// if (pressed && _sticky_key) {
|
||||
// (*_sticky_key)();
|
||||
// _sticky_key = NULL;
|
||||
// }
|
||||
if (_flags.tick_keypresses)
|
||||
timer___tick_keypresses();
|
||||
|
||||
_flags.tick_keypresses = true; // restore default
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -97,8 +97,10 @@
|
|||
* #define keys__release__lpo1l1 KF(nop)
|
||||
*/
|
||||
#define KEYS__LAYER__PUSH_POP(ID, LAYER) \
|
||||
void P(lpupo##ID##l##LAYER) (void) { layer_stack__push(0, ID, LAYER); } \
|
||||
void R(lpupo##ID##l##LAYER) (void) { layer_stack__pop_id(ID); }
|
||||
void P(lpupo##ID##l##LAYER) (void) { layer_stack__push(0, ID, LAYER); \
|
||||
_flags.tick_keypresses = false; } \
|
||||
void R(lpupo##ID##l##LAYER) (void) { layer_stack__pop_id(ID); \
|
||||
_flags.tick_keypresses = false; }
|
||||
|
||||
/** macros/(group) layer : number pad/description
|
||||
* Define functions for pushing and popping the number pad (namely `numPush`,
|
||||
|
@ -117,22 +119,28 @@
|
|||
KF(press)(KEYBOARD__LockingNumLock); \
|
||||
usb__kb__send_report(); \
|
||||
KF(release)(KEYBOARD__LockingNumLock); \
|
||||
usb__kb__send_report(); } \
|
||||
usb__kb__send_report(); \
|
||||
_flags.tick_keypresses = false; } \
|
||||
void R(numPuPo) (void) { layer_stack__pop_id(ID); \
|
||||
KF(press)(KEYBOARD__LockingNumLock); \
|
||||
usb__kb__send_report(); \
|
||||
KF(release)(KEYBOARD__LockingNumLock); \
|
||||
usb__kb__send_report(); }
|
||||
usb__kb__send_report(); \
|
||||
_flags.tick_keypresses = false; }
|
||||
|
||||
#define KEYS__LAYER__NUM_PUSH(ID, LAYER) \
|
||||
void P(numPush) (void) { layer_stack__push(0, ID, LAYER); \
|
||||
KF(press)(KEYBOARD__LockingNumLock); } \
|
||||
void R(numPush) (void) { KF(release)(KEYBOARD__LockingNumLock); }
|
||||
KF(press)(KEYBOARD__LockingNumLock); \
|
||||
_flags.tick_keypresses = false; } \
|
||||
void R(numPush) (void) { KF(release)(KEYBOARD__LockingNumLock); \
|
||||
_flags.tick_keypresses = false; }
|
||||
|
||||
#define KEYS__LAYER__NUM_POP(ID) \
|
||||
void P(numPop) (void) { layer_stack__pop_id(ID); \
|
||||
KF(press)(KEYBOARD__LockingNumLock); } \
|
||||
void R(numPop) (void) { KF(release)(KEYBOARD__LockingNumLock); }
|
||||
KF(press)(KEYBOARD__LockingNumLock); \
|
||||
_flags.tick_keypresses = false; } \
|
||||
void R(numPop) (void) { KF(release)(KEYBOARD__LockingNumLock); \
|
||||
_flags.tick_keypresses = false; }
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -28,13 +28,13 @@
|
|||
* something like
|
||||
*
|
||||
* typedef struct {
|
||||
* list__node_t _private; // must be the first element
|
||||
* list__node_t _super; // must be the first element
|
||||
* uint8_t data;
|
||||
* } node_t;
|
||||
*
|
||||
* - If you want to iterate through a list, use something like
|
||||
*
|
||||
* for (node_t * node = list.head; node; node = node->_private.next) {
|
||||
* for (node_t * node = list.head; node; node = node->_super.next) {
|
||||
* // do stuff
|
||||
* }
|
||||
*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* Prefix: `layer_stack__`
|
||||
*
|
||||
* This file is meant to be included and used by the keyboard layout
|
||||
* implemenmtation.
|
||||
* implementation.
|
||||
*/
|
||||
|
||||
|
||||
|
|
|
@ -8,11 +8,36 @@
|
|||
* Timer interface
|
||||
*
|
||||
* Prefixes: `timer__`, `timer___`
|
||||
*
|
||||
*
|
||||
* Usage notes:
|
||||
* - A "tick" is an ill-defined unit of time. It may represent any occurrence,
|
||||
* even a randomly timed one; but it makes the most sense for it to count
|
||||
* something that occurs predictably, like the passing of a millisecond, or
|
||||
* the completion of a scan cycle.
|
||||
*
|
||||
* - To "tick" (as a verb) is to denote the passage of a "tick" of time by
|
||||
* performing the actions corresponding thereto (i.e. incrementing the
|
||||
* counter and running any scheduled events).
|
||||
*
|
||||
* - A "timer" is a collection of related `...get...()`, `...schedule...()`,
|
||||
* and `...tick...()` functions, all dealing with the same (not externally
|
||||
* visible) variables.
|
||||
*
|
||||
* - For milliseconds
|
||||
*
|
||||
* ---------------------------------------------------------------------
|
||||
* number highest value in in in in
|
||||
* of bits (milliseconds) seconds minutes hours days
|
||||
* --------- ---------------- ----------- --------- -------- ------
|
||||
* 8 255 0.3 0.0 0.0 0.0
|
||||
* 16 65535 65.5 1.1 0.0 0.0
|
||||
* 32 4294967295 4294967.3 71582.8 1193.0 49.7
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
* note: 32-bit values given for reference only
|
||||
*/
|
||||
|
||||
// TODO: make macros for defining timers; make groups for function
|
||||
// documentation; make notes for all extra information
|
||||
|
||||
|
||||
#ifndef ERGODOX_FIRMWARE__LIB__TIMER__H
|
||||
#define ERGODOX_FIRMWARE__LIB__TIMER__H
|
||||
|
@ -23,17 +48,19 @@
|
|||
uint8_t timer__init (void);
|
||||
|
||||
uint16_t timer__get_cycles (void);
|
||||
uint16_t timer__get_keypresses (void);
|
||||
uint16_t timer__get_milliseconds (void);
|
||||
|
||||
uint8_t timer__schedule_cycles ( uint16_t cycles,
|
||||
void(*function)(void) );
|
||||
uint8_t timer__schedule_milliseconds ( uint16_t milliseconds,
|
||||
void(*function)(void) );
|
||||
uint8_t timer__schedule_cycles (uint16_t ticks, void(*function)(void));
|
||||
uint8_t timer__schedule_keypresses (uint16_t ticks, void(*function)(void));
|
||||
uint8_t timer__schedule_milliseconds (uint16_t ticks, void(*function)(void));
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// private
|
||||
|
||||
void timer___tick_cycles (void);
|
||||
void timer___tick_cycles (void);
|
||||
void timer___tick_keypresses (void);
|
||||
void timer___tick_milliseconds (void);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -63,63 +90,44 @@ void timer___tick_cycles (void);
|
|||
* - Should be called exactly once by `main()` before entering the run loop.
|
||||
*/
|
||||
|
||||
// === timer__get_cycles() ===
|
||||
/** functions/timer__get_cycles/description
|
||||
* Return the number of scan cycles since the timer was initialized (mod 2^16)
|
||||
// === (group) get() ===
|
||||
/** functions/(group) get/description
|
||||
* Return the number of "ticks" since the given timer was initialized
|
||||
* (mod 2^16)
|
||||
*
|
||||
* Members:
|
||||
* - `timer__get_cycles`
|
||||
* - `timer__get_keypresses`
|
||||
* - `timer__get_milliseconds`
|
||||
*
|
||||
* Returns:
|
||||
* - success: The number of cycles since the timer was initialized (mod 2^16)
|
||||
*
|
||||
* Usage notes:
|
||||
* - See the documentation for `timer__get_milliseconds()`
|
||||
*/
|
||||
|
||||
// === timer__get_milliseconds() ===
|
||||
/** functions/timer__get_milliseconds/description
|
||||
* Return the number of milliseconds since the timer was initialized (mod 2^16)
|
||||
*
|
||||
* ---------------------------------------------------------------------
|
||||
* number highest value in in in in
|
||||
* of bits (milliseconds) seconds minutes hours days
|
||||
* --------- ---------------- ----------- --------- -------- ------
|
||||
* 8 255 0.3 0.0 0.0 0.0
|
||||
* 16 65535 65.5 1.1 0.0 0.0
|
||||
* 32 4294967295 4294967.3 71582.8 1193.0 49.7
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
* note: 32-bit values given for reference only
|
||||
*
|
||||
*
|
||||
* Returns:
|
||||
* - success: The number of milliseconds since the timer was initialized (mod
|
||||
* 2^16)
|
||||
* - success: The number of "ticks" since the timer was initialized (mod 2^16)
|
||||
*
|
||||
*
|
||||
* Usage notes:
|
||||
*
|
||||
* - It's unnecessary to keep 16-bit resolution when storing the value returned
|
||||
* by `timer__get_milliseconds()` if you don't need it. Use variables of the
|
||||
* smallest type that can (*always*) hold the amount of time you'll be
|
||||
* dealing with.
|
||||
* by a get function if you don't need it. Use variables of the smallest
|
||||
* type that can (*always*) hold the amount of time you'll be dealing with.
|
||||
*
|
||||
* - Use `end_time - start_time` for determining time difference. Since the
|
||||
* returned values are unsigned (and you should be storing them in unsigned
|
||||
* variables as well) this will work across overflows, for up to the maximum
|
||||
* amount of milliseconds representable by the type you're using. (See [this
|
||||
* answer] (http://stackoverflow.com/a/50632) on <http://stackoverflow.com/>
|
||||
* if you're curious as to why this workes across overflows.)
|
||||
* if you're curious as to why this works across overflows.)
|
||||
*
|
||||
*
|
||||
* Warnings:
|
||||
*
|
||||
* - Do not cast the return value of `timer__get_milliseconds()` directly.
|
||||
* Instead, store the return value in a smaller variable
|
||||
* - Do not cast the return value of a get function directly. Instead, store
|
||||
* the return value in a smaller variable
|
||||
*
|
||||
* uint8_t start_time = timer__get_milliseconds()
|
||||
* uint8_t start_time = timer__get_cycles()
|
||||
*
|
||||
* or cast the expression as a whole
|
||||
*
|
||||
* (uint8_t)( timer__get_milliseconds() - start_time )
|
||||
* (uint8_t)( timer__get_cycles() - start_time )
|
||||
*
|
||||
* Casting directly within the end condition check of a `while` or `for` loop
|
||||
* does not produce the desired behavior. I don't know assembly well enough
|
||||
|
@ -145,53 +153,38 @@ void timer___tick_cycles (void);
|
|||
* except within the first 2^8 milliseconds of the timer being initialized.
|
||||
*/
|
||||
|
||||
// === timer__schedule_cycles() ===
|
||||
/** functions/timer__schedule_cycles/description
|
||||
* Schedule `function` to run in the given number of cycles
|
||||
// === (group) schedule() ===
|
||||
/** functions/(group) schedule/description
|
||||
* Schedule `function` to run in the given number of "ticks"
|
||||
*
|
||||
* Members:
|
||||
* - `timer__schedule_cycles`
|
||||
* - `timer__schedule_keypresses`
|
||||
* - `timer__schedule_milliseconds`
|
||||
*
|
||||
* Arguments:
|
||||
* - `cycles`: The number of cycles to wait
|
||||
* - `ticks`: The number of ticks to wait
|
||||
* - `function`: A pointer to the function to run
|
||||
*
|
||||
* Returns:
|
||||
* - success: `0`
|
||||
* - failure: [other]
|
||||
*
|
||||
* Usage notes:
|
||||
* - If possible, prefer this function to `timer__schedule_milliseconds()`: it
|
||||
* has slightly lower overhead (since scan cycles are going to be longer than
|
||||
* 1 millisecond); and since functions scheduled here are not executed inside
|
||||
* an interrupt vector, you need not worry about any of them messing with
|
||||
* access to a shared resource.
|
||||
*/
|
||||
|
||||
// === timer__schedule_milliseconds() ===
|
||||
/** functions/timer__schedule_milliseconds/description
|
||||
* Schedule `function` to run in the given number of milliseconds
|
||||
*
|
||||
* Arguments:
|
||||
* - `milliseconds`: The number of milliseconds to wait
|
||||
* - `function`: A pointer to the function to run
|
||||
*
|
||||
* Returns:
|
||||
* - success: `0`
|
||||
* - failure: [other]
|
||||
*
|
||||
* Usage notes:
|
||||
* - Functions will be run with interrupts enabled, so you need not worry more
|
||||
* than usual about how long your function takes.
|
||||
*
|
||||
* - If a function needs a longer wait time than is possible with a 16-bit
|
||||
* millisecond resolution counter, it can repeatedly schedule itself to run
|
||||
* in, say, 1 minute (= 1000*60 milliseconds), increment a counter each time,
|
||||
* and then only execute its body code after, say, 5 calls (for a 5 minute
|
||||
* delay).
|
||||
* resolution counter, it can repeatedly schedule itself to run in, say, 1
|
||||
* minute (= 1000*60 milliseconds) (using the millisecond timer), increment a
|
||||
* counter each time, and then only execute its body code after, say, 5 calls
|
||||
* (for a 5 minute delay).
|
||||
*
|
||||
* Warnings:
|
||||
* - Be *very* careful when using this to schedule functions that share
|
||||
* resources: functions scheduled here are still called from within an
|
||||
* interrupt vector, and the interrupt vector may have interrupted something
|
||||
* else in the middle of an access to that resource. You must pay full
|
||||
* attention to all the issues this could possibly cause.
|
||||
* - The milliseconds timer is unique in that events may not be run as soon as
|
||||
* one would expect: all events scheduled to be run sometime during a scan
|
||||
* cycle should be run at the end of that scan cycle. This is done to avoid
|
||||
* having scheduled functions executing within an interrupt vector, which is
|
||||
* (in a case like this where everything has to be so generalized) really not
|
||||
* worth the pain.
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -202,11 +195,28 @@ void timer___tick_cycles (void);
|
|||
* Increment the counter for the number of cycles, and perform scheduled tasks
|
||||
*
|
||||
* Meant to be used only by `main()`
|
||||
*
|
||||
* Notes:
|
||||
* - See "./event-list.h" regarding the function name.
|
||||
* - The corresponding real-time function (dealing with milliseconds instead of
|
||||
* cycles) will be in an interrupt vector, and not explicitly called anywhere
|
||||
* in the code.
|
||||
*/
|
||||
|
||||
// === timer___tick_keypresses() ===
|
||||
/** functions/timer___tick_keypresses/description
|
||||
* Increment the counter for the number of keypresses, and perform scheduled
|
||||
* tasks
|
||||
*
|
||||
* Meant to be used only by `kb__layout__exec_key()`
|
||||
*/
|
||||
|
||||
// === timer___tick_milliseconds() ===
|
||||
/** functions/timer___tick_milliseconds/description
|
||||
* Perform scheduled tasks *only*
|
||||
*
|
||||
* Meant to be used only by `main()`
|
||||
*
|
||||
* The counter for this timer should be incremented within an interrupt vector
|
||||
* (and so needs no `...tick...()` function), but in order to avoid the
|
||||
* complications of having scheduled functions run within the interrupt vector
|
||||
* as well, this function splits that portion of the timer's functionality out.
|
||||
* It should be called by `main()` once per cycle, and should execute all tasks
|
||||
* that were scheduled to be run between the last time it was called and the
|
||||
* time of the current call.
|
||||
*/
|
||||
|
||||
|
|
|
@ -45,14 +45,22 @@ uint16_t timer__get_milliseconds(void) {
|
|||
return _milliseconds__counter;
|
||||
}
|
||||
|
||||
uint8_t timer__schedule_milliseconds( uint16_t milliseconds,
|
||||
void(*function)(void)) {
|
||||
uint8_t timer__schedule_milliseconds(uint16_t ticks, void(*function)(void)) {
|
||||
return event_list__append(
|
||||
_milliseconds__scheduled_events, milliseconds, function );
|
||||
_milliseconds__scheduled_events, ticks, function );
|
||||
}
|
||||
|
||||
void timer___tick_milliseconds(void) {
|
||||
static uint8_t _milliseconds__last_ticked;
|
||||
uint8_t elapsed = timer__get_milliseconds() - _milliseconds__last_ticked;
|
||||
|
||||
for (uint8_t i=0; i<elapsed; i++)
|
||||
event_list__tick(_milliseconds__scheduled_events);
|
||||
|
||||
_milliseconds__last_ticked += elapsed;
|
||||
}
|
||||
|
||||
ISR(TIMER0_COMPA_vect) {
|
||||
_milliseconds__counter++;
|
||||
event_list__tick(_milliseconds__scheduled_events);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2013 Ben Blazak <benblazak.dev@gmail.com>
|
||||
* Released under The MIT License (see "doc/licenses/MIT.md")
|
||||
* Project located at <https://github.com/benblazak/ergodox-firmware>
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/** description
|
||||
* Implements the event-list interface defined in "../event-list.h"
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "../../../firmware/lib/data-types/list.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
list__node_t _super; // "subclass" `list__node_t`
|
||||
uint16_t ticks; // our unit of time
|
||||
void(*function)(void);
|
||||
} event_t;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
uint8_t event_list__append( list__list_t list,
|
||||
uint16_t ticks,
|
||||
void(*function)(void) ) {
|
||||
if (!function) return 0; // success: nothing to do
|
||||
|
||||
event_t * event = malloc(sizeof(event_t));
|
||||
if (!event) return 1; // error
|
||||
|
||||
event->ticks = ticks;
|
||||
event->function = function;
|
||||
|
||||
list__insert(list, -1, event);
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
void event_list__tick(list__list_t list) {
|
||||
for (event_t * event = list.head; event;) {
|
||||
if (event->ticks == 0) {
|
||||
(*event->function)();
|
||||
event = list__pop_node_next(list, event);
|
||||
} else {
|
||||
event->ticks--;
|
||||
event = event->_super.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,28 +9,11 @@
|
|||
*
|
||||
* Prefix: `event_list__`
|
||||
*
|
||||
* Meant to be used only within ".../firmware/lib/timer"
|
||||
*
|
||||
*
|
||||
* Usage notes:
|
||||
*
|
||||
* - A "tick" is an ill-defined unit of time. It may represent any occurrence,
|
||||
* even a randomly timed one; but it makes the most sense for it to count
|
||||
* something that occurs predictably, like the passing of a millisecond, or
|
||||
* the completion of a scan cycle.
|
||||
*
|
||||
* - To "tick" (as a verb) is to denote the passage of a "tick" of time by
|
||||
* performing the actions corresponding thereto (i.e. incrementing the
|
||||
* counter and running any scheduled events).
|
||||
*
|
||||
* - All functions declared here should be safe for use within interrupt
|
||||
* routines, as long as you pay attention to the warnings below.
|
||||
*
|
||||
* Meant to be used within ".../firmware/lib/timer"
|
||||
*
|
||||
* Warnings:
|
||||
*
|
||||
* - Any list passed as an argument to one of these functions must not be used
|
||||
* *anywhere* except as an argument to one of these functions.
|
||||
* - These functions are not safe for use within interrupt vectors. Just in
|
||||
* case you were tempted to try :)
|
||||
*/
|
||||
|
||||
|
||||
|
@ -87,5 +70,10 @@ void event_list__tick (list__list_t list);
|
|||
*
|
||||
* Arguments:
|
||||
* - `list`: The list to "tick"
|
||||
*
|
||||
* Implementation notes:
|
||||
* - In the case that more than one function is scheduled to run on a given
|
||||
* "tick", the functions should be run in the order in which they were
|
||||
* scheduled.
|
||||
*/
|
||||
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
/* ----------------------------------------------------------------------------
|
||||
* Copyright (c) 2013 Ben Blazak <benblazak.dev@gmail.com>
|
||||
* Released under The MIT License (see "doc/licenses/MIT.md")
|
||||
* Project located at <https://github.com/benblazak/ergodox-firmware>
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/** description
|
||||
* Implements the event-list interface defined in "../event-list.h" for the
|
||||
* ATMega32U4
|
||||
*
|
||||
* Notes:
|
||||
* - The code should be the same for anything in the AVR family. It's the
|
||||
* `<util/atomic>` macros that make this non-universal.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <util/atomic.h>
|
||||
#include "../../../../firmware/lib/data-types/list.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
list__node_t _private; // "subclass" `list__node_t`
|
||||
uint16_t ticks; // our unit of time
|
||||
void(*function)(void);
|
||||
} event_t;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
uint8_t event_list__append( list__list_t list,
|
||||
uint16_t ticks,
|
||||
void(*function)(void) ) {
|
||||
if (!function) return 0; // success: nothing to do
|
||||
|
||||
event_t * event = malloc(sizeof(event_t));
|
||||
if (!event) return 1; // error
|
||||
|
||||
event->ticks = ticks;
|
||||
event->function = function;
|
||||
|
||||
ATOMIC_BLOCK( ATOMIC_RESTORESTATE ) {
|
||||
list__insert(list, -1, event);
|
||||
}
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
void event_list__tick(list__list_t list) {
|
||||
event_t * next;
|
||||
event_t * run = NULL; // for keeping track of events to run
|
||||
|
||||
// go through the list
|
||||
// - keep track of the events that need to be run this "tick"
|
||||
// - note that every other event is one "tick" closer to being run
|
||||
ATOMIC_BLOCK( ATOMIC_RESTORESTATE ) {
|
||||
for (event_t * event = list.head; event;) {
|
||||
if (event->ticks == 0) {
|
||||
next = event->_private.next;
|
||||
list__pop_node(list, event);
|
||||
event->_private.next = run;
|
||||
run = event;
|
||||
event = next;
|
||||
} else {
|
||||
event->ticks--;
|
||||
event = event->_private.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run all the scheduled events, with interrupts enabled
|
||||
NONATOMIC_BLOCK( NONATOMIC_RESTORESTATE ) {
|
||||
while (run) {
|
||||
next = run->_private.next;
|
||||
(*run->function)();
|
||||
free(run);
|
||||
run = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -35,6 +35,5 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
DEFINE_TIMER(cycles);
|
||||
|
||||
// TODO: make a timer for keypresses?
|
||||
DEFINE_TIMER(keypresses);
|
||||
|
||||
|
|
|
@ -129,6 +129,7 @@ int main(void) {
|
|||
}
|
||||
|
||||
timer___tick_cycles();
|
||||
timer___tick_milliseconds();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -92,7 +92,7 @@ extern struct main__flags_t main__flags;
|
|||
* A collection of flags pertaining to the operation of `main()`
|
||||
*
|
||||
* Struct members:
|
||||
* - update_leds: A predicate indicating whether to update the keyboard LED
|
||||
* - `update_leds`: A predicate indicating whether to update the keyboard LED
|
||||
* state based on the USB LED state.
|
||||
* - This is for taking over control the LEDs temporarily, as one may want
|
||||
* to do when in a special mode, etc. If you want to change the meaning
|
||||
|
|
Loading…
Reference in New Issue