From 49f3d4bdd5433d0e6b3abc9af811a2a63bf33201 Mon Sep 17 00:00:00 2001 From: Ben Blazak Date: Thu, 9 May 2013 02:02:48 -0700 Subject: [PATCH] re-added linked lists :D; and minor aesthetic changes --- doc/references.md | 9 + .../ergodox/layout/common/exec_key.c.h | 2 +- firmware/keyboard/ergodox/led.c | 6 +- firmware/keyboard/ergodox/options.mk | 3 + firmware/lib/data-types/list.h | 167 ++++++++++++++++++ firmware/lib/data-types/list/list.c | 129 ++++++++++++++ firmware/lib/data-types/list/options.mk | 15 ++ firmware/lib/layout/eeprom-macro.h | 6 +- firmware/lib/layout/keys.h | 11 +- firmware/lib/layout/layer-stack/layer-stack.c | 4 +- firmware/lib/timer/atmega32u4.c | 2 - firmware/lib/usb.h | 2 +- firmware/main.c | 6 +- 13 files changed, 343 insertions(+), 19 deletions(-) create mode 100644 firmware/lib/data-types/list.h create mode 100644 firmware/lib/data-types/list/list.c create mode 100644 firmware/lib/data-types/list/options.mk diff --git a/doc/references.md b/doc/references.md index 2b59eea..f10311b 100644 --- a/doc/references.md +++ b/doc/references.md @@ -134,6 +134,15 @@ (http://mathforum.org/library/drmath/view/52343.html) `(-1)%5` in python returns `4` (just like it should) +* [Is it safe to free `void *`?] + (http://stackoverflow.com/a/2182522/2360353) + 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 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++ Stuff * [Google C++ Style Guide] diff --git a/firmware/keyboard/ergodox/layout/common/exec_key.c.h b/firmware/keyboard/ergodox/layout/common/exec_key.c.h index 0f23d72..97900b5 100644 --- a/firmware/keyboard/ergodox/layout/common/exec_key.c.h +++ b/firmware/keyboard/ergodox/layout/common/exec_key.c.h @@ -34,7 +34,7 @@ void kb__layout__exec_key(bool pressed, uint8_t row, uint8_t column) { void (*function)(void); uint8_t layer; - for(uint8_t i = 0; i < layer_stack__size()+1+1; i++) { // i = offset+1 + for (uint8_t i=0; i < layer_stack__size()+1+1; i++) { // i = offset+1 if (i == 0) if (!pressed) layer = pressed_layer[row][column]; diff --git a/firmware/keyboard/ergodox/led.c b/firmware/keyboard/ergodox/led.c index 016dae8..bd42f62 100644 --- a/firmware/keyboard/ergodox/led.c +++ b/firmware/keyboard/ergodox/led.c @@ -73,17 +73,17 @@ bool kb__led__read(uint8_t led) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void kb__led__all_on(void) { - for(uint8_t i=1; i<=3; i++) + for (uint8_t i=1; i<=3; i++) kb__led__on(i); } void kb__led__all_off(void) { - for(uint8_t i=1; i<=3; i++) + for (uint8_t i=1; i<=3; i++) kb__led__off(i); } void kb__led__all_set(float n) { - for(uint8_t i=1; i<=3; i++) + for (uint8_t i=1; i<=3; i++) kb__led__set(i, n); } diff --git a/firmware/keyboard/ergodox/options.mk b/firmware/keyboard/ergodox/options.mk index 0301607..4d506da 100644 --- a/firmware/keyboard/ergodox/options.mk +++ b/firmware/keyboard/ergodox/options.mk @@ -46,6 +46,9 @@ include $(CURDIR)/options.mk CURDIR := $(ROOTDIR)/lib/layout/layer-stack include $(CURDIR)/options.mk # ------- +CURDIR := $(ROOTDIR)/lib/data-types/list +include $(CURDIR)/options.mk +# ------- CURDIR := $(firstword $(CURDIRS)) CURDIRS := $(wordlist 2,$(words $(CURDIRS)),$(CURDIRS)) diff --git a/firmware/lib/data-types/list.h b/firmware/lib/data-types/list.h new file mode 100644 index 0000000..bfdf53f --- /dev/null +++ b/firmware/lib/data-types/list.h @@ -0,0 +1,167 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) 2013 Ben Blazak + * Released under The MIT License (see "doc/licenses/MIT.md") + * Project located at + * ------------------------------------------------------------------------- */ + +/** description + * An interface to a simple linked-list that can be used to implement lists, + * queues, stacks, and things + * + * Prefix: `list__` + * + * + * Implementation notes: + * + * - All functions that accept an `index` should set `index %= list->length` + * before using it. This will make all passed indices valid. It will also + * provide a convenient way to reference the last element of a list, by + * passing `-1` as the index (as in Python). + */ + + +#ifndef ERGODOX_FIRMWARE__FIRMWARE__LIB__DATA_TYPES__LIST__H +#define ERGODOX_FIRMWARE__FIRMWARE__LIB__DATA_TYPES__LIST__H +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + + +#include + +// ---------------------------------------------------------------------------- + +typedef struct list__node_t { + struct list__node_t * next; +} list__node_t; + +typedef struct list__list_t { + list__node_t * head; + list__node_t * tail; + uint8_t length; +} list__list_t; + +// ---------------------------------------------------------------------------- + +list__list_t * list__new (void); +void * list__insert ( list__list_t * list, + int8_t index, + uint8_t size ); +void * list__peek (list__list_t * list, int8_t index); +void * list__pop__no_free (list__list_t * list, int8_t index); +void list__free (list__list_t * list); + + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +#endif // ERGODOX_FIRMWARE__FIRMWARE__LIB__DATA_TYPES__LIST__H + + + +// ============================================================================ +// === documentation ========================================================== +// ============================================================================ + + +// ---------------------------------------------------------------------------- +// typedefs ------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +// === list__node_t === +/** typedefs/list__node_t/description + * The type of a "node", for the purposes of this library + * + * Full node types should be defined in the using '.c' or '.h' file, with + * something like + * + * typedef struct { + * list__node_t _private; + * uint8_t data; + * } node_t; + * + * The functions that return pointers to nodes will return `void *` pointers, + * so functions in the using '.c' file also need to cast these return values to + * the appropriate type before use. + */ + +// === list__list_t === +/** typedefs/list__list_t/description + * Simple struct to define and keep track of our 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` + * + * Arguments: + * - `list`: A pointer to the list to be operated on + * - `index`: An `int8_t` indicating the position the new node will occupy + * - `size`: The size of the full node type (as in `sizeof(node_t)`) defined in + * the using '.c' or '.h' file, so we know how much memory to allocate + * + * Returns: + * - success: A `void *` pointer to the new node + * - failure: `NULL` + * + * Warning: + * - For any given list, the `size` passed to this function should always be + * the same. + * + * Caution: + * - Initialization of the data to be stored in the node is the calling + * function's responsibility. + */ + +// === list__peek() === +/** functions/list__peek/description + * Return a pointer to the node at position `index % list->length` + * + * Arguments: + * - `list`: A pointer to the list to be operated on + * - `index`: An `int8_t` indicating the position of the node to peek at + * + * Returns: + * - success: A `void *` pointer to the node at position `index % list->length` + * - failure: `NULL` + */ + +// === list__pop__no_free() === +/** functions/list__pop__no_free/description + * Return a pointer to the node at position `index % list->length`, and remove + * the node from the list + * + * Warning: + * - Does not free the node's memory - this is the calling function's + * responsibility. If you want to pop the node and free its memory without + * looking at it, call `free( list__pop__no_free( node ) )`. + * + * Arguments: + * - `list`: A pointer to the list to be operated on + * - `index`: An `int8_t` indicating the position of the node to pop + * + * Returns: + * - success: A `void *` pointer to the node at position `index % list->length` + * - failure: `NULL` + */ + +// === list__free() === +/** functions/list__free/description + * Free all node pointers in `list`, then free `list` + * + * Arguments: + * - `list`: A pointer to the list to be operated on + */ + diff --git a/firmware/lib/data-types/list/list.c b/firmware/lib/data-types/list/list.c new file mode 100644 index 0000000..2c477f9 --- /dev/null +++ b/firmware/lib/data-types/list/list.c @@ -0,0 +1,129 @@ +/* ---------------------------------------------------------------------------- + * Copyright (c) 2012, 2013 Ben Blazak + * Released under The MIT License (see "doc/licenses/MIT.md") + * Project located at + * ------------------------------------------------------------------------- */ + +/** description + * Implements the list type in "../list.h" + */ + + +#include +#include +#include "../list.h" + +// ---------------------------------------------------------------------------- + +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, uint8_t size) { + list__node_t * node = malloc(size); + if (!node) return NULL; + + list->length++; + + if (list->length == 1) { + // insert as only node (no others exist yet) + list->head = node; + list->tail = node; + node->next = NULL; + + } else { + index %= list->length; + + if (index == 0) { + // insert as first node + node->next = list->head; + list->head = node; + + } else if (index == list->length-1) { + // insert as last node + list->tail->next = node; + list->tail = node; + node->next = NULL; + + } else { + // insert as other node + list__node_t * previous = list->head; + for (uint8_t i=1; inext; + node->next = previous->next; + previous->next = node; + } + } + + return node; +} + +void * list__peek(list__list_t * list, int8_t index) { + // if no nodes exist + if (list->length == 0) + return NULL; + + index %= list->length; + + // if last node + if (index == list->length-1) + return list->tail; + + // else + list__node_t * node = list->head; + for (uint8_t i=0; inext; + return node; +} + +void * list__pop__no_free(list__list_t * list, int8_t index) { + // if no nodes exist + if (list->length == 0) + return NULL; + + index %= list->length; + + list__node_t * node; + + if (index == 0) { + // pop first node + node = list->head; + list->head = node->next; + + } else { + // find the `index-1`th node + list__node_t * previous = list->head; + for (uint8_t i=1; inext; + + // if last node + if (index == list->length-1) + list->tail = previous; + + // pop the node at `index` + node = previous->next; + previous->next = node->next; + } + + list->length--; + + return node; +} + +void list__free(list__list_t * list) { + list__node_t * node; + while (list->head) { + node = list->head; + list->head = list->head->next; + free(node); + } + free(list); +} + diff --git a/firmware/lib/data-types/list/options.mk b/firmware/lib/data-types/list/options.mk new file mode 100644 index 0000000..fc4d554 --- /dev/null +++ b/firmware/lib/data-types/list/options.mk @@ -0,0 +1,15 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2013 Ben Blazak +# Released under The MIT License (see "doc/licenses/MIT.md") +# Project located at +# ----------------------------------------------------------------------------- + +## description +# list options +# +# This file is meant to be included by the using '.../options.mk' +# + + +SRC += $(wildcard $(CURDIR)/*.c) + diff --git a/firmware/lib/layout/eeprom-macro.h b/firmware/lib/layout/eeprom-macro.h index 6e9d0ca..9038bc6 100644 --- a/firmware/lib/layout/eeprom-macro.h +++ b/firmware/lib/layout/eeprom-macro.h @@ -14,8 +14,8 @@ */ -#ifndef ERGODOX_FIRMWARE__LIB__LAYOUT__EEPROM_MACRO__H -#define ERGODOX_FIRMWARE__LIB__LAYOUT__EEPROM_MACRO__H +#ifndef ERGODOX_FIRMWARE__FIRMWARE__LIB__LAYOUT__EEPROM_MACRO__H +#define ERGODOX_FIRMWARE__FIRMWARE__LIB__LAYOUT__EEPROM_MACRO__H // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- @@ -25,5 +25,5 @@ // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- -#endif // ERGODOX_FIRMWARE__LIB__LAYOUT__EEPROM_MACRO__H +#endif // ERGODOX_FIRMWARE__FIRMWARE__LIB__LAYOUT__EEPROM_MACRO__H diff --git a/firmware/lib/layout/keys.h b/firmware/lib/layout/keys.h index 73e4d74..1180995 100644 --- a/firmware/lib/layout/keys.h +++ b/firmware/lib/layout/keys.h @@ -14,10 +14,13 @@ * * Prefixes: `keys__`, [none] * - * Usage: `#define` `KEYS__DEFAULT` and `KEYS__SHIFTED` before `#include`ing. - * - * TODO: add media and mouse keys (after i figure out which OSs are supposed to - * support which keys) + * Usage: + * - `#define` `KEYS__DEFAULT` and `KEYS__SHIFTED` before `#include`ing. + * - These macros should probably do what their names imply (i.e. define a + * "default" or "shifted" key, respectively, whatever that means to the + * implementing layout), but in a practical sense they can be used however + * one wants. They're simply a really convenient way to generate almost + * the same bit of code for a lot of (key_name, key_code) pairs. */ diff --git a/firmware/lib/layout/layer-stack/layer-stack.c b/firmware/lib/layout/layer-stack/layer-stack.c index 4cb3226..366745f 100644 --- a/firmware/lib/layout/layer-stack/layer-stack.c +++ b/firmware/lib/layout/layer-stack/layer-stack.c @@ -132,7 +132,7 @@ static uint8_t _shift_elements(uint8_t offset, bool up) { uint8_t increment = (up) ? -1 : 1 ; uint8_t end = (up) ? _filled-1-offset : _filled-1 ; - for(uint8_t i=start; i!=(end+increment); i+=increment) { + for (uint8_t i=start; i!=(end+increment); i+=increment) { _stack[i-increment].id = _stack[i].id; _stack[i-increment].number = _stack[i].number; } @@ -197,7 +197,7 @@ uint8_t layer_stack__pop_id(uint8_t layer_id) { } uint8_t layer_stack__find_id(uint8_t layer_id) { - for(uint8_t i=0; i<_filled; i++) + for (uint8_t i=0; i<_filled; i++) if (_stack[i].id == layer_id) return _filled-1-i; // offset return -1; // failure: return an invalid offset diff --git a/firmware/lib/timer/atmega32u4.c b/firmware/lib/timer/atmega32u4.c index bf1758c..3c3a5a5 100644 --- a/firmware/lib/timer/atmega32u4.c +++ b/firmware/lib/timer/atmega32u4.c @@ -7,8 +7,6 @@ /** description * Implements the timer functions defined in "../timer.h" for the ATMega32U4 * - * Prefix: `timer__` - * * See the accompanying '.md' file for documentation. */ diff --git a/firmware/lib/usb.h b/firmware/lib/usb.h index 4cd8bc4..95c76e9 100644 --- a/firmware/lib/usb.h +++ b/firmware/lib/usb.h @@ -59,7 +59,7 @@ uint8_t usb__kb__send_report (void); */ // === usb__is_configured === -/** variables/usb__is_configured/description +/** functions/usb__is_configured/description * Check whether this device has been configured by the host * * Returns: diff --git a/firmware/main.c b/firmware/main.c index 3707a07..fcccc86 100644 --- a/firmware/main.c +++ b/firmware/main.c @@ -82,7 +82,7 @@ int main(void) { time_scan_started // on the first iteration, scan immediately = timer__get_milliseconds() - OPT__DEBOUNCE_TIME; - for(;;) { + for (;;) { temp = is_pressed; is_pressed = was_pressed; was_pressed = temp; @@ -96,8 +96,8 @@ int main(void) { kb__update_matrix(*is_pressed); // "execute" keys that have changed state - for(row=0; row