2012-04-10 10:44:27 +02:00
|
|
|
// vim: ts=4 sw=4 sts=4
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
|
|
* main()
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
|
|
|
|
* Released under The MIT License (MIT) (see "license.md")
|
|
|
|
* Project located at <https://github.com/benblazak/ergodox-firmware>
|
|
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
2012-07-31 23:48:31 +02:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
2012-04-10 10:44:27 +02:00
|
|
|
#include <util/delay.h>
|
2012-08-07 00:57:23 +02:00
|
|
|
#include "./lib-other/pjrc/usb_keyboard/usb_keyboard.h"
|
|
|
|
#include "./lib/key-functions/public.h"
|
|
|
|
#include "./keyboard/controller.h"
|
|
|
|
#include "./keyboard/layout.h"
|
|
|
|
#include "./keyboard/matrix.h"
|
|
|
|
#include "./main.h"
|
2012-07-31 23:48:31 +02:00
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2012-11-30 21:06:41 +01:00
|
|
|
#define MAX_ACTIVE_LAYERS 20
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2012-08-07 00:57:23 +02:00
|
|
|
static bool _main_kb_is_pressed[KB_ROWS][KB_COLUMNS];
|
|
|
|
bool (*main_kb_is_pressed)[KB_ROWS][KB_COLUMNS] = &_main_kb_is_pressed;
|
2012-07-31 23:48:31 +02:00
|
|
|
|
2012-08-07 00:57:23 +02:00
|
|
|
static bool _main_kb_was_pressed[KB_ROWS][KB_COLUMNS];
|
|
|
|
bool (*main_kb_was_pressed)[KB_ROWS][KB_COLUMNS] = &_main_kb_was_pressed;
|
|
|
|
|
2012-11-30 21:06:41 +01:00
|
|
|
uint8_t main_layers_pressed[KB_ROWS][KB_COLUMNS];
|
2012-08-07 00:57:23 +02:00
|
|
|
|
|
|
|
uint8_t main_loop_row;
|
|
|
|
uint8_t main_loop_col;
|
|
|
|
|
|
|
|
uint8_t main_arg_layer;
|
2012-11-30 21:06:41 +01:00
|
|
|
uint8_t main_arg_layer_offset;
|
2012-08-07 00:57:23 +02:00
|
|
|
uint8_t main_arg_row;
|
|
|
|
uint8_t main_arg_col;
|
|
|
|
bool main_arg_is_pressed;
|
|
|
|
bool main_arg_was_pressed;
|
2013-04-08 09:49:35 +02:00
|
|
|
bool main_arg_any_non_trans_key_pressed;
|
|
|
|
bool main_arg_trans_key_pressed;
|
2012-04-10 10:44:27 +02:00
|
|
|
|
2012-07-31 23:48:31 +02:00
|
|
|
// ----------------------------------------------------------------------------
|
2012-04-10 10:44:27 +02:00
|
|
|
|
2012-07-31 23:48:31 +02:00
|
|
|
/*
|
|
|
|
* main()
|
|
|
|
*/
|
2012-04-10 10:44:27 +02:00
|
|
|
int main(void) {
|
|
|
|
kb_init(); // does controller initialization too
|
|
|
|
|
2012-06-01 09:50:45 +02:00
|
|
|
kb_led_state_power_on();
|
2012-04-12 06:05:45 +02:00
|
|
|
|
2012-04-10 10:44:27 +02:00
|
|
|
usb_init();
|
|
|
|
while (!usb_configured());
|
2012-06-01 09:50:45 +02:00
|
|
|
kb_led_delay_usb_init(); // give the OS time to load drivers, etc.
|
2012-04-10 10:44:27 +02:00
|
|
|
|
2012-06-01 09:50:45 +02:00
|
|
|
kb_led_state_ready();
|
2012-04-12 06:05:45 +02:00
|
|
|
|
2012-04-10 10:44:27 +02:00
|
|
|
for (;;) {
|
2012-08-07 00:57:23 +02:00
|
|
|
// swap `main_kb_is_pressed` and `main_kb_was_pressed`, then update
|
|
|
|
bool (*temp)[KB_ROWS][KB_COLUMNS] = main_kb_was_pressed;
|
|
|
|
main_kb_was_pressed = main_kb_is_pressed;
|
|
|
|
main_kb_is_pressed = temp;
|
|
|
|
|
|
|
|
kb_update_matrix(*main_kb_is_pressed);
|
2012-04-10 10:44:27 +02:00
|
|
|
|
2012-06-21 01:56:24 +02:00
|
|
|
// this loop is responsible to
|
2012-08-07 00:57:23 +02:00
|
|
|
// - "execute" keys when they change state
|
2012-06-21 01:56:24 +02:00
|
|
|
// - keep track of which layers the keys were on when they were pressed
|
|
|
|
// (so they can be released using the function from that layer)
|
|
|
|
//
|
|
|
|
// note
|
|
|
|
// - everything else is the key function's responsibility
|
|
|
|
// - see the keyboard layout file ("keyboard/ergodox/layout/*.c") for
|
|
|
|
// which key is assigned which function (per layer)
|
2012-08-07 00:57:23 +02:00
|
|
|
// - see "lib/key-functions/public/*.c" for the function definitions
|
2012-11-30 21:06:41 +01:00
|
|
|
#define row main_loop_row
|
|
|
|
#define col main_loop_col
|
|
|
|
#define layer main_arg_layer
|
|
|
|
#define is_pressed main_arg_is_pressed
|
|
|
|
#define was_pressed main_arg_was_pressed
|
2012-08-07 00:57:23 +02:00
|
|
|
for (row=0; row<KB_ROWS; row++) {
|
|
|
|
for (col=0; col<KB_COLUMNS; col++) {
|
|
|
|
is_pressed = (*main_kb_is_pressed)[row][col];
|
|
|
|
was_pressed = (*main_kb_was_pressed)[row][col];
|
bugfix (mostly): changed the way layers are handled
before, if you pressed a key, then shifted layers, then released it, the
first layer's press() would be called, and the 2nd layer's release()
would be called, causing keys to stick, and probably other errors. now,
the layer that the key was on when it was pressed is kept track of, and
the proper release() is called.
also, layers can be shifted per key now, instead of just for the whole
board at once
i also changed how keyboard-private includes are handled. "private"
stuff is now in its own file, instead of being nested in an extra
`#ifdef`.
and i think that's it. i'm pretty tired right now, so there may be
errors, but it seemed to work all right with cursory tests.
2012-06-11 12:27:34 +02:00
|
|
|
|
2012-04-11 03:58:26 +02:00
|
|
|
if (is_pressed != was_pressed) {
|
2012-08-07 00:57:23 +02:00
|
|
|
if (is_pressed) {
|
2012-11-30 21:06:41 +01:00
|
|
|
layer = main_layers_peek(0);
|
|
|
|
main_layers_pressed[row][col] = layer;
|
2012-08-07 00:57:23 +02:00
|
|
|
} else {
|
2012-11-30 21:06:41 +01:00
|
|
|
layer = main_layers_pressed[row][col];
|
2012-08-07 00:57:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// set remaining vars, and "execute" key
|
2012-11-30 21:06:41 +01:00
|
|
|
main_arg_row = row;
|
|
|
|
main_arg_col = col;
|
|
|
|
main_arg_layer_offset = 0;
|
2012-08-07 00:57:23 +02:00
|
|
|
main_exec_key();
|
2012-04-11 03:58:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-07 00:57:23 +02:00
|
|
|
#undef row
|
|
|
|
#undef col
|
|
|
|
#undef layer
|
|
|
|
#undef is_pressed
|
|
|
|
#undef was_pressed
|
2012-04-10 10:44:27 +02:00
|
|
|
|
2012-06-21 01:56:24 +02:00
|
|
|
// send the USB report (even if nothing's changed)
|
|
|
|
usb_keyboard_send();
|
2012-08-07 00:57:23 +02:00
|
|
|
_delay_ms(MAKEFILE_DEBOUNCE_TIME);
|
2012-06-21 01:56:24 +02:00
|
|
|
|
2012-04-10 10:44:27 +02:00
|
|
|
// update LEDs
|
2012-06-01 09:50:45 +02:00
|
|
|
if (keyboard_leds & (1<<0)) { kb_led_num_on(); }
|
|
|
|
else { kb_led_num_off(); }
|
|
|
|
if (keyboard_leds & (1<<1)) { kb_led_caps_on(); }
|
|
|
|
else { kb_led_caps_off(); }
|
|
|
|
if (keyboard_leds & (1<<2)) { kb_led_scroll_on(); }
|
|
|
|
else { kb_led_scroll_off(); }
|
|
|
|
if (keyboard_leds & (1<<3)) { kb_led_compose_on(); }
|
|
|
|
else { kb_led_compose_off(); }
|
|
|
|
if (keyboard_leds & (1<<4)) { kb_led_kana_on(); }
|
|
|
|
else { kb_led_kana_off(); }
|
2012-04-10 10:44:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-07 00:57:23 +02:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// convenience macros (for the helper functions below)
|
|
|
|
#define layer main_arg_layer
|
|
|
|
#define row main_arg_row
|
|
|
|
#define col main_arg_col
|
|
|
|
#define is_pressed main_arg_is_pressed
|
|
|
|
#define was_pressed main_arg_was_pressed
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2012-11-30 21:06:41 +01:00
|
|
|
/* ----------------------------------------------------------------------------
|
|
|
|
* Layer Functions
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
* We keep track of which layer is foremost by placing it on a stack. Layers
|
|
|
|
* may appear in the stack more than once. The base layer will always be
|
|
|
|
* layer-0.
|
|
|
|
*
|
|
|
|
* Implemented as a fixed size stack.
|
|
|
|
* ------------------------------------------------------------------------- */
|
|
|
|
|
2012-12-04 01:19:12 +01:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2012-11-30 21:06:41 +01:00
|
|
|
struct layers {
|
|
|
|
uint8_t layer;
|
|
|
|
uint8_t id;
|
2013-04-08 09:49:35 +02:00
|
|
|
uint8_t sticky;
|
2012-11-30 21:06:41 +01:00
|
|
|
};
|
|
|
|
|
2012-12-04 01:19:12 +01:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
struct layers layers[MAX_ACTIVE_LAYERS];
|
|
|
|
uint8_t layers_head = 0;
|
|
|
|
uint8_t layers_ids_in_use[MAX_ACTIVE_LAYERS] = {true};
|
2012-11-30 21:06:41 +01:00
|
|
|
|
2013-04-08 09:49:35 +02:00
|
|
|
/*
|
|
|
|
* Exec key
|
|
|
|
* - Execute the keypress or keyrelease function (if it exists) of the key at
|
|
|
|
* the current possition.
|
|
|
|
*/
|
|
|
|
void main_exec_key(void) {
|
|
|
|
void (*key_function)(void) =
|
|
|
|
( (is_pressed)
|
|
|
|
? kb_layout_press_get(layer, row, col)
|
|
|
|
: kb_layout_release_get(layer, row, col) );
|
|
|
|
|
|
|
|
main_arg_trans_key_pressed = false;
|
|
|
|
if (key_function)
|
|
|
|
(*key_function)();
|
|
|
|
|
|
|
|
// If the current layer is in the sticky once up state and a key defined
|
|
|
|
// for this layer (a non-transparent key) was pressed, pop the layer
|
|
|
|
if (layers[layers_head].sticky == eStickyOnceUp && main_arg_any_non_trans_key_pressed)
|
|
|
|
main_layers_pop_id(layers_head);
|
|
|
|
}
|
|
|
|
|
2012-11-30 21:06:41 +01:00
|
|
|
/*
|
|
|
|
* peek()
|
|
|
|
*
|
|
|
|
* Arguments
|
|
|
|
* - 'offset': the offset (down the stack) from the head element
|
|
|
|
*
|
|
|
|
* Returns
|
|
|
|
* - success: the layer-number of the requested element (which may be 0)
|
|
|
|
* - failure: 0 (default) (out of bounds)
|
|
|
|
*/
|
|
|
|
uint8_t main_layers_peek(uint8_t offset) {
|
2012-12-04 01:19:12 +01:00
|
|
|
if (offset <= layers_head)
|
|
|
|
return layers[layers_head - offset].layer;
|
2012-11-30 21:06:41 +01:00
|
|
|
|
2012-12-04 01:19:12 +01:00
|
|
|
return 0; // default, or error
|
2012-11-30 21:06:41 +01:00
|
|
|
}
|
|
|
|
|
2013-04-08 09:49:35 +02:00
|
|
|
uint8_t main_layers_peek_sticky(uint8_t offset) {
|
|
|
|
if (offset <= layers_head)
|
|
|
|
return layers[layers_head - offset].sticky;
|
|
|
|
|
|
|
|
return 0; // default, or error
|
|
|
|
}
|
|
|
|
|
2012-11-30 21:06:41 +01:00
|
|
|
/*
|
|
|
|
* push()
|
|
|
|
*
|
|
|
|
* Arguments
|
|
|
|
* - 'layer': the layer-number to push to the top of the stack
|
|
|
|
*
|
|
|
|
* Returns
|
|
|
|
* - success: the id assigned to the newly added element
|
|
|
|
* - failure: 0 (the stack was already full)
|
|
|
|
*/
|
2013-04-08 09:49:35 +02:00
|
|
|
uint8_t main_layers_push(uint8_t layer, uint8_t sticky) {
|
2012-12-04 01:19:12 +01:00
|
|
|
// look for an available id
|
2013-04-08 09:49:35 +02:00
|
|
|
for (uint8_t id=1; id<MAX_ACTIVE_LAYERS; id++) {
|
2012-12-04 01:19:12 +01:00
|
|
|
// if one is found
|
|
|
|
if (layers_ids_in_use[id] == false) {
|
|
|
|
layers_ids_in_use[id] = true;
|
|
|
|
layers_head++;
|
|
|
|
layers[layers_head].layer = layer;
|
|
|
|
layers[layers_head].id = id;
|
2013-04-08 09:49:35 +02:00
|
|
|
layers[layers_head].sticky = sticky;
|
2012-11-30 21:06:41 +01:00
|
|
|
return id;
|
|
|
|
}
|
2013-04-08 09:49:35 +02:00
|
|
|
}
|
2012-11-30 21:06:41 +01:00
|
|
|
|
2012-12-04 01:19:12 +01:00
|
|
|
return 0; // default, or error
|
2012-11-30 21:06:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pop_id()
|
|
|
|
*
|
|
|
|
* Arguments
|
|
|
|
* - 'id': the id of the element to pop from the stack
|
|
|
|
*/
|
|
|
|
void main_layers_pop_id(uint8_t id) {
|
2012-12-04 01:19:12 +01:00
|
|
|
// look for the element with the id we want to pop
|
|
|
|
for (uint8_t element=1; element<=layers_head; element++)
|
|
|
|
// if we find it
|
|
|
|
if (layers[element].id == id) {
|
|
|
|
// move all layers above it down one
|
|
|
|
for (; element<layers_head; element++) {
|
|
|
|
layers[element].layer = layers[element+1].layer;
|
|
|
|
layers[element].id = layers[element+1].id;
|
|
|
|
}
|
|
|
|
// reinitialize the topmost (now unused) slot
|
|
|
|
layers[layers_head].layer = 0;
|
|
|
|
layers[layers_head].id = 0;
|
|
|
|
// record keeping
|
|
|
|
layers_ids_in_use[id] = false;
|
|
|
|
layers_head--;
|
2012-11-30 21:06:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_offset_id()
|
|
|
|
*
|
|
|
|
* Arguments
|
|
|
|
* - 'id': the id of the element you want the offset of
|
|
|
|
*
|
|
|
|
* Returns
|
|
|
|
* - success: the offset (down the stack from the head element) of the element
|
|
|
|
* with the given id
|
|
|
|
* - failure: 0 (default) (id unassigned)
|
|
|
|
*/
|
|
|
|
uint8_t main_layers_get_offset_id(uint8_t id) {
|
2012-12-04 01:19:12 +01:00
|
|
|
// look for the element with the id we want to get the offset of
|
|
|
|
for (uint8_t element=1; element<=layers_head; element++)
|
|
|
|
// if we find it
|
|
|
|
if (layers[element].id == id)
|
|
|
|
return (layers_head - element);
|
|
|
|
|
|
|
|
return 0; // default, or error
|
2012-11-30 21:06:41 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------------------
|
|
|
|
* ------------------------------------------------------------------------- */
|
2012-08-07 00:57:23 +02:00
|
|
|
|