(in the middle of a lot of misc changes)

partial-rewrite
Ben Blazak 2013-05-24 12:35:08 -07:00
parent 4628061b53
commit d3e9291d49
11 changed files with 111 additions and 149 deletions

View File

@ -139,10 +139,23 @@
Yes. The memory manager keeps track of the size of allocations - and the
pointer you pass to `free()` is cast to `void *` before deallocation anyway.
* [Why exactly should I not call free() on variables not allocated by malloc()?]
(http://stackoverflow.com/questions/2688377/why-exactly-should-i-not-call-free-on-variables-not-allocated-by-malloc)
But it's not safe to call `free()` on non-`malloc()`ed things.
* [Why do we need C Unions?]
(http://stackoverflow.com/questions/252552/why-do-we-need-c-unions)
Some good examples of what Unions are good for.
* [C preprocessor, recursive macros]
(http://stackoverflow.com/questions/5641836/c-preprocessor-recursive-macros)
I'm not entirely sure I understand what's going on... but be it known that
function like macros that expand into other function like macros are tricky
business.
* [Declaring and Using Bit Fields in Structures]
(http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=%2Fcom.ibm.vacpp6m.doc%2Flanguage%2Fref%2Fclrc03defbitf.htm)
### C++ Stuff
* [Google C++ Style Guide]

View File

@ -20,11 +20,12 @@
#include <stddef.h>
#include <stdint.h>
#include <avr/pgmspace.h>
#include "../../../../../firmware/keyboard.h"
#include "../../../../../firmware/lib/data-types/list.h"
#include "../../../../../firmware/lib/usb.h"
#include "../../../../../firmware/lib/usb/usage-page/keyboard.h"
#include "../../../../../firmware/lib/layout/key-functions.h"
#include "../../../../../firmware/lib/layout/layer-stack.h"
#include "../../../../../firmware/keyboard.h"
// ----------------------------------------------------------------------------
@ -41,7 +42,7 @@
/** macros/K/description
* Expand into a "key" suitable for putting into the layout matrix
*/
#define K(name) { &P(name), &R(name) }
#define K(name) { &keys__press__##name, &keys__release__##name }
/** macros/KF/description
* Expand `name` into the corresponding "key_functions" function name
@ -79,7 +80,7 @@ void KF(nop) (void) {}
// ----------------------------------------------------------------------------
/** typedefs/_key_t/description
/** types/_key_t/description
* The type we will use for our "key"s
*
* Notes:
@ -92,7 +93,7 @@ void KF(nop) (void) {}
*/
typedef void (*_key_t[2])(void);
/** typedefs/_layout_t/description
/** types/_layout_t/description
* The type we will use for our layout matrix
*
* Notes:
@ -101,26 +102,25 @@ typedef void (*_key_t[2])(void);
*/
typedef const _key_t _layout_t[][OPT__KB__ROWS][OPT__KB__COLUMNS];
/** variables/layout/description
// ----------------------------------------------------------------------------
/** variables/_layout/description
* The variable containing our layout matrix
*/
static _layout_t PROGMEM _layout;
/** variables/sticky_key/description
* A pointer to the release function of the last sticky key pressed
/** variables/_flags/description
* A collection of flags pertaining to the operation of `...exec_key()`
*
* The function pointed to by this should be executed directly after executing
* the "press" function of the next key pressed.
*
* Notes:
* - In order for things to work right, sticky keys should either execute this
* stored function themselves before placing their own "release" function
* value here, or else save the value that's here and call it as part of
* their own "release" function. If this isn't done, and the key pressed
* directly before this was a sticky key as well, then the previous sticky
* key will never be released.
* Struct members:
* - stick_current: TODO: probably just want 'tick_keypresses'?
*/
static void (*_sticky_key)(void);
static struct {
bool stick_current : 1;
bool stick_press : 1;
bool stick_release : 1;
bool unstick_all : 1;
} _flags;
// ----------------------------------------------------------------------------

View File

@ -23,14 +23,16 @@
void kb__layout__exec_key(bool pressed, uint8_t row, uint8_t column) {
// keep track of the layer the key was pressed on, so we can release it on
// the same layer
// if we press a key, we need to keep track of the layer it was pressed on,
// so we can release it on the same layer
// - if the release is transparent, search through the layer stack for a
// non-transparent release in the same position, as normal
// - don't need to initialize, since we'll only read from positions that
// 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;
@ -58,10 +60,11 @@ void kb__layout__exec_key(bool pressed, uint8_t row, uint8_t column) {
(*function)();
if (pressed && _sticky_key) {
(*_sticky_key)();
_sticky_key = NULL;
}
// TODO: implement sticky keys
// if (pressed && _sticky_key) {
// (*_sticky_key)();
// _sticky_key = NULL;
// }
return;
}

View File

@ -11,6 +11,8 @@
* Meant to be included *only* by the layout using it.
*/
// TODO: make a KF for windows/mac style unicode input
// TODO: write a chordmak (or asetniop) layout, on top of a standard colemak
// layout, using chained sticky keys for the modifiers
@ -22,6 +24,7 @@
// - sticky keys
// - macros
// - chorded keys
// - timed keys
// - layers
// - making layouts
// - changing the meaning of the LEDs
@ -88,16 +91,10 @@
* (only) functions may be defined as follows (using the example `lpupo1l1`
* from above):
*
* #define keys__press__lpu1l1 keys__press__lpupo1l1
* #define keys__press__lpu1l1 P(lpupo1l1)
* #define keys__release__lpu1l1 KF(nop)
* #define keys__press__lpo1l1 R(lpupo1l1)
* #define keys__release__lpo1l1 KF(nop)
*
* - Also note that writing `#define keys__press__lpu1l1 P(lpupo1l1)` will
* not work. My guess is that this has something to do with the fact that,
* if things are being expanded within the layout definition, the left hand
* side "press" function names will themselves have been expanded by the
* `P()` macro; but I'm not really sure why that makes a difference.
*/
#define KEYS__LAYER__PUSH_POP(ID, LAYER) \
void P(lpupo##ID##l##LAYER) (void) { layer_stack__push(0, ID, LAYER); } \
@ -213,61 +210,61 @@ void R(btldr) (void) {}
// them if they're inconvenient
KEYS__LAYER__PUSH_POP(0, 0);
#define keys__press__lpu0l0 keys__press__lpupo0l0
#define keys__press__lpu0l0 P(lpupo0l0)
#define keys__release__lpu0l0 KF(nop)
#define keys__press__lpo0l0 R(lpupo0l0)
#define keys__release__lpo0l0 KF(nop)
KEYS__LAYER__PUSH_POP(1, 1);
#define keys__press__lpu1l1 keys__press__lpupo1l1
#define keys__press__lpu1l1 P(lpupo1l1)
#define keys__release__lpu1l1 KF(nop)
#define keys__press__lpo1l1 R(lpupo1l1)
#define keys__release__lpo1l1 KF(nop)
KEYS__LAYER__PUSH_POP(2, 2);
#define keys__press__lpu2l2 keys__press__lpupo2l2
#define keys__press__lpu2l2 P(lpupo2l2)
#define keys__release__lpu2l2 KF(nop)
#define keys__press__lpo2l2 R(lpupo2l2)
#define keys__release__lpo2l2 KF(nop)
KEYS__LAYER__PUSH_POP(3, 3);
#define keys__press__lpu3l3 keys__press__lpupo3l3
#define keys__press__lpu3l3 P(lpupo3l3)
#define keys__release__lpu3l3 KF(nop)
#define keys__press__lpo3l3 R(lpupo3l3)
#define keys__release__lpo3l3 KF(nop)
KEYS__LAYER__PUSH_POP(4, 4);
#define keys__press__lpu4l4 keys__press__lpupo4l4
#define keys__press__lpu4l4 P(lpupo4l4)
#define keys__release__lpu4l4 KF(nop)
#define keys__press__lpo4l4 R(lpupo4l4)
#define keys__release__lpo4l4 KF(nop)
KEYS__LAYER__PUSH_POP(5, 5);
#define keys__press__lpu5l5 keys__press__lpupo5l5
#define keys__press__lpu5l5 P(lpupo5l5)
#define keys__release__lpu5l5 KF(nop)
#define keys__press__lpo5l5 R(lpupo5l5)
#define keys__release__lpo5l5 KF(nop)
KEYS__LAYER__PUSH_POP(6, 6);
#define keys__press__lpu6l6 keys__press__lpupo6l6
#define keys__press__lpu6l6 P(lpupo6l6)
#define keys__release__lpu6l6 KF(nop)
#define keys__press__lpo6l6 R(lpupo6l6)
#define keys__release__lpo6l6 KF(nop)
KEYS__LAYER__PUSH_POP(7, 7);
#define keys__press__lpu7l7 keys__press__lpupo7l7
#define keys__press__lpu7l7 P(lpupo7l7)
#define keys__release__lpu7l7 KF(nop)
#define keys__press__lpo7l7 R(lpupo7l7)
#define keys__release__lpo7l7 KF(nop)
KEYS__LAYER__PUSH_POP(8, 8);
#define keys__press__lpu8l8 keys__press__lpupo8l8
#define keys__press__lpu8l8 P(lpupo8l8)
#define keys__release__lpu8l8 KF(nop)
#define keys__press__lpo8l8 R(lpupo8l8)
#define keys__release__lpo8l8 KF(nop)
KEYS__LAYER__PUSH_POP(9, 9);
#define keys__press__lpu9l9 keys__press__lpupo9l9
#define keys__press__lpu9l9 P(lpupo9l9)
#define keys__release__lpu9l9 KF(nop)
#define keys__press__lpo9l9 R(lpupo9l9)
#define keys__release__lpo9l9 KF(nop)

View File

@ -4,6 +4,9 @@
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
// TODO: change from using pointers to everything, to just using the things
// (since they're structs anyway)
/** description
* An interface to a simple linked-list that can be used to implement lists,
* queues, stacks, and things
@ -77,7 +80,6 @@ typedef struct list__list_t {
// ----------------------------------------------------------------------------
list__list_t * list__new (void);
void * list__insert ( list__list_t * list,
int8_t index,
void * node );
@ -100,16 +102,16 @@ void list__free (list__list_t * list);
// ----------------------------------------------------------------------------
// typedefs -------------------------------------------------------------------
// types ----------------------------------------------------------------------
// ----------------------------------------------------------------------------
// === list__node_t ===
/** typedefs/list__node_t/description
/** types/list__node_t/description
* The type of a "node", for the purposes of this library
*/
// === list__list_t ===
/** typedefs/list__list_t/description
/** types/list__list_t/description
* Simple struct to define and keep track of our list
*/
@ -118,15 +120,6 @@ void list__free (list__list_t * list);
// functions ------------------------------------------------------------------
// ----------------------------------------------------------------------------
// === list__new() ===
/** functions/list__new/description
* Allocate a new (empty) list
*
* Returns:
* - success: A pointer to the new list
* - failure: `NULL`
*/
// === list__insert() ===
/** functions/list__insert/description
* Insert `node` at position `index % list->length`
@ -211,7 +204,7 @@ void list__free (list__list_t * list);
// === list__free() ===
/** functions/list__free/description
* Free all node pointers in `list`, then free `list`
* Free all node pointers in `list`
*
* Arguments:
* - `list`: A pointer to the list to be operated on

View File

@ -20,17 +20,6 @@
// ----------------------------------------------------------------------------
list__list_t * list__new(void) {
list__list_t * list = malloc( sizeof(list__list_t) );
if (!list) return NULL;
list->head = NULL;
list->tail = NULL;
list->length = 0;
return list;
}
void * list__insert(list__list_t * list, int8_t index, void * node) {
if (!node) return NULL;
@ -171,7 +160,6 @@ void list__free(list__list_t * list) {
list->head = N(list->head)->next;
free(node);
}
free(list);
}
}

View File

@ -10,6 +10,9 @@
* Prefixes: `timer__`, `timer___`
*/
// 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

View File

@ -5,14 +5,10 @@
* ------------------------------------------------------------------------- */
/** description
* Implements the timer interface defined in ".../firmware/lib/timer.h" for the
* ATMega32U4
* Implements the device specific portion of the timer interface defined in
* ".../firmware/lib/timer.h" for the ATMega32U4
*
* See the accompanying '.md' file for further documentation.
*
* Notes:
* - Not all of this code is device-specific, but the parts that aren't are
* trivial enough that it's not worth separating them.
*/
@ -30,44 +26,12 @@
// ----------------------------------------------------------------------------
/** variables/_cycles/description
* The number of scan cycles since the timer was initialized (mod 2^16)
*/
static uint16_t _cycles;
/** variables/_cycles__scheduled/description
* A list of scheduled events, to be run in a given number of cycles
*
* After initialization, this should *only* be used as an argument to an
* `event_list__...()` function.
*/
static list__list_t * _cycles__scheduled;
/** variables/_milliseconds/description
* The number of milliseconds since the timer was initialized (mod 2^16)
*/
static volatile uint16_t _milliseconds;
/** variables/_milliseconds__scheduled/description
* A list of scheduled events, to be run in a given number of milliseconds
*
* After initialization, this should *only* be used as an argument to an
* `event_list__...()` function.
*/
static list__list_t * _milliseconds__scheduled;
static volatile uint16_t _milliseconds__counter;
static list__list_t * _milliseconds__scheduled_events = &(list__list_t){};
// ----------------------------------------------------------------------------
uint8_t timer__init(void) {
_cycles__scheduled = list__new();
_milliseconds__scheduled = list__new();
if (!_cycles__scheduled || !_milliseconds__scheduled) {
list__free(_cycles__scheduled);
list__free(_milliseconds__scheduled);
return 1; // error
}
OCR0A = 250; // (ticks per millisecond)
TCCR0A = 0b00000010; // (configure Timer/Counter 0)
TCCR0B = 0b00000011; // (configure Timer/Counter 0)
@ -77,36 +41,18 @@ uint8_t timer__init(void) {
return 0; // success
}
uint16_t timer__get_cycles(void) {
return _cycles;
}
uint16_t timer__get_milliseconds(void) {
return _milliseconds;
}
uint8_t timer__schedule_cycles(uint16_t cycles, void(*function)(void)) {
return event_list__append(_cycles__scheduled, cycles, function);
return _milliseconds__counter;
}
uint8_t timer__schedule_milliseconds( uint16_t milliseconds,
void(*function)(void) ) {
return event_list__append( _milliseconds__scheduled,
milliseconds,
function );
void(*function)(void)) {
return event_list__append(
_milliseconds__scheduled_events, milliseconds, function );
}
// ----------------------------------------------------------------------------
void timer___tick_cycles (void) {
_cycles++;
event_list__tick(_cycles__scheduled);
}
// ----------------------------------------------------------------------------
ISR(TIMER0_COMPA_vect) {
_milliseconds++;
event_list__tick(_milliseconds__scheduled);
_milliseconds__counter++;
event_list__tick(_milliseconds__scheduled_events);
}

View File

@ -11,6 +11,7 @@
#
SRC += $(wildcard $(CURDIR)/*.c)
SRC += $(wildcard $(CURDIR)/device/$(MCU).c)
SRC += $(wildcard $(CURDIR)/event-list/$(MCU).c)

View File

@ -37,22 +37,21 @@
#define main__was_pressed was_pressed
#define main__row row
#define main__col col
#define main__update_leds update_leds
#define main__flags flags
// ----------------------------------------------------------------------------
// --- for main() loop ---
static bool _pressed_1[OPT__KB__ROWS][OPT__KB__COLUMNS];
static bool _pressed_2[OPT__KB__ROWS][OPT__KB__COLUMNS];
bool (* is_pressed) [OPT__KB__ROWS][OPT__KB__COLUMNS] = &_pressed_1;
bool (* was_pressed) [OPT__KB__ROWS][OPT__KB__COLUMNS] = &_pressed_2;
bool (* is_pressed) [OPT__KB__ROWS][OPT__KB__COLUMNS]
= &( bool [OPT__KB__ROWS][OPT__KB__COLUMNS] ){};
bool (* was_pressed) [OPT__KB__ROWS][OPT__KB__COLUMNS]
= &( bool [OPT__KB__ROWS][OPT__KB__COLUMNS] ){};
uint8_t row;
uint8_t col;
bool update_leds = true;
struct main__flags_t flags = { .update_leds = true };
// ----------------------------------------------------------------------------
@ -115,7 +114,7 @@ int main(void) {
// note: only use the `kb__led__logical...` functions here, since the
// meaning of the physical LEDs should be controlled by the layout
if (update_leds) {
if (flags.update_leds) {
#define read usb__kb__read_led
#define on kb__led__logical_on
#define off kb__led__logical_off

View File

@ -25,13 +25,19 @@
// ----------------------------------------------------------------------------
struct main__flags_t {
bool update_leds : 1;
};
// ----------------------------------------------------------------------------
extern bool (* main__is_pressed) [OPT__KB__ROWS][OPT__KB__COLUMNS];
extern bool (* main__was_pressed) [OPT__KB__ROWS][OPT__KB__COLUMNS];
extern uint8_t main__row;
extern uint8_t main__col;
extern bool main__update_leds;
extern struct main__flags_t main__flags;
// ----------------------------------------------------------------------------
@ -45,6 +51,16 @@ extern bool main__update_leds;
// ============================================================================
// ----------------------------------------------------------------------------
// types ----------------------------------------------------------------------
// ----------------------------------------------------------------------------
// === main__flags_t ===
/** types/struct main__flags_t/description
* See the documentation for `main__flags`
*/
// ----------------------------------------------------------------------------
// variables ------------------------------------------------------------------
// ----------------------------------------------------------------------------
@ -71,15 +87,18 @@ extern bool main__update_leds;
* Indicates which column is currently being tested for changes of key state
*/
// === main__update_leds ===
/** variables/main__update_leds/description
* A predicate indicating whether to update the keyboard LED state based on the
* USB LED state
// === main__flags ===
/** variables/main__flags/description
* A collection of flags pertaining to the operation of `main()`
*
* 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 of the
* LEDs under normal use, the correct place to do that is in the layout file,
* where the `kb__led__logical_...()` functions are defined (see the
* documentation in that and related files for more information).
* Struct members:
* - 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
* of the LEDs under normal use, the correct place to do that is in the
* layout file, where the `kb__led__logical_...()` functions are defined
* (see the documentation in that and related files for more
* information).
*/