diff --git a/TODO b/TODO index 6083b62..dca8224 100644 --- a/TODO +++ b/TODO @@ -6,11 +6,10 @@ Bugs to fix: Things to do before 1.0: - bopti: Test partial transparency -* core: Allow return to menu - demo: Try 284x124 at (-60, -28) (all disadvantages) - project: Check size of *all* library structures - project: Clean headers that have some internal definitions -- project: Unify this hellish mess of register access! +- project: Get rid of 7705.h (keyboard) and 7305.h (keyboard, gint) - time: Compute CLOCKS_PER_SEC Things to do later: diff --git a/demo/gintdemo.c b/demo/gintdemo.c index 9532bdb..cfc653d 100644 --- a/demo/gintdemo.c +++ b/demo/gintdemo.c @@ -277,6 +277,9 @@ void tlb_debug(void) } */ +#include +#include + /* main_menu() Displays the main menu and returns user's choice: 0 for [EXIT], @@ -301,7 +304,7 @@ void main_menu(int *category, int *app) }; const char *list_tests[] = { - "Keyboard and events", + "Keyboard & events", "Gray engine", "Image rendering", "Text rendering", @@ -353,9 +356,10 @@ void main_menu(int *category, int *app) { case 0: print(1, 1, "gint %s", gint_version); - print(2, 4, "handler size: %5d", gint_size); - print(2, 5, "mpu type: %7s", mpu); - print(2, 6, "romdata: %08x", &romdata); + print(2, 3, "MPU type %7s", mpu); + print(2, 4, "Add-in size %3dk", + ((uint32_t)&romdata - 0x00300000) >> 10); + print(2, 5, "gint size %5do", gint_size); list = NULL; break; @@ -408,9 +412,6 @@ void main_menu(int *category, int *app) switch(getkey()) { -// case KEY_7: -// crt0_system_menu(); -// break; case KEY_F1: if(!tab) break; tab = 0; @@ -434,6 +435,9 @@ void main_menu(int *category, int *app) index = 0; scroll = 0; break; + case KEY_F5: + gint_switch(); + break; case KEY_F6:; void screen(void); screen(); @@ -480,11 +484,11 @@ void main_menu(int *category, int *app) if(app) *app = index + 1; return; - case KEY_MENU: +/* case KEY_MENU: if(category) *category = 0; if(app) *app = 0; return; - +*/ default: leave = 0; } diff --git a/demo/gintdemo.ld b/demo/gintdemo.ld index 9111fcc..7a7d11e 100644 --- a/demo/gintdemo.ld +++ b/demo/gintdemo.ld @@ -3,7 +3,7 @@ output. Note how symbols romdata, bbss, ebss, bdata and edata are used in the initialization routine (crt0.c) to initialize the application. - Two ram areas are specified. The "real ram" is accessed direcly while + Two ram areas are specified. The "real ram" is accessed directly while the other area is virtualized. It is not possible to execute code in virtualized ram. */ diff --git a/demo/test_keyboard.c b/demo/test_keyboard.c index 3012590..02ea379 100644 --- a/demo/test_keyboard.c +++ b/demo/test_keyboard.c @@ -4,8 +4,9 @@ #include #include -static void draw_keyboard(volatile uint8_t *state) +static int draw_keyboard(volatile uint8_t *state) { + int pressed_keys = 0; int i, j, k, l; int x, y; @@ -29,6 +30,7 @@ static void draw_keyboard(volatile uint8_t *state) // Drawing a filled shape when the key is pressed. if(state[i] & (0x80 >> j)) { + pressed_keys++; for(k = -2; k <= 2; k++) for(l = -2; l <= 2; l++) if(abs(k) + abs(l) <= 2) dpixel(x + k, y + l, color_black); @@ -49,47 +51,61 @@ static void draw_keyboard(volatile uint8_t *state) // An horizontal line to separate parts of the keyboard. dline(5, 28, 32, 28, color_black); + + return pressed_keys; } typedef struct { - event_type_t type; uint32_t key; int repeats; +} history_key_t; -} enhanced_event_t; +typedef struct { + history_key_t *data; + int size; + int pressed; +} history_t; -static void push_history(enhanced_event_t *history, int size, event_t event) +static int pressed_keys = -1; +static int releases = 0; + +static void history_push(history_t *h, event_t event) { - #define event_eq(x, y) \ - ((x).type == (y).type && (x).key == (y).key.code) + // Only reset the number of pressed keys in the history when the actual + // number of pressed keys reaches 0. - // Determining where the history ends. - int length = 0; - while(length < size && history[length].type != event_none) length++; - - // Checking if the previous event is being repeated. - if(length > 0 && event_eq(history[length - 1], event)) + if(event.type == event_key_release) { - history[length - 1].repeats++; + pressed_keys--; + if(!pressed_keys) h->pressed = 0; return; } - // Making up some space if required. - if(length == size) + // Now we're sure a key was pressed or repeated. Check if it's in the + // last pressed elements of the history array, if so, update it. + // Otherwise make space for a new entry and add it. + + if(event.type == event_key_press) pressed_keys++; + + for(int i = h->size - h->pressed; i < h->size; i++) { - for(int i = 0; i < size - 1; i++) history[i] = history[i + 1]; - length = size - 1; + if(h->data[i].key == event.key.code) + { + h->data[i].repeats++; + return; + } } - // Adding a new entry to the history. - history[length].type = event.type; - history[length].key = event.key.code; - history[length].repeats = 1; + // If there are already h->size keys pressed, do not add more. + if(event.type == event_key_press) h->pressed++; + if(h->pressed > h->size) return; - #undef event_eq + for(int i = 0; i < h->size - 1; i++) h->data[i] = h->data[i + 1]; + h->data[h->size - 1].key = event.key.code; + h->data[h->size - 1].repeats = 1; } -static void draw_events(enhanced_event_t *history, int size) +static void draw_events(history_t *h) { const char *key_names[] = { "F1", "F2", "F3", "F4", "F5", "F6", @@ -102,17 +118,21 @@ static void draw_events(enhanced_event_t *history, int size) "1", "2", "3", "+", "-", NULL, "0", ".", "\x08", "(-)", "EXE", NULL }; - const char *event_names[] = { - "None ", "User ", "Press", "Rept.", "Rel. ", "Timer" - }; - for(int i = 0; i < size && history[i].type != event_none; i++) + int y = 3; + + print(8, 2, "%d %d %d", pressed_keys, h->pressed, releases); + + for(int i = 0; i < h->size; i++) { - print(8, 3 + i, "%s %s", event_names[history[i].type], - key_names[key_id(history[i].key)]); - if(history[i].repeats > 1) - print(19, 3 + i, "%d", history[i].repeats); + if(!h->data[i].key) continue; + print(8, y, "%s", key_names[key_id(h->data[i].key)]); + if(h->data[i].repeats > 1) + print(18, y, "%d", h->data[i].repeats); + y++; } + + if(h->pressed > h->size) print(8, 8, "(more)"); } /* @@ -121,23 +141,31 @@ static void draw_events(enhanced_event_t *history, int size) */ void test_keyboard_events(void) { - enhanced_event_t history[5]; - int history_size = 5; + history_key_t history_data[5] = { 0 }; + history_t history = { + .data = history_data, + .size = 5, + .pressed = 0, + }; event_t event; - for(int i = 0; i < history_size; i++) history[i].type = event_none; - while(1) { dclear(); locate(1, 1, "Keyboard and events"); - draw_keyboard(keyboard_stateBuffer()); - draw_events(history, history_size); + + // There may be more than zero keys pressed when this test + // starts. We need to detect this count automatically. + int x = draw_keyboard(keyboard_stateBuffer()); + if(pressed_keys < 0) pressed_keys = x; + + draw_events(&history); dupdate(); event = waitevent(); + if(event.type == event_key_release) releases++; if(event.type == event_key_press && event.key.code == KEY_EXIT) break; - push_history(history, history_size, event); + history_push(&history, event); } } diff --git a/include/gint.h b/include/gint.h index ac264cb..3060a89 100644 --- a/include/gint.h +++ b/include/gint.h @@ -236,4 +236,16 @@ typedef enum */ volatile void *gint_reg(gint_register_t reg); + + +//--- +// Other functions +//--- + +/* + gint_switch() + Temporarily returns to the system's main menu. +*/ +void gint_switch(void); + #endif // _GINT_H diff --git a/include/gray.h b/include/gray.h index a4e3233..86fa721 100644 --- a/include/gray.h +++ b/include/gray.h @@ -51,6 +51,14 @@ uint32_t *gray_lightVRAM(void); */ uint32_t *gray_darkVRAM(void); +/* + gray_currentVRAM() + Returns the currently displayed video ram (if the engine runs). Used + internally, but has no interest for the user. You don't want to draw to + this vram. +*/ +uint32_t *gray_currentVRAM(void); + /* gray_getDelays() Returns the gray engine delays. Pointers are not set if NULL. diff --git a/include/keyboard.h b/include/keyboard.h index f788c13..ea5cd7f 100644 --- a/include/keyboard.h +++ b/include/keyboard.h @@ -162,6 +162,10 @@ typedef enum // compatible models. getkey_manage_backlight = 0x04, + // Allow returning to menu using the [MENU] key. (This operation is not + // absolutely safe.) + getkey_task_switch = 0x08, + // Allow key repetition. This option does not control the generation of // repeat events (use keyboard_setRepeatRate() for this) but filters // them. Please note that modifiers will never be repeated, even when diff --git a/include/modules/interrupts.h b/include/modules/interrupts.h index 41e6bae..54b172e 100644 --- a/include/modules/interrupts.h +++ b/include/modules/interrupts.h @@ -590,7 +590,7 @@ typedef struct uint8_t IMR12; char gap2[15]; -} __attribute__((packed)) mod_intc_masks_7305_t; +} __attribute__((packed, aligned(4))) mod_intc_masks_7305_t; /* mod_intc_userimask_7305_t @@ -605,7 +605,7 @@ typedef struct void set_user_imask(int new_level) { mod_intc_userimask_7305_t mask = *(INTC._7305.USERIMASK); - mask._a5 = 0xa5; + mask._0xa5 = 0xa5; mask.UIMASK = new_level & 0x0f; *(INTC._7305.USERIMASK) = mask; } @@ -613,7 +613,7 @@ typedef struct typedef struct { lword_union(, - uint _a5 :8; /* Always set to 0xa5 before writing */ + uint _0xa5 :8; /* Always set to 0xa5 before writing */ uint :16; uint UIMASK :4; /* User Interrupt Mask Level */ uint :4; @@ -628,7 +628,7 @@ typedef struct */ typedef struct { - byte_union(, + word_union(, uint const NMIL :1; /* NMI Interupt Level */ uint :14; uint NMIFL :1; /* NMI Interrupt Request Flag */ @@ -682,4 +682,7 @@ typedef union } __attribute__((packed)) mod_intc_t; +// Here's what you'll need to use. +extern mod_intc_t INTC; + #endif // _MODULE_INTERRUPTS diff --git a/include/modules/macros.h b/include/modules/macros.h index f17e817..327dde7 100644 --- a/include/modules/macros.h +++ b/include/modules/macros.h @@ -39,7 +39,7 @@ typedef unsigned uint; uint16_t word; \ struct { fields } \ __attribute__((packed)); \ - } __attribute__((packed)) name + } __attribute__((packed, aligned(2))) name /* lword_union() @@ -52,6 +52,6 @@ typedef unsigned uint; uint32_t lword; \ struct { fields } \ __attribute__((packed)); \ - } __attribute__((packed)) name + } __attribute__((packed, aligned(4))) name #endif // _MODULES_MACROS_H diff --git a/src/core/crt0.c b/src/core/crt0.c index be9d0e4..618af26 100644 --- a/src/core/crt0.c +++ b/src/core/crt0.c @@ -140,8 +140,6 @@ __attribute__((section(".pretext.entry"))) int start(void) dg->stage = stage_running; #endif - - // Saving the execution state there. int x = setjmp(env); // If the program has just started, executing main(). Otherwise, the @@ -253,13 +251,3 @@ int atexit(void (*function)(void)) atexit_handlers[atexit_index++] = function; return 0; } - -void crt0_system_menu(void) -{ - fini(); - gint_quit(); - __system_menu(); - mmu_pseudoTLBInit(); - gint_init(); - init(); -} diff --git a/src/core/gint.c b/src/core/gint.c index 6d309f9..f213dcf 100644 --- a/src/core/gint.c +++ b/src/core/gint.c @@ -153,7 +153,7 @@ void gint_install(gint_interrupt_type_t type, void *function) /* gint_uninstall() - Uninstalls the exception or interrupt handler that was used for the + Un-installs the exception or interrupt handler that was used for the given interrupt, falling back to gint's default handler. */ void gint_uninstall(gint_interrupt_type_t type) diff --git a/src/core/gint_sh7705.c b/src/core/gint_sh7705.c index a79802c..80df397 100644 --- a/src/core/gint_sh7705.c +++ b/src/core/gint_sh7705.c @@ -4,7 +4,6 @@ #include #include #include -#include <7705.h> /* gint_reg() @@ -34,15 +33,18 @@ volatile void *gint_reg_7705(gint_register_t reg) void gint_save_7705(environment_7705_t *e) { + mod_intc_7705_t *intc = &INTC._7705; + mod_intc_ipc_7705_t *ipc = &intc->iprs; + // Saving the interrupt masks from registers IPRA to IPRH. - e->IPR[0] = INTC.IPRA.WORD; - e->IPR[1] = INTC.IPRB.WORD; - e->IPR[2] = INTX.IPRC.WORD; - e->IPR[3] = INTX.IPRD.WORD; - e->IPR[4] = INTX.IPRE.WORD; - e->IPR[5] = INTX.IPRF.WORD; - e->IPR[6] = INTX.IPRG.WORD; - e->IPR[7] = INTX.IPRH.WORD; + e->IPR[0] = ipc->IPRA->word; + e->IPR[1] = ipc->IPRB->word; + e->IPR[2] = ipc->IPRC->word; + e->IPR[3] = ipc->IPRD->word; + e->IPR[4] = ipc->IPRE->word; + e->IPR[5] = ipc->IPRF->word; + e->IPR[6] = ipc->IPRG->word; + e->IPR[7] = ipc->IPRH->word; // Saving RTC registers. e->RCR1 = RTC.RCR1->byte; @@ -54,35 +56,39 @@ void gint_save_7705(environment_7705_t *e) e->TMU2 = *(TMU.timers[2]); e->TSTR = TMU.TSTR->byte; - // Saving port data used to access the keyboard. +/* // Saving port data used to access the keyboard. e->PACR = PFC.PACR.WORD; e->PADR = PA.DR.BYTE; e->PBCR = PFC.PBCR.WORD; e->PBDR = PB.DR.BYTE; e->PMCR = PFC.PMCR.WORD; e->PMDR = PM.DR.BYTE; +*/ } void gint_lock_and_setup_7705(void) { + mod_intc_7705_t *intc = &INTC._7705; + mod_intc_ipc_7705_t *ipc = &intc->iprs; + // Disabling everything by default to avoid receiving an interrupt that // the handler doesn't handle, which would cause the user program to // freeze. - INTC.IPRA.WORD = 0x0000; - INTC.IPRB.WORD = 0x0000; - INTX.IPRC.WORD = 0x0000; - INTX.IPRD.WORD = 0x0000; - INTX.IPRE.WORD = 0x0000; - INTX.IPRF.WORD = 0x0000; - INTX.IPRG.WORD = 0x0000; - INTX.IPRH.WORD = 0x0000; + ipc->IPRA->word = 0x0000; + ipc->IPRB->word = 0x0000; + ipc->IPRC->word = 0x0000; + ipc->IPRD->word = 0x0000; + ipc->IPRE->word = 0x0000; + ipc->IPRF->word = 0x0000; + ipc->IPRG->word = 0x0000; + ipc->IPRH->word = 0x0000; // Allowing RTC and timer (which handles keyboard and a whole bunch of // other things). - INTC.IPRA.BIT._RTC = 10; - INTC.IPRA.BIT._TMU0 = 12; - INTC.IPRA.BIT._TMU1 = 12; - INTC.IPRA.BIT._TMU2 = 12; + ipc->IPRA->RTC = 10; + ipc->IPRA->TMU0 = 12; + ipc->IPRA->TMU1 = 12; + ipc->IPRA->TMU2 = 12; // Don't enable RTC periodic signals by default. RTC.RCR2->byte = 0x09; @@ -90,15 +96,18 @@ void gint_lock_and_setup_7705(void) void gint_restore_and_unlock_7705(environment_7705_t *e) { + mod_intc_7705_t *intc = &INTC._7705; + mod_intc_ipc_7705_t *ipc = &intc->iprs; + // Restoring the saved states. - INTC.IPRA.WORD = e->IPR[0]; - INTC.IPRB.WORD = e->IPR[1]; - INTX.IPRC.WORD = e->IPR[2]; - INTX.IPRD.WORD = e->IPR[3]; - INTX.IPRE.WORD = e->IPR[4]; - INTX.IPRF.WORD = e->IPR[5]; - INTX.IPRG.WORD = e->IPR[6]; - INTX.IPRH.WORD = e->IPR[7]; + ipc->IPRA->word = e->IPR[0]; + ipc->IPRB->word = e->IPR[1]; + ipc->IPRC->word = e->IPR[2]; + ipc->IPRD->word = e->IPR[3]; + ipc->IPRE->word = e->IPR[4]; + ipc->IPRF->word = e->IPR[5]; + ipc->IPRG->word = e->IPR[6]; + ipc->IPRH->word = e->IPR[7]; // Restoring RTC registers. RTC.RCR1->byte = e->RCR1; @@ -110,11 +119,12 @@ void gint_restore_and_unlock_7705(environment_7705_t *e) *(TMU.timers[2]) = e->TMU2; TMU.TSTR->byte = e->TSTR; - // Restoring keyboard-related I/O port registers. +/* // Restoring keyboard-related I/O port registers. PFC.PACR.WORD = e->PACR; PA.DR.BYTE = e->PADR; PFC.PBCR.WORD = e->PBCR; PB.DR.BYTE = e->PBDR; PFC.PMCR.WORD = e->PMCR; PM.DR.BYTE = e->PMDR; +*/ } diff --git a/src/core/init_quit.c b/src/core/init_quit.c index a50d287..6103f41 100644 --- a/src/core/init_quit.c +++ b/src/core/init_quit.c @@ -79,3 +79,46 @@ void gint_quit(void) // Restoring the system's VBR. gint_setvbr(gint.system_vbr, stop); } + + + +//--- +// System-switch technique +//--- + +#include +#include + +/* + gint_switch() + Temporarily returns to the system's main menu. +*/ +static environment_t switch_env; +static void switch_(void) +{ + isSH3() ? gint_restore_and_unlock_7705(&switch_env.env_7705) + : gint_restore_and_unlock_7305(&switch_env.env_7305); +} +void gint_switch(void) +{ + // Save the current environment in a special buffer, so that we can + // restore it if we ever come back to gint. + isSH3() ? gint_save_7705(&switch_env.env_7705) + : gint_save_7305(&switch_env.env_7305); + // Give the control back to the system. + gint_setvbr(gint.system_vbr, stop); + + // When returning to the add-in from the menu, the system displays the + // add-in's video ram again, but it's often blank. We thus need to copy + // the contents of the gint video ram to the system's. + void *vram = gray_runs() + ? gray_currentVRAM() + : display_getCurrentVRAM(); + + // Use system calls to put KEY_MENU in the key buffer and invoke + // GetKeyWait(), triggering the main menu. + __system_menu(vram); + + // If the user came back, restore the gint working environment. + gint_setvbr(gint.gint_vbr, switch_); +} diff --git a/src/core/syscalls.s b/src/core/syscalls.s index 0fdb38d..960c2de 100644 --- a/src/core/syscalls.s +++ b/src/core/syscalls.s @@ -4,7 +4,6 @@ All the system calls used by the library. Somehow "the less, the better". We have finally gotten rid of every obscure system-related syscalls! - Looks like an important step towards being completely free-standing :) */ .global ___malloc @@ -45,6 +44,18 @@ ___system_menu: sts.l pr, @-r15 add #-4, r15 + /* Copying gint's VRAM into the system's. */ + mov.l syscall_table, r1 + mov.l .syscall_vram, r0 + jsr @r1 + mov.l r4, @r15 /* gint video ram */ + mov r0, r4 + mov.l @r15, r5 + mov.w .vram_size, r6 + mov.l .memcpy, r1 + jsr @r1 + nop + /* Putting the matrix code in the key buffer. */ mov r15, r4 @@ -60,14 +71,14 @@ ___system_menu: mov r15, r4 /* column pointer */ add #-4, r15 mov r15, r5 /* row pointer */ - mov #-5, r15 - mov r15, r1 + add #-4, r15 + mov r15, r1 /* keycode pointer */ mov #2, r6 /* type of waiting */ mov #0, r7 /* timeout period */ - mov.l r1, @-r15 /* keycode pointer */ - mov #0, r2 - mov.l r2, @-r15 /* allow return to menu */ + mov.l r1, @-r15 + mov #0, r2 /* allow return to menu */ + mov.l r2, @-r15 mov.l syscall_table, r1 mov.l .syscall_getkeywait, r0 @@ -88,8 +99,14 @@ ___system_menu: .long 0x0247 .syscall_putcode: .long 0x024f +.syscall_vram: + .long 0x0135 .matrix_menu: .word 0x0308 +.vram_size: + .word 1024 +.memcpy: + .long _memcpy diff --git a/src/ctype/ctype_functions.c b/src/ctype/ctype_functions.c index f4697ac..ad1500b 100644 --- a/src/ctype/ctype_functions.c +++ b/src/ctype/ctype_functions.c @@ -69,3 +69,5 @@ _inline int tolower(int c) { _inline int toupper(int c) { return c & ~(islower(c) << 1); } + +#undef _inline diff --git a/src/gray/gray_engine.c b/src/gray/gray_engine.c index 3d12bb1..8e9d207 100644 --- a/src/gray/gray_engine.c +++ b/src/gray/gray_engine.c @@ -140,6 +140,17 @@ uint32_t *gray_darkVRAM(void) return vrams[(~current & 2) | 1]; } +/* + gray_currentVRAM() + Returns the currently displayed video ram (if the engine runs). Used + internally, but has no interest for the user. You don't want to draw to + this vram. +*/ +uint32_t *gray_currentVRAM(void) +{ + return vrams[current ^ 1]; +} + /* gray_getDelays() Returns the gray engine delays. Pointers are not set if NULL. diff --git a/src/keyboard/getkey.c b/src/keyboard/getkey.c index 4889b77..1fc3eb1 100644 --- a/src/keyboard/getkey.c +++ b/src/keyboard/getkey.c @@ -3,6 +3,7 @@ #include #include #include +#include /* getkey() @@ -15,6 +16,7 @@ int getkey(void) getkey_shift_modifier | getkey_alpha_modifier | getkey_manage_backlight | + getkey_task_switch | getkey_repeat_arrow_keys, 0 @@ -62,6 +64,11 @@ int getkey_opt(getkey_option_t options, int delay_ms) modifier &= ~MOD_SHIFT; continue; } + if((options & getkey_task_switch) && key == KEY_MENU + && !modifier) + { + continue; + } if(options & getkey_shift_modifier && key == KEY_SHIFT) { modifier ^= MOD_SHIFT; @@ -98,6 +105,13 @@ int getkey_opt(getkey_option_t options, int delay_ms) break; case event_key_release: + if((options & getkey_task_switch) && event.key.code == KEY_MENU + && !modifier) + { + gint_switch(); + continue; + } + if((int)event.key.code != last_key) break; last_key = KEY_NONE; last_repeats = 0; diff --git a/src/keyboard/keyboard_core.c b/src/keyboard/keyboard_core.c index bb74325..6e956f4 100644 --- a/src/keyboard/keyboard_core.c +++ b/src/keyboard/keyboard_core.c @@ -82,42 +82,66 @@ static inline void push_release(int keycode) */ void keyboard_interrupt(void) { - uint8_t state[10] = { 0 }; + // This procedure is critical for speed. If there's anything that could + // be optimized, please tell me. + // New keyboard state. + uint8_t state[10] = { 0 }; isSH3() ? keyboard_updateState_7705(state) : keyboard_updateState_7305(state); - // This procedure really needs to be speed-optimized... and it's hard - // because of this bit manipulation. This condition handles AC/ON. - if(keyboard_state[0] ^ state[0]) - { - uint8_t pressed = ~keyboard_state[0] & state[0]; - uint8_t released = keyboard_state[0] & ~state[0]; + // Event types associated with each old/new state pair (see later). + uint8_t events[4] = { + event_none, + event_key_release, + event_key_press, + event_key_repeat, + }; - if(pressed & 1) push_press(KEY_AC_ON); - if(released & 1) push_release(KEY_AC_ON); + // AC/ON has not a matrix code that corresponds to its location in the + // buffer, so we need to check it independently. + if(keyboard_state[0] | state[0]) + { + int kind = (state[0] << 1) | keyboard_state[0]; + + if(kind) + { + event_t event = { + .type = events[kind], + .key.code = KEY_AC_ON, + .key.id = key_id(KEY_AC_ON), + .key.character = key_char(KEY_AC_ON) + }; + event_push(event); + } } keyboard_state[0] = state[0]; for(int row = 1; row <= 9; row++) { - uint8_t pressed = ~keyboard_state[row] & state[row]; - uint8_t repeated = keyboard_state[row] & state[row]; - uint8_t released = keyboard_state[row] & ~state[row]; + // Shifting the new state will allow us to make up a 2-bit + // value for each key more easily, improving efficiency. + uint16_t old = keyboard_state[row]; + uint16_t new = state[row] << 1; + + if(!new && !old) continue; keyboard_state[row] = state[row]; - // Make this a bit faster. - if(!(pressed | repeated | released)) continue; - - for(int column = 0; column < 8; column++) + for(uint8_t code = row; code < (row | 0x80); code += 0x10) { - if(pressed & 1) push_press ((column << 4) | row); - if(repeated & 1) push_repeat ((column << 4) | row); - if(released & 1) push_release((column << 4) | row); + int kind = (new & 2) | (old & 1); + old >>= 1; + new >>= 1; - pressed >>= 1; - repeated >>= 1; - released >>= 1; + if(!kind) continue; + + event_t event = { + .type = events[kind], + .key.code = code, + .key.id = key_id(code), + .key.character = key_char(code) + }; + event_push(event); } } diff --git a/src/rtc/rtc_callback.c b/src/rtc/rtc_callback.c index 1efeb24..775910d 100644 --- a/src/rtc/rtc_callback.c +++ b/src/rtc/rtc_callback.c @@ -44,7 +44,7 @@ static void rtc_cb_update(void) -1 Array is full -2 Invalid parameter The number of repeats may be set to 0, in which case the callback is - called indefinitely unless the user calls rtc_cb_end(). + called indefinitely until the user calls rtc_cb_end(). */ int rtc_cb_add(rtc_frequency_t freq, void (*function)(void), int repeats) { diff --git a/version b/version index 405a713..18bb01c 100644 --- a/version +++ b/version @@ -1 +1 @@ -beta-0.9-354 +beta-0.9-410