Key repeat events & Timer callbacks with arguments. Fixed sleep_us().

This commit is contained in:
lephe 2017-02-25 23:19:35 +01:00
parent 4d0794f899
commit 0a694a1cd8
25 changed files with 264 additions and 189 deletions

19
TODO
View file

@ -9,22 +9,21 @@ Simple improvements:
- demo: Try 284x124 at (-60, -28) (all disadvantages) - demo: Try 284x124 at (-60, -28) (all disadvantages)
- display: Rectangle-based drawing functions - display: Rectangle-based drawing functions
- time: Compute CLOCKS_PER_SEC - time: Compute CLOCKS_PER_SEC
- events: Introduce KeyRepeat events
- string: Use cmp/str to implement memchr() (assembler examples) - string: Use cmp/str to implement memchr() (assembler examples)
- string: Do some tests for memcmp() - string: Do some tests for memcmp()
- core: Register more interrupts (and understand their parameters) - core: Register more interrupts (and understand their parameters)
- rtc: Take care of carry when reading time - rtc: Take care of carry when reading time
Larger improvements: Larger improvements:
- errno: Introduce errno and use it more or less everywhere - errno: Introduce errno and use it more or less everywhere
- bopti: Monochrome bitmaps blending modes - bopti: Monochrome bitmaps blending modes
- bopti: Handle partial transparency - bopti: Handle partial transparency
- core: Implement all callbacks and a complete user API - core: Implement all callbacks and a complete user API
* core: Better save registers * core: Better save registers
* core: Allow return to menu * core: Allow return to menu
- serial: Implement a driver - serial: Implement a driver
- usb: Implement a driver - usb: Implement a driver
- esper: Cleaner playback, synthetizing - esper: Cleaner playback, synthetizing
- clock: Handle overclocking (relaunch clocks when overclocking) - clock: Handle overclocking (relaunch clocks when overclocking)
Things to investigate: Things to investigate:
- Packed bit fields alignment - Packed bit fields alignment

View file

@ -300,7 +300,7 @@ void main_menu(int *category, int *app)
}; };
const char *list_tests[] = { const char *list_tests[] = {
"Keyboard", "Keyboard and events",
"Gray engine", "Gray engine",
"Image rendering", "Image rendering",
"Text rendering", "Text rendering",
@ -495,6 +495,8 @@ int main(void)
{ {
int category, app; int category, app;
sleep_ms(2000);
while(1) while(1)
{ {
main_menu(&category, &app); main_menu(&category, &app);
@ -502,7 +504,7 @@ int main(void)
switch((category << 8) | app) switch((category << 8) | app)
{ {
case 0x0101: test_keyboard(); break; case 0x0101: test_keyboard_events(); break;
case 0x0102: test_gray(); break; case 0x0102: test_gray(); break;
case 0x0103: test_bopti(); break; case 0x0103: test_bopti(); break;
case 0x0104: test_tales(); break; case 0x0104: test_tales(); break;

View file

@ -46,10 +46,10 @@ void print(int x, int y, const char *format, ...);
//--- //---
/* /*
test_keyboard() test_keyboard_events()
Displays a real-time multigetkey() and the keyboard state. Real-time keyboard management with events.
*/ */
void test_keyboard(void); void test_keyboard_events(void);
/* /*
test_gray() test_gray()

View file

@ -2,13 +2,9 @@
#include <display.h> #include <display.h>
#include <keyboard.h> #include <keyboard.h>
#include <stdlib.h> #include <stdlib.h>
#include <events.h>
/* static void draw_keyboard(volatile uint8_t *state)
test_keyboard()
Displays a real-time multigetkey() and the keyboard state.
*/
static void draw(volatile unsigned char *state)
{ {
int i, j, k, l; int i, j, k, l;
int x, y; int x, y;
@ -22,12 +18,16 @@ static void draw(volatile unsigned char *state)
if(i == 4 && j == 5) continue; if(i == 4 && j == 5) continue;
x = 5 * j + 1; x = 5 * j + 1;
y = 61 - 5 * i; y = 59 - 5 * i;
// Space for the horizontal line.
y += 3 * (i < 7);
// Moving the [AC/ON] key. // Moving the [AC/ON] key.
if(!i) x = 5 * (5) + 1, y = 61 - 5 * (4); if(!i) x = 5 * (5) + 1, y = 61 - 5 * (4) + 1;
// Drawing a filled shape when the key is pressed. // Drawing a filled shape when the key is pressed.
if(state[i] & (128 >> j)) if(state[i] & (0x80 >> j))
{ {
for(k = -2; k <= 2; k++) for(l = -2; l <= 2; l++) for(k = -2; k <= 2; k++) for(l = -2; l <= 2; l++)
if(abs(k) + abs(l) <= 2) if(abs(k) + abs(l) <= 2)
@ -40,9 +40,55 @@ static void draw(volatile unsigned char *state)
if(k || l) dpixel(x + k, y + l, Color_Black); if(k || l) dpixel(x + k, y + l, Color_Black);
} }
} }
// Binding the arrow keys together for a more visual thing.
dpixel(28, 19, Color_Black); dpixel(29, 19, Color_Black);
dpixel(28, 24, Color_Black); dpixel(29, 24, Color_Black);
dpixel(26, 21, Color_Black); dpixel(26, 22, Color_Black);
dpixel(31, 21, Color_Black); dpixel(31, 22, Color_Black);
// An horizontal line to separate parts of the keyboard.
dline(5, 28, 32, 28, Color_Black);
} }
void test_keyboard(void) typedef struct {
event_type_t type;
int key;
int repeats;
} enhanced_event_t;
static void push_history(enhanced_event_t *history, int size, event_t event)
{
#define event_eq(x, y) ((x).type == (y).type && (x).key == (y).key)
// Determining where the history ends.
int length = 0;
while(length < size && history[length].type != ET_None) length++;
// Checking if the previous event is being repeated.
if(length > 0 && event_eq(history[length - 1], event))
{
history[length - 1].repeats++;
return;
}
// Making up some space if required.
if(length == size)
{
for(int i = 0; i < size - 1; i++) history[i] = history[i + 1];
length = size - 1;
}
// Adding a new entry to the history.
history[length].type = event.type;
history[length].key = event.key;
history[length].repeats = 1;
#undef event_eq
}
static void draw_events(enhanced_event_t *history, int size)
{ {
const char *key_names[] = { const char *key_names[] = {
"F1", "F2", "F3", "F4", "F5", "F6", "F1", "F2", "F3", "F4", "F5", "F6",
@ -55,28 +101,41 @@ void test_keyboard(void)
"1", "2", "3", "+", "-", NULL, "1", "2", "3", "+", "-", NULL,
"0", ".", "\x08", "(-)", "EXE", NULL "0", ".", "\x08", "(-)", "EXE", NULL
}; };
const char *event_names[] = {
"None ", "User ", "Press", "Rept.", "Rel. "
};
volatile unsigned char *state = keystate(); for(int i = 0; i < size && history[i].type != ET_None; i++)
int keys[4] = { 0 }; {
int i; print(8, 3 + i, "%s %s", event_names[history[i].type],
key_names[keyid(history[i].key)]);
if(history[i].repeats > 1)
print(19, 3 + i, "%d", history[i].repeats);
}
}
/*
test_keyboard_events()
Real-time keyboard management with events.
*/
void test_keyboard_events(void)
{
enhanced_event_t history[5];
int history_size = 5;
event_t event;
for(int i = 0; i < history_size; i++) history[i].type = ET_None;
while(1) while(1)
{ {
dclear(); dclear();
locate(1, 1, "Keyboard driver"); locate(1, 1, "Keyboard and events");
locate(8, 3, "Pressed keys:"); draw_keyboard(keystate());
draw(state); draw_events(history, history_size);
if(keys[0] == KEY_NONE) locate(9, 4, ":None");
else for(i = 0; i < 4 && keys[i] != KEY_NONE; i++)
{
locate( 9, i + 4, ":");
locate(10, i + 4, key_names[keyid(keys[i])]);
}
dupdate(); dupdate();
multigetkey(keys, 4, 1); event = waitevent();
if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break; if(event.type == ET_KeyPress && event.key == KEY_EXIT) break;
push_history(history, history_size, event);
} }
} }

View file

@ -35,7 +35,7 @@ static void timing_timer(void)
static void timing_start(void) static void timing_start(void)
{ {
timer_start(TIMER_USER, 64, Clock_Hz, timing_timer, 0); timer_start(TIMER_USER, 64, Clock_Hz, timing_timer, NULL, 0);
rtc_cb_edit(cb_id, RTCFreq_64Hz, timing_rtc); rtc_cb_edit(cb_id, RTCFreq_64Hz, timing_rtc);
elapsed_timer = 0; elapsed_timer = 0;

View file

@ -9,15 +9,11 @@
#ifndef _EVENTS_H #ifndef _EVENTS_H
#define _EVENTS_H #define _EVENTS_H
//---
// Type definitions.
//---
/* /*
enum EventType event_type_t
Something user programs will surely use most often. Something user programs will surely use most often.
*/ */
enum EventType typedef enum
{ {
EventType_None = 0, EventType_None = 0,
ET_None = EventType_None, ET_None = EventType_None,
@ -28,27 +24,32 @@ enum EventType
EventType_KeyPressed = 2, EventType_KeyPressed = 2,
ET_KeyPress = EventType_KeyPressed, ET_KeyPress = EventType_KeyPressed,
EventType_KeyReleased = 3, EventType_KeyRepeated = 3,
ET_KeyRepeat = EventType_KeyRepeated,
EventType_KeyReleased = 4,
ET_KeyRel = EventType_KeyReleased, ET_KeyRel = EventType_KeyReleased,
};
} event_type_t;
/* /*
struct Event event_t
Wake up, something's going on. The union member that holds information Wake up, something's going on. The union member that holds information
about the event is implicitly defined by the type attribute. about the event is implicitly defined by the type attribute.
*/ */
struct Event typedef struct
{ {
enum EventType type; event_type_t type;
union union
{ {
// For ET_User. // For ET_User.
void *data; void *data;
// For ET_KeyPress and ET_KeyRel. // For ET_KeyPress, ET_KeyRepeat and ET_KeyRel.
int key; int key;
}; };
};
} event_t;
@ -64,21 +65,21 @@ struct Event
allowed. allowed.
Returns non-zero on error. Returns non-zero on error.
*/ */
int event_push(struct Event event); int event_push(event_t event);
/* /*
getevent() waitevent()
Returns the next event. If no one is available, waits for something to Returns the next event. If no one is available, waits for something to
happen. This function uses low-level sleep and should be preferred to happen. This function uses low-level sleep and should be preferred to
active waiting using loops. active waiting using loops.
*/ */
struct Event getevent(void); event_t waitevent(void);
/* /*
pollevent() pollevent()
Returns the next event. If no one is available, returns an event whose Returns the next event. If no one is available, returns an event whose
type is ET_None. This function always returns immediately. type is ET_None. This function always returns immediately.
*/ */
struct Event pollevent(void); event_t pollevent(void);
#endif // _EVENTS_H #endif // _EVENTS_H

View file

@ -12,7 +12,7 @@
like any other queue. Trying to add an event when the queue is full like any other queue. Trying to add an event when the queue is full
fails, and the operation is ignored. fails, and the operation is ignored.
*/ */
extern volatile struct Event event_queue[]; extern volatile event_t event_queue[];
extern volatile int queue_start; extern volatile int queue_start;
extern volatile int queue_size; extern volatile int queue_size;

View file

@ -5,7 +5,7 @@
#include <clock.h> #include <clock.h>
// Keyboard variables. // Keyboard variables.
extern volatile unsigned char keyboard_state[10]; extern volatile uint8_t keyboard_state[10];
extern volatile int interrupt_flag; extern volatile int interrupt_flag;
// Key statistics. // Key statistics.
@ -19,7 +19,7 @@ extern unsigned cb_id;
getPressedKey() getPressedKey()
Finds a pressed key in the keyboard state and returns it. Finds a pressed key in the keyboard state and returns it.
*/ */
int getPressedKey(volatile unsigned char *keyboard_state); int getPressedKey(volatile uint8_t *keyboard_state);
/* /*
getPressedKeys() getPressedKeys()
@ -28,7 +28,13 @@ int getPressedKey(volatile unsigned char *keyboard_state);
WARNING: keyboard artifacts make this function read as pressed keys WARNING: keyboard artifacts make this function read as pressed keys
that aren't (typically, LEFT + DOWN + SHIFT => ALPHA). that aren't (typically, LEFT + DOWN + SHIFT => ALPHA).
*/ */
int getPressedKeys(volatile unsigned char *keyboard_state, int *keys, int getPressedKeys(volatile uint8_t *keyboard_state, int *keys, int count);
int count);
/*
keyboard_updateState()
Updates the keyboard state.
*/
void keyboard_updateState_7705(volatile uint8_t *state);
void keyboard_updateState_7305(volatile uint8_t *state);
#endif // _INTERNALS_KEYBOARD_H #endif // _INTERNALS_KEYBOARD_H

View file

@ -7,7 +7,8 @@
*/ */
struct Timer struct Timer
{ {
void (*callback)(void); void *callback;
void *data;
int repeats; int repeats;
}; };

View file

@ -13,6 +13,7 @@
#ifndef _KEYBOARD_H #ifndef _KEYBOARD_H
#define _KEYBOARD_H 1 #define _KEYBOARD_H 1
#include <stdint.h>
#include <rtc.h> #include <rtc.h>
//--- //---
@ -232,7 +233,7 @@ int keylast(int *repeat_count);
functions, but the buffer data is very volatile. Therefore, data functions, but the buffer data is very volatile. Therefore, data
written to the buffer could be replaced anytime. written to the buffer could be replaced anytime.
*/ */
volatile unsigned char *keystate(void); volatile uint8_t *keystate(void);
@ -268,37 +269,4 @@ int keychar(int key);
*/ */
enum KeyType keytype(int key); enum KeyType keytype(int key);
//---
// Internal API.
// Reference here for documentation purposes only. Do not call.
//---
/*
keyboard_interrupt()
Notifies the keyboard module that an interrupt request has been issued,
and updates the keyboard state.
*/
void keyboard_interrupt(void);
/*
keyboard_updateState()
Updates the keyboard state.
*/
void keyboard_updateState_7705(volatile unsigned char *state);
void keyboard_updateState_7305(volatile unsigned char *state);
/*
keyboard_init()
Starts the keyboard timer.
*/
void keyboard_init(void) __attribute__((constructor));
/*
keyboard_quit()
Stops the keyboard timer.
*/
void keyboard_quit(void) __attribute__((destructor));
#endif // _KEYBOARD_H #endif // _KEYBOARD_H

View file

@ -48,17 +48,22 @@
not running the gray engine. not running the gray engine.
Unit names are defined in the clock.h header and must be one of the Unit names are defined in the clock.h header and must be one of the
following: following:
- Clock_us (microseconds) - Clock_us (microseconds)
- Clock_ms (milliseconds) - Clock_ms (milliseconds)
- Clock_s (seconds) - Clock_s (seconds)
- Clock_Hz (hertz) - Clock_Hz (hertz)
- Clock_kHz (kilohertz) - Clock_kHz (kilohertz)
- Clock_MHz (megahertz) - Clock_MHz (megahertz)
The number of repeats may to set to 0. In this case, the timer will not The number of repeats may to set to 0. In this case, the timer will not
stop until timer_stop() is explicitly called. stop until timer_stop() is explicitly called.
The callback is expected to be a function of the following type:
- void callback(void) if data == NULL
- void callback(void *data) if data is non-NULL
In the latter case, the data pointer will be passed as argument to the
callback function.
*/ */
void timer_start(int timer, int delay_or_frequency, enum ClockUnit unit, void timer_start(int timer, int delay_or_frequency, enum ClockUnit unit,
void (*callback)(void), int repeats); void *callback, void *data, int repeats);
/* /*
timer_start2() timer_start2()
@ -71,8 +76,8 @@ void timer_start(int timer, int delay_or_frequency, enum ClockUnit unit,
- TIMER_Po_256 - TIMER_Po_256
- TIMER_TCLK - TIMER_TCLK
*/ */
void timer_start2(int timer, int delay, int prescaler, void (*callback)(void), void timer_start2(int timer, int delay, int prescaler, void *callback,
int repeats); void *data, int repeats);
/* /*
timer_stop() timer_stop()

View file

@ -4,6 +4,7 @@
#include <rtc.h> #include <rtc.h>
#include <stddef.h> #include <stddef.h>
#include <mpu.h> #include <mpu.h>
#include <stdint.h>
static clock_config_t conf = { static clock_config_t conf = {
.FLL = -1, .PLL = -1, .FLL = -1, .PLL = -1,
@ -21,27 +22,36 @@ static clock_config_t conf = {
int clock_setting(int duration, enum ClockUnit unit) int clock_setting(int duration, enum ClockUnit unit)
{ {
if(conf.Pphi_f <= 0) return -1; if(conf.Pphi_f <= 0) return -1;
int f = conf.Pphi_f >> 2; uint64_t f = conf.Pphi_f >> 2;
uint64_t result;
switch(unit) switch(unit)
{ {
case Clock_us: case Clock_us:
return (duration * f) / 1000000; result = (duration * f) / 1000000;
break;
case Clock_ms: case Clock_ms:
return (duration * f) / 1000; result = (duration * f) / 1000;
break;
case Clock_s: case Clock_s:
return (duration * f); result = (duration * f);
break;
case Clock_Hz: case Clock_Hz:
return f / duration; result = f / duration;
break;
case Clock_kHz: case Clock_kHz:
return f / (duration * 1000); result = f / (duration * 1000);
break;
case Clock_MHz: case Clock_MHz:
return f / (duration * 1000000); result = f / (duration * 1000000);
break;
default: default:
return -1; return -1;
} }
return (result > 0xffffffff) ? (0xffffffff) : (result);
} }
/* /*
@ -60,7 +70,7 @@ clock_config_t clock_config(void)
void sleep(void) void sleep(void)
{ {
__asm__( __asm__(
"sleep\n\t" "sleep"
); );
} }
@ -71,10 +81,9 @@ void sleep(void)
than requested. than requested.
*/ */
static volatile int sleep_done = 0; static void sleep_callback(void *flag)
static void sleep_callback(void)
{ {
sleep_done = 1; *((int *)flag) = 1;
} }
void sleep_ms(int ms_delay) void sleep_ms(int ms_delay)
@ -83,8 +92,10 @@ void sleep_ms(int ms_delay)
} }
void sleep_us(int us_delay) void sleep_us(int us_delay)
{ {
sleep_done = 0; volatile int sleep_done = 0;
timer_start(TIMER_USER, us_delay, Clock_us, sleep_callback, 1); timer_start(TIMER_USER, us_delay, Clock_us, sleep_callback,
(void *)&sleep_done, 1);
do sleep(); do sleep();
while(!sleep_done); while(!sleep_done);
} }
@ -133,6 +144,7 @@ void clock_measure(void)
tmu->TCR.CKEG = 0; tmu->TCR.CKEG = 0;
timers[TIMER_USER].callback = NULL; timers[TIMER_USER].callback = NULL;
timers[TIMER_USER].data = NULL;
timers[TIMER_USER].repeats = 0; timers[TIMER_USER].repeats = 0;
cb_id_7705 = rtc_cb_add(RTCFreq_256Hz, clock_measure_7705, 0); cb_id_7705 = rtc_cb_add(RTCFreq_256Hz, clock_measure_7705, 0);

View file

@ -7,9 +7,9 @@
Returns the next event. If no one is available, returns an event whose Returns the next event. If no one is available, returns an event whose
type is ET_None. This function always returns immediately. type is ET_None. This function always returns immediately.
*/ */
struct Event pollevent(void) event_t pollevent(void)
{ {
struct Event event = { event_t event = {
.type = ET_None .type = ET_None
}; };
if(queue_size <= 0) return event; if(queue_size <= 0) return event;
@ -24,14 +24,14 @@ struct Event pollevent(void)
} }
/* /*
getevent() waitevent()
Returns the next event. If no one is available, waits for something to Returns the next event. If no one is available, waits for something to
happen. This function uses low-level sleep and should be preferred to happen. This function uses low-level sleep and should be preferred to
active waiting using loops. active waiting using loops.
*/ */
struct Event getevent(void) event_t waitevent(void)
{ {
struct Event event; event_t event;
while((event = pollevent()).type == ET_None) sleep(); while((event = pollevent()).type == ET_None) sleep();
return event; return event;

View file

@ -1,7 +1,7 @@
#include <internals/events.h> #include <internals/events.h>
#include <events.h> #include <events.h>
volatile struct Event event_queue[EVENTS_QUEUE_SIZE]; volatile event_t event_queue[EVENTS_QUEUE_SIZE];
volatile int queue_start = 0; volatile int queue_start = 0;
volatile int queue_size = 0; volatile int queue_size = 0;
@ -11,7 +11,7 @@ volatile int queue_size = 0;
or pollevent() later. Pushing ET_None events is not allowed. or pollevent() later. Pushing ET_None events is not allowed.
Returns non-zero on error. Returns non-zero on error.
*/ */
int event_push(struct Event event) int event_push(event_t event)
{ {
if(queue_size >= EVENTS_QUEUE_SIZE) return 1; if(queue_size >= EVENTS_QUEUE_SIZE) return 1;
if(event.type == ET_None) return 2; if(event.type == ET_None) return 2;

View file

@ -68,7 +68,8 @@ void gray_start(void)
{ {
if(runs) return; if(runs) return;
timer_start2(TIMER_GRAY, delays[0], GRAY_PRESCALER, gray_interrupt, 0); timer_start2(TIMER_GRAY, delays[0], GRAY_PRESCALER, gray_interrupt,
NULL, 0);
current &= 1; current &= 1;
runs = 1; runs = 1;
} }

View file

@ -4,7 +4,7 @@
getPressedKey() getPressedKey()
Finds a pressed key in the keyboard state and returns it. Finds a pressed key in the keyboard state and returns it.
*/ */
int getPressedKey(volatile unsigned char *keyboard_state) int getPressedKey(volatile uint8_t *keyboard_state)
{ {
int row = 1, column = 0; int row = 1, column = 0;
int state; int state;

View file

@ -5,8 +5,7 @@
Find 'count' pressed keys in the keyboard state and fills the 'keys' Find 'count' pressed keys in the keyboard state and fills the 'keys'
array. Returns the number of actually-pressed keys found. array. Returns the number of actually-pressed keys found.
*/ */
int getPressedKeys(volatile unsigned char *keyboard_state, int *keys, int getPressedKeys(volatile uint8_t *keyboard_state, int *keys, int count)
int count)
{ {
int row = 1, column; int row = 1, column;
int found = 0, actually_pressed; int found = 0, actually_pressed;

View file

@ -25,7 +25,7 @@ int getkey(void)
If max_cycles is non-zero and positive, getkey_opt() will return If max_cycles is non-zero and positive, getkey_opt() will return
KEY_NOEVENT if no event occurs during max_cycle analysis. KEY_NOEVENT if no event occurs during max_cycle analysis.
*/ */
void getkey_opt_wait(int *cycles) static void getkey_opt_wait(int *cycles)
{ {
while(!interrupt_flag) sleep(); while(!interrupt_flag) sleep();
interrupt_flag = 0; interrupt_flag = 0;
@ -34,7 +34,7 @@ void getkey_opt_wait(int *cycles)
} }
int getkey_opt(enum GetkeyOpt options, int cycles) int getkey_opt(enum GetkeyOpt options, int cycles)
{ {
struct Event event; event_t event;
int modifier = 0; int modifier = 0;
static int event_ref = 0; static int event_ref = 0;
@ -120,19 +120,3 @@ int getkey_opt(enum GetkeyOpt options, int cycles)
event_ref = 0; event_ref = 0;
return KEY_NONE; return KEY_NONE;
} }
/*
int getkey_opt(enum GetkeyOpt options, int max_cycles)
{
while(max_cycles != 0)
{
// Handling "new key" events.
// Handling key repetitions.
}
// When no key was pressed during the given delay...
return KEY_NOEVENT;
}
*/

View file

@ -10,7 +10,7 @@
//--- //---
// These ones get modified by interrupts. // These ones get modified by interrupts.
volatile unsigned char keyboard_state[10] = { 0 }; volatile uint8_t keyboard_state[10] = { 0 };
volatile int interrupt_flag = 0; volatile int interrupt_flag = 0;
// Key statistics. // Key statistics.
@ -28,16 +28,25 @@ unsigned cb_id;
static void push_press(int keycode) static void push_press(int keycode)
{ {
struct Event event = { event_t event = {
.type = ET_KeyPress, .type = ET_KeyPress,
.key = keycode, .key = keycode,
}; };
event_push(event); event_push(event);
} }
static void push_repeat(int keycode)
{
event_t event = {
.type = ET_KeyRepeat,
.key = keycode,
};
event_push(event);
}
static void push_release(int keycode) static void push_release(int keycode)
{ {
struct Event event = { event_t event = {
.type = ET_KeyRel, .type = ET_KeyRel,
.key = keycode, .key = keycode,
}; };
@ -51,7 +60,7 @@ static void push_release(int keycode)
*/ */
void keyboard_interrupt(void) void keyboard_interrupt(void)
{ {
unsigned char state[10] = { 0 }; uint8_t state[10] = { 0 };
isSH3() ? keyboard_updateState_7705(state) isSH3() ? keyboard_updateState_7705(state)
: keyboard_updateState_7305(state) : keyboard_updateState_7305(state)
@ -61,8 +70,8 @@ void keyboard_interrupt(void)
// AC/ON. // AC/ON.
if(keyboard_state[0] ^ state[0]) if(keyboard_state[0] ^ state[0])
{ {
unsigned char pressed = ~keyboard_state[0] & state[0]; uint8_t pressed = ~keyboard_state[0] & state[0];
unsigned char released = keyboard_state[0] & ~state[0]; uint8_t released = keyboard_state[0] & ~state[0];
if(pressed & 1) push_press(KEY_AC_ON); if(pressed & 1) push_press(KEY_AC_ON);
if(released & 1) push_release(KEY_AC_ON); if(released & 1) push_release(KEY_AC_ON);
@ -71,19 +80,22 @@ void keyboard_interrupt(void)
for(int row = 1; row <= 9; row++) for(int row = 1; row <= 9; row++)
{ {
unsigned char pressed = ~keyboard_state[row] & state[row]; uint8_t pressed = ~keyboard_state[row] & state[row];
unsigned char released = keyboard_state[row] & ~state[row]; uint8_t repeated = keyboard_state[row] & state[row];
uint8_t released = keyboard_state[row] & ~state[row];
keyboard_state[row] = state[row]; keyboard_state[row] = state[row];
// Fasten this a bit. // Fasten this a bit.
if(!pressed && !released) continue; if(!(pressed | repeated | released)) continue;
for(int column = 0; column < 8; column++) for(int column = 0; column < 8; column++)
{ {
if(pressed & 1) push_press ((column << 4) | row); if(pressed & 1) push_press ((column << 4) | row);
if(repeated & 1) push_repeat ((column << 4) | row);
if(released & 1) push_release((column << 4) | row); if(released & 1) push_release((column << 4) | row);
pressed >>= 1; pressed >>= 1;
repeated >>= 1;
released >>= 1; released >>= 1;
} }
} }
@ -95,7 +107,7 @@ void keyboard_interrupt(void)
keyboard_init() keyboard_init()
Starts the keyboard timer. Starts the keyboard timer.
*/ */
void keyboard_init(void) __attribute__((constructor)) void keyboard_init(void)
{ {
cb_id = rtc_cb_add(RTCFreq_16Hz, keyboard_interrupt, 0); cb_id = rtc_cb_add(RTCFreq_16Hz, keyboard_interrupt, 0);
} }
@ -114,7 +126,7 @@ void keyboard_setFrequency(enum KeyboardFrequency frequency)
keyboard_quit() keyboard_quit()
Stops the keyboard timer. Stops the keyboard timer.
*/ */
void keyboard_quit(void) __attribute__((destructor)) void keyboard_quit(void)
{ {
rtc_cb_end(cb_id); rtc_cb_end(cb_id);
} }

View file

@ -19,7 +19,7 @@ int keylast(int *repeat_count)
Returns the address of the keyboard state array. The returned address Returns the address of the keyboard state array. The returned address
is the handler's buffer, therefore it contains volatile data. is the handler's buffer, therefore it contains volatile data.
*/ */
volatile unsigned char *keystate(void) volatile uint8_t *keystate(void)
{ {
return keyboard_state; return keyboard_state;
} }

View file

@ -136,7 +136,7 @@ static int krow(int row)
keyboard_updateState() keyboard_updateState()
Updates the keyboard state. Updates the keyboard state.
*/ */
void keyboard_updateState_7305(volatile unsigned char *keyboard_state) void keyboard_updateState_7305(volatile uint8_t *keyboard_state)
{ {
for(int i = 0; i < 10; i++) keyboard_state[i] = krow(i); for(int i = 0; i < 10; i++) keyboard_state[i] = krow(i);
} }

View file

@ -129,7 +129,7 @@ static int krow(int row)
keyboard_updateState() keyboard_updateState()
Updates the keyboard state. Updates the keyboard state.
*/ */
void keyboard_updateState_7705(volatile unsigned char *keyboard_state) void keyboard_updateState_7705(volatile uint8_t *keyboard_state)
{ {
for(int i = 0; i < 10; i++) keyboard_state[i] = krow(i); for(int i = 0; i < 10; i++) keyboard_state[i] = krow(i);
} }

View file

@ -1,5 +1,6 @@
#include <keyboard.h> #include <keyboard.h>
#include <internals/keyboard.h> #include <internals/keyboard.h>
#include <events.h>
/* /*
multigetkey() multigetkey()
@ -12,23 +13,28 @@
Setting count = 3 is generally safe. Setting count = 3 is generally safe.
The function returns after 'max_cycles' if no key is pressed. The function returns after 'max_cycles' if no key is pressed.
*/ */
void multigetkey(int *keys, int count, int max_cycles) static void multigetkey_wait(int *cycles)
{ {
int number; while(!interrupt_flag) sleep();
interrupt_flag = 0;
if(!max_cycles) max_cycles = -1; if(*cycles > 0) (*cycles)--;
}
void multigetkey(int *keys, int count, int cycles)
{
event_t event;
int number = 0;
while(max_cycles != 0) if(count <= 0) return;
if(cycles <= 0) cycles = -1;
while(cycles != 0)
{ {
while(!interrupt_flag) sleep();
interrupt_flag = 0;
if(max_cycles > 0) max_cycles--;
number = getPressedKeys(keyboard_state, keys, count); number = getPressedKeys(keyboard_state, keys, count);
// We need to update the last key data, in case multigetkey() // We want to update the last key data when multigetkey()
// returns a single key, and getkey() is called a short time // returns a single key, because getkey() could be called a
// after. Otherwise getkey() could re-send an event for this // short time after we return, and send a new event for this
// key. // key.
if(number == 1) if(number == 1)
{ {
@ -37,10 +43,12 @@ void multigetkey(int *keys, int count, int max_cycles)
last_events = 0; last_events = 0;
} }
if(number) return; if(number) break;
multigetkey_wait(&cycles);
} }
// When no key was pressed during the given delay... (no need to fill do event = pollevent();
// the array, it has already been done by getPressedKeys()). while(event.type != ET_None);
return; return;
} }

View file

@ -3,7 +3,11 @@
#include <stddef.h> #include <stddef.h>
struct Timer timers[3] = { { NULL, 0 }, { NULL, 0 }, { NULL, 0 } }; struct Timer timers[3] = {
{ .callback = NULL, .data = NULL, .repeats = 0 },
{ .callback = NULL, .data = NULL, .repeats = 0 },
{ .callback = NULL, .data = NULL, .repeats = 0 },
};
/* /*
timer_interrupt() timer_interrupt()
@ -15,7 +19,20 @@ void timer_interrupt(int timer)
timer_get(timer, &tmu, NULL); timer_get(timer, &tmu, NULL);
tmu->TCR.UNF = 0; tmu->TCR.UNF = 0;
if(timers[timer].callback) timers[timer].callback();
if(timers[timer].callback)
{
if(timers[timer].data)
{
void (*fun)(void *data) = timers[timer].callback;
fun(timers[timer].data);
}
else
{
void (*fun)(void) = timers[timer].callback;
fun();
}
}
// Reducing the number of repetitions left, if not infinite. // Reducing the number of repetitions left, if not infinite.
if(!timers[timer].repeats) return; if(!timers[timer].repeats) return;

View file

@ -5,8 +5,8 @@
timer_start2() timer_start2()
Configures and starts a time using a clock count and a prescaler. Configures and starts a time using a clock count and a prescaler.
*/ */
void timer_start2(int timer, int delay, int prescaler, void (*callback)(void), void timer_start2(int timer, int delay, int prescaler, void *callback,
int repeats) void *data, int repeats)
{ {
volatile struct mod_tmu *tmu; volatile struct mod_tmu *tmu;
volatile unsigned char *tstr; volatile unsigned char *tstr;
@ -27,8 +27,9 @@ void timer_start2(int timer, int delay, int prescaler, void (*callback)(void),
tmu->TCR.CKEG = 0; tmu->TCR.CKEG = 0;
// Loading the structure information. // Loading the structure information.
timers[timer].callback = callback; timers[timer].callback = callback;
timers[timer].repeats = repeats; timers[timer].data = data;
timers[timer].repeats = repeats;
// Starting the timer. // Starting the timer.
*tstr |= byte; *tstr |= byte;
@ -39,9 +40,9 @@ void timer_start2(int timer, int delay, int prescaler, void (*callback)(void),
Configures and starts a timer using a delay, or a frequency, and the Configures and starts a timer using a delay, or a frequency, and the
associated unit. associated unit.
*/ */
void timer_start(int timer, int delay, enum ClockUnit unit, void timer_start(int timer, int delay, enum ClockUnit unit, void *callback,
void (*callback)(void), int repeats) void *data, int repeats)
{ {
timer_start2(timer, clock_setting(delay, unit), TIMER_Po_4, callback, timer_start2(timer, clock_setting(delay, unit), TIMER_Po_4, callback,
repeats); data, repeats);
} }