lib/eeprom-macro : debating implementation

partial-rewrite
Ben Blazak 2013-06-01 23:56:05 -07:00
parent 0c23c45627
commit 56cbc8cb1b
3 changed files with 100 additions and 44 deletions

View File

@ -170,6 +170,10 @@
`uint8_t`s when operating on things then, when possible, and to just not
bitshift `char`s.
* [GCC docs : Variable Attributes]
(http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html)
How to byte align variables in GCC (among other things...)
### C++ Stuff
* [Google C++ Style Guide]

View File

@ -13,29 +13,25 @@
* implementation.
*
*
* TODO: might need a "get_size_total()" and "get_size_free()" later, for
* information display purposes
* Usage notes:
*
* - These function will play back keystrokes, not actions. This means that
* new macro definitions may affect old ones. It also means that different
* keyboard states may lead to different actions being performed for the same
* macro (if, say, the layer the macro is on is mostly transparent, and there
* is a different layer underneath it on a subsequent press than there was
* during definition).
*
* TODO: rewrite the following
* notes:
* - Even though `eeprom_macro__index_t` has distinct fields, there is nothing
* that says the calling function(s) must maintain those semantic meanings.
* I imagine that under most circumstances one would want to, but as long as
* the '.c' file implementing this interface agrees (or at least works) with
* whatever the calling functions are doing, things should be fine.
*
* - these functions will play back keystrokes, not functions or (layer, row,
* column) tuples, or anything like that. this means that if you press a key
* that has a macro assigned to it while defining a new macro, the former
* macro will be activated each time the new macro is run (unless it is
* deleted). this means that if you intend to use these functions to move
* letter keys around, you should probably have a layer somewhere with all
* the letters on it, and define the macros on your home layer to press keys
* on that other layer. otherwise, assigning a macro to a letter key will
* make that letter unreachable until the macro is removed.
*
* - or (instead of the above) `...exec_key()` could handle macro assignment
* differently, and trigger macro replay based on something besides what i'm
* currently thinking of for the ergodox. that is, "layers" here need not
* correspond to "layers" elsewhere in the firmware, except for the purposes
* of convenience, and possibly sanity (both of which are typically overruled
* by memory constraints...).
* - Particularly, if there were a layout implementation that ignored
* layers, but wanted to manually map different key combinations to
* different macros for a given key, this could be done by repurposing
* the `layer` field to mean "key combination id" (or some such thing).
*/
@ -80,7 +76,8 @@ void eeprom_macro__clear_all (void);
/** types/eeprom_macro__index_t/description
* A convenient way to specify a position in the layer matrix
*
* Used here to uniquely identify macros, and to group them for optimizations.
* Used here as a UID (Unique IDentifier) for macros, and to group them for
* optimizations.
*
* Notes:
* - This format artificially limits the number of layers, rows, and columns
@ -144,7 +141,7 @@ void eeprom_macro__clear_all (void);
*
* Arguments:
* - `skip`: The number of keystrokes at the end of our recording to ignore
* - `index`: The unique ID of this macro
* - `index`: The UID of this macro
*
* Returns:
* - success: `0`
@ -157,10 +154,10 @@ void eeprom_macro__clear_all (void);
// === eeprom_macro__play ===
/** functions/eeprom_macro__play/description
* Play back recorded keystrokes for the macro with unique ID `index`
* Play back recorded keystrokes for the macro with UID `index`
*
* Arguments:
* - `index`: The unique ID of the macro to play
* - `index`: The UID of the macro to play
*
* Returns:
* - `0`: Macro successfully played
@ -175,10 +172,10 @@ void eeprom_macro__clear_all (void);
// === eeprom_macro__clear ===
/** functions/eeprom_macro__clear/description
* Clear the macro with unique ID `index`
* Clear the macro with UID `index`
*
* Arguments:
* - `index`: The unique ID of the macro to clear
* - `index`: The UID of the macro to clear
*/
// === eeprom_macro__clear_all ===

View File

@ -8,13 +8,18 @@
* Implements the eeprom-macro functionality defined in "../eeprom-macro.h" for
* the ATMega32U4
*
*
* Implementation notes:
*
* - "block"s are 4 bytes long, aligned on the 4 byte boundary
* - blocks are pointed to by `uint8_t`s
*
* - Blocks are pointed to by `uint8_t`s
* - the EEPROM contains 1024 bytes = 256 blocks
* (i.e. 2^10 bytes, 2^8 blocks)
* - the beginning of a block is pointed to by
* `eeprom_address = block_address<<2`
* `eeprom_address = block_address << 2`
*
* - A "UID" (Unique ID) in this file is a `eeprom_macro__index_t`
*/
@ -36,11 +41,14 @@
* Size (in blocks): 1
*
* Format:
* - byte 0: the version of this layout
* - `0x00`, `0xFF` => uninitialized
* - byte 1: the number of rows in the table
* - byte 2: the number of columns in the table
* - byte 3: the first free block not yet used by `MACROS`
*
* struct {
* uint8_t version; // the version of this layout
* // `0x00`,`0xFF` => uninitialized
* uint8_t rows; // the number of rows in the table
* uint8_t columns; // the number of columns in the table
* uint8_t free; // the first free block not yet used for macros
* };
*
* Notes:
* - The number of rows and columns is significant to the offsets of some of
@ -57,7 +65,7 @@
*
* Notes:
* - Each entry is a block pointer to the first macro with the corresponding
* `row` and `column` in its unique ID
* `row` and `column` in its UID
*
* Format:
* - A `[ROWS][COLUMNS]` table, where the `[row][column]` entry can be accessed
@ -72,17 +80,23 @@
* Size (in blocks): `END - MACROS + 1` (since `END` is included)
*
* Format: macro header:
* - byte 0: a block pointer to the next macro with the same `row` and `column`
* in its unique ID
* - `0x00` => this macro is the last in the linked list for this `row`,
* `column` pair
* - `0xFF` => this macro has been deleted
* - byte 1: the run length of the macro, in number of key actions
* - byte 2..3: the unique ID of this macro (its `index`)
*
* Format: key action
* - The same as the format of `eeprom_macro__index_t` (which is the format of
* the unique IDs), except that `layer` will be ignored
* struct {
* uint8_t next; // a block pointer to the next macro with the same
* // `row` and `column` in its UID
* // `0x00` => this macro is the last in the linked
* // list for this `row`, `column` pair
* // `0xFF` => this macro has been deleted
* uint8_t length; // the run length of the macro, in number of
* // key actions
* eeprom_macro__index_t index; // the UID of this macro
* };
*
* Format: key action:
*
* struct {
* eeprom_macro__index_t index; // `layer` will be ignored
* };
*/
#define MACROS (TABLE + ((ROWS * COLUMNS + 0b11) >> 2))
@ -94,5 +108,46 @@
// ----------------------------------------------------------------------------
// sanity check
#if MACROS+10 >= END
#error "Insufficient EEPROM allocated to \".../firmware/lib/eeprom-macro\""
#endif
// ----------------------------------------------------------------------------
// TODO: if we do it this way, this belongs in the options file
#define OPT__EEPROM_MACRO__SIZE 1024
#define VERSION 1
struct {
uint8_t version; // the version of this layout
// `0x00`,`0xFF` => uninitialized
uint8_t rows; // the number of rows in the table
uint8_t columns; // the number of columns in the table
uint8_t free; // the first free block not yet used for macros
} header EEMEM;
uint8_t table[OPT__KB__ROWS][OPT__KB__COLUMNS] EEMEM;
uint8_t macros[ OPT__EEPROM_MACRO__SIZE-sizeof(header)-sizeof(table) ] EEMEM;
// ----------------------------------------------------------------------------
void f(void) {
uint8_t version1 = eeprom_read_byte( (HEADER<<2) + 0 );
uint8_t version2 = eeprom_read_byte( &header.version );
uint8_t ptr1 = eeprom_read_byte( TABLE + 5*COLUMNS + 3 );
uint8_t ptr2 = eeprom_read_byte( &table[5][3] );
// to suppress warnings about unused variables...
uint8_t version3 = version1+version2;
version3++;
}
// ----------------------------------------------------------------------------
// TODO: functions