mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 04:23:36 +01:00
Key repeat events & Timer callbacks with arguments. Fixed sleep_us().
This commit is contained in:
parent
4d0794f899
commit
0a694a1cd8
25 changed files with 264 additions and 189 deletions
19
TODO
19
TODO
|
@ -9,22 +9,21 @@ Simple improvements:
|
|||
- demo: Try 284x124 at (-60, -28) (all disadvantages)
|
||||
- display: Rectangle-based drawing functions
|
||||
- time: Compute CLOCKS_PER_SEC
|
||||
- events: Introduce KeyRepeat events
|
||||
- string: Use cmp/str to implement memchr() (assembler examples)
|
||||
- string: Do some tests for memcmp()
|
||||
- core: Register more interrupts (and understand their parameters)
|
||||
- rtc: Take care of carry when reading time
|
||||
- core: Register more interrupts (and understand their parameters)
|
||||
- rtc: Take care of carry when reading time
|
||||
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: Handle partial transparency
|
||||
- core: Implement all callbacks and a complete user API
|
||||
* core: Better save registers
|
||||
* core: Allow return to menu
|
||||
- serial: Implement a driver
|
||||
- usb: Implement a driver
|
||||
- esper: Cleaner playback, synthetizing
|
||||
- clock: Handle overclocking (relaunch clocks when overclocking)
|
||||
* core: Better save registers
|
||||
* core: Allow return to menu
|
||||
- serial: Implement a driver
|
||||
- usb: Implement a driver
|
||||
- esper: Cleaner playback, synthetizing
|
||||
- clock: Handle overclocking (relaunch clocks when overclocking)
|
||||
|
||||
Things to investigate:
|
||||
- Packed bit fields alignment
|
||||
|
|
|
@ -300,7 +300,7 @@ void main_menu(int *category, int *app)
|
|||
};
|
||||
|
||||
const char *list_tests[] = {
|
||||
"Keyboard",
|
||||
"Keyboard and events",
|
||||
"Gray engine",
|
||||
"Image rendering",
|
||||
"Text rendering",
|
||||
|
@ -495,6 +495,8 @@ int main(void)
|
|||
{
|
||||
int category, app;
|
||||
|
||||
sleep_ms(2000);
|
||||
|
||||
while(1)
|
||||
{
|
||||
main_menu(&category, &app);
|
||||
|
@ -502,7 +504,7 @@ int main(void)
|
|||
|
||||
switch((category << 8) | app)
|
||||
{
|
||||
case 0x0101: test_keyboard(); break;
|
||||
case 0x0101: test_keyboard_events(); break;
|
||||
case 0x0102: test_gray(); break;
|
||||
case 0x0103: test_bopti(); break;
|
||||
case 0x0104: test_tales(); break;
|
||||
|
|
|
@ -46,10 +46,10 @@ void print(int x, int y, const char *format, ...);
|
|||
//---
|
||||
|
||||
/*
|
||||
test_keyboard()
|
||||
Displays a real-time multigetkey() and the keyboard state.
|
||||
test_keyboard_events()
|
||||
Real-time keyboard management with events.
|
||||
*/
|
||||
void test_keyboard(void);
|
||||
void test_keyboard_events(void);
|
||||
|
||||
/*
|
||||
test_gray()
|
||||
|
|
|
@ -2,13 +2,9 @@
|
|||
#include <display.h>
|
||||
#include <keyboard.h>
|
||||
#include <stdlib.h>
|
||||
#include <events.h>
|
||||
|
||||
/*
|
||||
test_keyboard()
|
||||
Displays a real-time multigetkey() and the keyboard state.
|
||||
*/
|
||||
|
||||
static void draw(volatile unsigned char *state)
|
||||
static void draw_keyboard(volatile uint8_t *state)
|
||||
{
|
||||
int i, j, k, l;
|
||||
int x, y;
|
||||
|
@ -22,12 +18,16 @@ static void draw(volatile unsigned char *state)
|
|||
if(i == 4 && j == 5) continue;
|
||||
|
||||
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.
|
||||
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.
|
||||
if(state[i] & (128 >> j))
|
||||
if(state[i] & (0x80 >> j))
|
||||
{
|
||||
for(k = -2; k <= 2; k++) for(l = -2; l <= 2; l++)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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[] = {
|
||||
"F1", "F2", "F3", "F4", "F5", "F6",
|
||||
|
@ -55,28 +101,41 @@ void test_keyboard(void)
|
|||
"1", "2", "3", "+", "-", NULL,
|
||||
"0", ".", "\x08", "(-)", "EXE", NULL
|
||||
};
|
||||
const char *event_names[] = {
|
||||
"None ", "User ", "Press", "Rept.", "Rel. "
|
||||
};
|
||||
|
||||
volatile unsigned char *state = keystate();
|
||||
int keys[4] = { 0 };
|
||||
int i;
|
||||
for(int i = 0; i < size && history[i].type != ET_None; 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)
|
||||
{
|
||||
dclear();
|
||||
locate(1, 1, "Keyboard driver");
|
||||
locate(8, 3, "Pressed keys:");
|
||||
draw(state);
|
||||
|
||||
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])]);
|
||||
}
|
||||
|
||||
locate(1, 1, "Keyboard and events");
|
||||
draw_keyboard(keystate());
|
||||
draw_events(history, history_size);
|
||||
dupdate();
|
||||
|
||||
multigetkey(keys, 4, 1);
|
||||
if(keys[0] == KEY_EXIT && keys[1] == KEY_NONE) break;
|
||||
event = waitevent();
|
||||
if(event.type == ET_KeyPress && event.key == KEY_EXIT) break;
|
||||
push_history(history, history_size, event);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ static void timing_timer(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);
|
||||
|
||||
elapsed_timer = 0;
|
||||
|
|
|
@ -9,15 +9,11 @@
|
|||
#ifndef _EVENTS_H
|
||||
#define _EVENTS_H
|
||||
|
||||
//---
|
||||
// Type definitions.
|
||||
//---
|
||||
|
||||
/*
|
||||
enum EventType
|
||||
event_type_t
|
||||
Something user programs will surely use most often.
|
||||
*/
|
||||
enum EventType
|
||||
typedef enum
|
||||
{
|
||||
EventType_None = 0,
|
||||
ET_None = EventType_None,
|
||||
|
@ -28,27 +24,32 @@ enum EventType
|
|||
EventType_KeyPressed = 2,
|
||||
ET_KeyPress = EventType_KeyPressed,
|
||||
|
||||
EventType_KeyReleased = 3,
|
||||
EventType_KeyRepeated = 3,
|
||||
ET_KeyRepeat = EventType_KeyRepeated,
|
||||
|
||||
EventType_KeyReleased = 4,
|
||||
ET_KeyRel = EventType_KeyReleased,
|
||||
};
|
||||
|
||||
} event_type_t;
|
||||
|
||||
/*
|
||||
struct Event
|
||||
event_t
|
||||
Wake up, something's going on. The union member that holds information
|
||||
about the event is implicitly defined by the type attribute.
|
||||
*/
|
||||
struct Event
|
||||
typedef struct
|
||||
{
|
||||
enum EventType type;
|
||||
event_type_t type;
|
||||
|
||||
union
|
||||
{
|
||||
// For ET_User.
|
||||
void *data;
|
||||
// For ET_KeyPress and ET_KeyRel.
|
||||
// For ET_KeyPress, ET_KeyRepeat and ET_KeyRel.
|
||||
int key;
|
||||
};
|
||||
};
|
||||
|
||||
} event_t;
|
||||
|
||||
|
||||
|
||||
|
@ -64,21 +65,21 @@ struct Event
|
|||
allowed.
|
||||
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
|
||||
happen. This function uses low-level sleep and should be preferred to
|
||||
active waiting using loops.
|
||||
*/
|
||||
struct Event getevent(void);
|
||||
event_t waitevent(void);
|
||||
|
||||
/*
|
||||
pollevent()
|
||||
Returns the next event. If no one is available, returns an event whose
|
||||
type is ET_None. This function always returns immediately.
|
||||
*/
|
||||
struct Event pollevent(void);
|
||||
event_t pollevent(void);
|
||||
|
||||
#endif // _EVENTS_H
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
like any other queue. Trying to add an event when the queue is full
|
||||
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_size;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <clock.h>
|
||||
|
||||
// Keyboard variables.
|
||||
extern volatile unsigned char keyboard_state[10];
|
||||
extern volatile uint8_t keyboard_state[10];
|
||||
extern volatile int interrupt_flag;
|
||||
|
||||
// Key statistics.
|
||||
|
@ -19,7 +19,7 @@ extern unsigned cb_id;
|
|||
getPressedKey()
|
||||
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()
|
||||
|
@ -28,7 +28,13 @@ int getPressedKey(volatile unsigned char *keyboard_state);
|
|||
WARNING: keyboard artifacts make this function read as pressed keys
|
||||
that aren't (typically, LEFT + DOWN + SHIFT => ALPHA).
|
||||
*/
|
||||
int getPressedKeys(volatile unsigned char *keyboard_state, int *keys,
|
||||
int count);
|
||||
int getPressedKeys(volatile uint8_t *keyboard_state, int *keys, 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
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
*/
|
||||
struct Timer
|
||||
{
|
||||
void (*callback)(void);
|
||||
void *callback;
|
||||
void *data;
|
||||
int repeats;
|
||||
};
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#ifndef _KEYBOARD_H
|
||||
#define _KEYBOARD_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rtc.h>
|
||||
|
||||
//---
|
||||
|
@ -232,7 +233,7 @@ int keylast(int *repeat_count);
|
|||
functions, but the buffer data is very volatile. Therefore, data
|
||||
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);
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// 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
|
||||
|
|
|
@ -48,17 +48,22 @@
|
|||
not running the gray engine.
|
||||
Unit names are defined in the clock.h header and must be one of the
|
||||
following:
|
||||
- Clock_us (microseconds)
|
||||
- Clock_ms (milliseconds)
|
||||
- Clock_s (seconds)
|
||||
- Clock_Hz (hertz)
|
||||
- Clock_kHz (kilohertz)
|
||||
- Clock_MHz (megahertz)
|
||||
- Clock_us (microseconds)
|
||||
- Clock_ms (milliseconds)
|
||||
- Clock_s (seconds)
|
||||
- Clock_Hz (hertz)
|
||||
- Clock_kHz (kilohertz)
|
||||
- Clock_MHz (megahertz)
|
||||
The number of repeats may to set to 0. In this case, the timer will not
|
||||
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 (*callback)(void), int repeats);
|
||||
void *callback, void *data, int repeats);
|
||||
|
||||
/*
|
||||
timer_start2()
|
||||
|
@ -71,8 +76,8 @@ void timer_start(int timer, int delay_or_frequency, enum ClockUnit unit,
|
|||
- TIMER_Po_256
|
||||
- TIMER_TCLK
|
||||
*/
|
||||
void timer_start2(int timer, int delay, int prescaler, void (*callback)(void),
|
||||
int repeats);
|
||||
void timer_start2(int timer, int delay, int prescaler, void *callback,
|
||||
void *data, int repeats);
|
||||
|
||||
/*
|
||||
timer_stop()
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <rtc.h>
|
||||
#include <stddef.h>
|
||||
#include <mpu.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static clock_config_t conf = {
|
||||
.FLL = -1, .PLL = -1,
|
||||
|
@ -21,27 +22,36 @@ static clock_config_t conf = {
|
|||
int clock_setting(int duration, enum ClockUnit unit)
|
||||
{
|
||||
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)
|
||||
{
|
||||
case Clock_us:
|
||||
return (duration * f) / 1000000;
|
||||
result = (duration * f) / 1000000;
|
||||
break;
|
||||
case Clock_ms:
|
||||
return (duration * f) / 1000;
|
||||
result = (duration * f) / 1000;
|
||||
break;
|
||||
case Clock_s:
|
||||
return (duration * f);
|
||||
result = (duration * f);
|
||||
break;
|
||||
|
||||
case Clock_Hz:
|
||||
return f / duration;
|
||||
result = f / duration;
|
||||
break;
|
||||
case Clock_kHz:
|
||||
return f / (duration * 1000);
|
||||
result = f / (duration * 1000);
|
||||
break;
|
||||
case Clock_MHz:
|
||||
return f / (duration * 1000000);
|
||||
result = f / (duration * 1000000);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (result > 0xffffffff) ? (0xffffffff) : (result);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -60,7 +70,7 @@ clock_config_t clock_config(void)
|
|||
void sleep(void)
|
||||
{
|
||||
__asm__(
|
||||
"sleep\n\t"
|
||||
"sleep"
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -71,10 +81,9 @@ void sleep(void)
|
|||
than requested.
|
||||
*/
|
||||
|
||||
static volatile int sleep_done = 0;
|
||||
static void sleep_callback(void)
|
||||
static void sleep_callback(void *flag)
|
||||
{
|
||||
sleep_done = 1;
|
||||
*((int *)flag) = 1;
|
||||
}
|
||||
|
||||
void sleep_ms(int ms_delay)
|
||||
|
@ -83,8 +92,10 @@ void sleep_ms(int ms_delay)
|
|||
}
|
||||
void sleep_us(int us_delay)
|
||||
{
|
||||
sleep_done = 0;
|
||||
timer_start(TIMER_USER, us_delay, Clock_us, sleep_callback, 1);
|
||||
volatile int sleep_done = 0;
|
||||
timer_start(TIMER_USER, us_delay, Clock_us, sleep_callback,
|
||||
(void *)&sleep_done, 1);
|
||||
|
||||
do sleep();
|
||||
while(!sleep_done);
|
||||
}
|
||||
|
@ -133,6 +144,7 @@ void clock_measure(void)
|
|||
tmu->TCR.CKEG = 0;
|
||||
|
||||
timers[TIMER_USER].callback = NULL;
|
||||
timers[TIMER_USER].data = NULL;
|
||||
timers[TIMER_USER].repeats = 0;
|
||||
|
||||
cb_id_7705 = rtc_cb_add(RTCFreq_256Hz, clock_measure_7705, 0);
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
Returns the next event. If no one is available, returns an event whose
|
||||
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
|
||||
};
|
||||
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
|
||||
happen. This function uses low-level sleep and should be preferred to
|
||||
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();
|
||||
return event;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <internals/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_size = 0;
|
||||
|
||||
|
@ -11,7 +11,7 @@ volatile int queue_size = 0;
|
|||
or pollevent() later. Pushing ET_None events is not allowed.
|
||||
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(event.type == ET_None) return 2;
|
||||
|
|
|
@ -68,7 +68,8 @@ void gray_start(void)
|
|||
{
|
||||
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;
|
||||
runs = 1;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
getPressedKey()
|
||||
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 state;
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
Find 'count' pressed keys in the keyboard state and fills the 'keys'
|
||||
array. Returns the number of actually-pressed keys found.
|
||||
*/
|
||||
int getPressedKeys(volatile unsigned char *keyboard_state, int *keys,
|
||||
int count)
|
||||
int getPressedKeys(volatile uint8_t *keyboard_state, int *keys, int count)
|
||||
{
|
||||
int row = 1, column;
|
||||
int found = 0, actually_pressed;
|
||||
|
|
|
@ -25,7 +25,7 @@ int getkey(void)
|
|||
If max_cycles is non-zero and positive, getkey_opt() will return
|
||||
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();
|
||||
interrupt_flag = 0;
|
||||
|
@ -34,7 +34,7 @@ void getkey_opt_wait(int *cycles)
|
|||
}
|
||||
int getkey_opt(enum GetkeyOpt options, int cycles)
|
||||
{
|
||||
struct Event event;
|
||||
event_t event;
|
||||
int modifier = 0;
|
||||
static int event_ref = 0;
|
||||
|
||||
|
@ -120,19 +120,3 @@ int getkey_opt(enum GetkeyOpt options, int cycles)
|
|||
event_ref = 0;
|
||||
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;
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//---
|
||||
|
||||
// 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;
|
||||
|
||||
// Key statistics.
|
||||
|
@ -28,16 +28,25 @@ unsigned cb_id;
|
|||
|
||||
static void push_press(int keycode)
|
||||
{
|
||||
struct Event event = {
|
||||
event_t event = {
|
||||
.type = ET_KeyPress,
|
||||
.key = keycode,
|
||||
};
|
||||
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)
|
||||
{
|
||||
struct Event event = {
|
||||
event_t event = {
|
||||
.type = ET_KeyRel,
|
||||
.key = keycode,
|
||||
};
|
||||
|
@ -51,7 +60,7 @@ static void push_release(int keycode)
|
|||
*/
|
||||
void keyboard_interrupt(void)
|
||||
{
|
||||
unsigned char state[10] = { 0 };
|
||||
uint8_t state[10] = { 0 };
|
||||
|
||||
isSH3() ? keyboard_updateState_7705(state)
|
||||
: keyboard_updateState_7305(state)
|
||||
|
@ -61,8 +70,8 @@ void keyboard_interrupt(void)
|
|||
// AC/ON.
|
||||
if(keyboard_state[0] ^ state[0])
|
||||
{
|
||||
unsigned char pressed = ~keyboard_state[0] & state[0];
|
||||
unsigned char released = keyboard_state[0] & ~state[0];
|
||||
uint8_t pressed = ~keyboard_state[0] & state[0];
|
||||
uint8_t released = keyboard_state[0] & ~state[0];
|
||||
|
||||
if(pressed & 1) push_press(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++)
|
||||
{
|
||||
unsigned char pressed = ~keyboard_state[row] & state[row];
|
||||
unsigned char released = keyboard_state[row] & ~state[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];
|
||||
keyboard_state[row] = state[row];
|
||||
|
||||
// Fasten this a bit.
|
||||
if(!pressed && !released) continue;
|
||||
if(!(pressed | repeated | released)) continue;
|
||||
|
||||
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);
|
||||
|
||||
pressed >>= 1;
|
||||
pressed >>= 1;
|
||||
repeated >>= 1;
|
||||
released >>= 1;
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +107,7 @@ void keyboard_interrupt(void)
|
|||
keyboard_init()
|
||||
Starts the keyboard timer.
|
||||
*/
|
||||
void keyboard_init(void)
|
||||
__attribute__((constructor)) void keyboard_init(void)
|
||||
{
|
||||
cb_id = rtc_cb_add(RTCFreq_16Hz, keyboard_interrupt, 0);
|
||||
}
|
||||
|
@ -114,7 +126,7 @@ void keyboard_setFrequency(enum KeyboardFrequency frequency)
|
|||
keyboard_quit()
|
||||
Stops the keyboard timer.
|
||||
*/
|
||||
void keyboard_quit(void)
|
||||
__attribute__((destructor)) void keyboard_quit(void)
|
||||
{
|
||||
rtc_cb_end(cb_id);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ int keylast(int *repeat_count)
|
|||
Returns the address of the keyboard state array. The returned address
|
||||
is the handler's buffer, therefore it contains volatile data.
|
||||
*/
|
||||
volatile unsigned char *keystate(void)
|
||||
volatile uint8_t *keystate(void)
|
||||
{
|
||||
return keyboard_state;
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ static int krow(int row)
|
|||
keyboard_updateState()
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ static int krow(int row)
|
|||
keyboard_updateState()
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <keyboard.h>
|
||||
#include <internals/keyboard.h>
|
||||
#include <events.h>
|
||||
|
||||
/*
|
||||
multigetkey()
|
||||
|
@ -12,23 +13,28 @@
|
|||
Setting count = 3 is generally safe.
|
||||
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);
|
||||
|
||||
// We need to update the last key data, in case multigetkey()
|
||||
// returns a single key, and getkey() is called a short time
|
||||
// after. Otherwise getkey() could re-send an event for this
|
||||
// We want to update the last key data when multigetkey()
|
||||
// returns a single key, because getkey() could be called a
|
||||
// short time after we return, and send a new event for this
|
||||
// key.
|
||||
if(number == 1)
|
||||
{
|
||||
|
@ -37,10 +43,12 @@ void multigetkey(int *keys, int count, int max_cycles)
|
|||
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
|
||||
// the array, it has already been done by getPressedKeys()).
|
||||
do event = pollevent();
|
||||
while(event.type != ET_None);
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
|
||||
#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()
|
||||
|
@ -15,7 +19,20 @@ void timer_interrupt(int timer)
|
|||
timer_get(timer, &tmu, NULL);
|
||||
|
||||
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.
|
||||
if(!timers[timer].repeats) return;
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
timer_start2()
|
||||
Configures and starts a time using a clock count and a prescaler.
|
||||
*/
|
||||
void timer_start2(int timer, int delay, int prescaler, void (*callback)(void),
|
||||
int repeats)
|
||||
void timer_start2(int timer, int delay, int prescaler, void *callback,
|
||||
void *data, int repeats)
|
||||
{
|
||||
volatile struct mod_tmu *tmu;
|
||||
volatile unsigned char *tstr;
|
||||
|
@ -27,8 +27,9 @@ void timer_start2(int timer, int delay, int prescaler, void (*callback)(void),
|
|||
tmu->TCR.CKEG = 0;
|
||||
|
||||
// Loading the structure information.
|
||||
timers[timer].callback = callback;
|
||||
timers[timer].repeats = repeats;
|
||||
timers[timer].callback = callback;
|
||||
timers[timer].data = data;
|
||||
timers[timer].repeats = repeats;
|
||||
|
||||
// Starting the timer.
|
||||
*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
|
||||
associated unit.
|
||||
*/
|
||||
void timer_start(int timer, int delay, enum ClockUnit unit,
|
||||
void (*callback)(void), int repeats)
|
||||
void timer_start(int timer, int delay, enum ClockUnit unit, void *callback,
|
||||
void *data, int repeats)
|
||||
{
|
||||
timer_start2(timer, clock_setting(delay, unit), TIMER_Po_4, callback,
|
||||
repeats);
|
||||
data, repeats);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue