mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 20:43:36 +01:00
Some quality review. Made keyboard time milliseconds.
This commit is contained in:
parent
39fedcd271
commit
c8170b165a
79 changed files with 1482 additions and 1175 deletions
2
Makefile
2
Makefile
|
@ -13,7 +13,7 @@ include Makefile.cfg
|
||||||
# Modules
|
# Modules
|
||||||
modules-gint = bopti clock core display events gray keyboard mmu rtc \
|
modules-gint = bopti clock core display events gray keyboard mmu rtc \
|
||||||
screen tales timer
|
screen tales timer
|
||||||
modules-libc = setjmp stdio stdlib string time
|
modules-libc = ctype setjmp stdio stdlib string time
|
||||||
|
|
||||||
# Targets
|
# Targets
|
||||||
target-lib = libgint.a
|
target-lib = libgint.a
|
||||||
|
|
4
TODO
4
TODO
|
@ -23,8 +23,8 @@ Larger improvements:
|
||||||
* 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, synthesizing
|
||||||
- clock: Handle overclocking (relaunch clocks when overclocking)
|
- clock: Handle overclock (relaunch clocks when overclocking)
|
||||||
- project: Unify this hellish mess of register access!
|
- project: Unify this hellish mess of register access!
|
||||||
|
|
||||||
Things to investigate:
|
Things to investigate:
|
||||||
|
|
|
@ -288,7 +288,7 @@ void main_menu(int *category, int *app)
|
||||||
// Quite a few things to declare...
|
// Quite a few things to declare...
|
||||||
//---
|
//---
|
||||||
|
|
||||||
extern Image res_opt_menu;
|
extern image_t res_opt_menu;
|
||||||
|
|
||||||
const char *mpu, *mpu_names[] = {
|
const char *mpu, *mpu_names[] = {
|
||||||
"Unknown",
|
"Unknown",
|
||||||
|
@ -332,7 +332,7 @@ void main_menu(int *category, int *app)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
mpu = mpu_names[MPU_CURRENT < 5 ? MPU_CURRENT : 5];
|
mpu = mpu_names[MPU_CURRENT < 5 ? MPU_CURRENT : 5];
|
||||||
text_configure(NULL, Color_Black);
|
text_configure(NULL, color_black);
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
|
@ -386,8 +386,8 @@ void main_menu(int *category, int *app)
|
||||||
if(scroll > 0) locate(20, 2, "\x0d");
|
if(scroll > 0) locate(20, 2, "\x0d");
|
||||||
if(scroll + 6 < list_len) locate(20, 7, "\x0e");
|
if(scroll + 6 < list_len) locate(20, 7, "\x0e");
|
||||||
|
|
||||||
dreverse_area(0, 8 * (index - scroll) + 8, 127,
|
drect(0, 8 * (index - scroll) + 8, 127,
|
||||||
8 * (index - scroll) + 15);
|
8 * (index - scroll) + 15, color_invert);
|
||||||
}
|
}
|
||||||
|
|
||||||
dupdate();
|
dupdate();
|
||||||
|
@ -495,8 +495,6 @@ int main(void)
|
||||||
{
|
{
|
||||||
int category, app;
|
int category, app;
|
||||||
|
|
||||||
sleep_ms(2000);
|
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
main_menu(&category, &app);
|
main_menu(&category, &app);
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
---------------------------------------------------------
|
---------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void getwh(Image *img, int *width, int *height)
|
static void getwh(image_t *img, int *width, int *height)
|
||||||
{
|
{
|
||||||
const uint8_t *data;
|
const uint8_t *data;
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ static void getwh(Image *img, int *width, int *height)
|
||||||
*height = (data[2] << 8) | data[3];
|
*height = (data[2] << 8) | data[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void getxy(Image *img, int *x, int *y)
|
static void getxy(image_t *img, int *x, int *y)
|
||||||
{
|
{
|
||||||
int width, height;
|
int width, height;
|
||||||
|
|
||||||
|
@ -51,10 +51,10 @@ static void getxy(Image *img, int *x, int *y)
|
||||||
*y = 28 - (height >> 1);
|
*y = 28 - (height >> 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Image *select(Image *current)
|
static image_t *select(image_t *current)
|
||||||
{
|
{
|
||||||
extern Image res_bopti_thumbs;
|
extern image_t res_bopti_thumbs;
|
||||||
extern Image
|
extern image_t
|
||||||
res_items,
|
res_items,
|
||||||
res_sprites,
|
res_sprites,
|
||||||
res_swords,
|
res_swords,
|
||||||
|
@ -62,7 +62,7 @@ static Image *select(Image *current)
|
||||||
res_isometric;
|
res_isometric;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Image *img;
|
image_t *img;
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *info;
|
const char *info;
|
||||||
} images[] = {
|
} images[] = {
|
||||||
|
@ -74,7 +74,7 @@ static Image *select(Image *current)
|
||||||
{ NULL, NULL, NULL }
|
{ NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
Image *thumbs = &res_bopti_thumbs;
|
image_t *thumbs = &res_bopti_thumbs;
|
||||||
int items = 0;
|
int items = 0;
|
||||||
static int row = 0;
|
static int row = 0;
|
||||||
int leave = 1, i;
|
int leave = 1, i;
|
||||||
|
@ -106,7 +106,7 @@ static Image *select(Image *current)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
greverse_area(0, 8 * row + 8, 128, 8 * row + 23);
|
grect(0, 8 * row + 8, 128, 8 * row + 23, color_invert);
|
||||||
gupdate();
|
gupdate();
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -138,8 +138,8 @@ static Image *select(Image *current)
|
||||||
|
|
||||||
void test_bopti(void)
|
void test_bopti(void)
|
||||||
{
|
{
|
||||||
extern Image res_opt_bitmap;
|
extern image_t res_opt_bitmap;
|
||||||
Image *img = NULL;
|
image_t *img = NULL;
|
||||||
|
|
||||||
int leave = 1;
|
int leave = 1;
|
||||||
int black_bg = 0;
|
int black_bg = 0;
|
||||||
|
@ -152,10 +152,10 @@ void test_bopti(void)
|
||||||
gray_start();
|
gray_start();
|
||||||
gclear();
|
gclear();
|
||||||
|
|
||||||
if(black_bg) greverse_area(0, 0, 127, 63);
|
if(black_bg) grect(0, 0, 127, 63, color_invert);
|
||||||
if(img) gimage(x, y, img);
|
if(img) gimage(x, y, img);
|
||||||
|
|
||||||
gclear_area(0, 55, 127, 63);
|
grect(0, 55, 127, 63, color_white);
|
||||||
gimage(0, 56, &res_opt_bitmap);
|
gimage(0, 56, &res_opt_bitmap);
|
||||||
gupdate();
|
gupdate();
|
||||||
}
|
}
|
||||||
|
@ -164,10 +164,10 @@ void test_bopti(void)
|
||||||
gray_stop();
|
gray_stop();
|
||||||
dclear();
|
dclear();
|
||||||
|
|
||||||
if(black_bg) dreverse_area(0, 0, 127, 63);
|
if(black_bg) drect(0, 0, 127, 63, color_invert);
|
||||||
if(img) dimage(x, y, img);
|
if(img) dimage(x, y, img);
|
||||||
|
|
||||||
dclear_area(0, 55, 127, 63);
|
drect(0, 55, 127, 63, color_white);
|
||||||
dimage(0, 56, &res_opt_bitmap);
|
dimage(0, 56, &res_opt_bitmap);
|
||||||
dupdate();
|
dupdate();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,9 @@
|
||||||
|
|
||||||
static void draw(int delay1, int delay2, int selected)
|
static void draw(int delay1, int delay2, int selected)
|
||||||
{
|
{
|
||||||
extern Image res_opt_gray;
|
extern image_t res_opt_gray;
|
||||||
unsigned int *vl = gray_lightVRAM();
|
uint32_t *vl = gray_lightVRAM();
|
||||||
unsigned int *vd = gray_darkVRAM();
|
uint32_t *vd = gray_darkVRAM();
|
||||||
|
|
||||||
gclear();
|
gclear();
|
||||||
locate(1, 1, "Gray engine");
|
locate(1, 1, "Gray engine");
|
||||||
|
@ -58,7 +58,7 @@ void test_gray(void)
|
||||||
}
|
}
|
||||||
changed = 0;
|
changed = 0;
|
||||||
|
|
||||||
key = getkey_opt(Getkey_RepeatArrowKeys, 1);
|
key = getkey_opt(getkey_repeat_arrow_keys, 25);
|
||||||
if(key == KEY_EXIT) break;
|
if(key == KEY_EXIT) break;
|
||||||
|
|
||||||
changed = 1;
|
changed = 1;
|
||||||
|
|
|
@ -31,24 +31,24 @@ static void draw_keyboard(volatile uint8_t *state)
|
||||||
{
|
{
|
||||||
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)
|
||||||
dpixel(x + k, y + l, Color_Black);
|
dpixel(x + k, y + l, color_black);
|
||||||
}
|
}
|
||||||
// Drawing a square border otherwise.
|
// Drawing a square border otherwise.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(k = -1; k <= 1; k++) for(l = -1; l <= 1; l++)
|
for(k = -1; k <= 1; k++) for(l = -1; l <= 1; l++)
|
||||||
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.
|
// Binding the arrow keys together for a more visual thing.
|
||||||
dpixel(28, 19, Color_Black); dpixel(29, 19, Color_Black);
|
dpixel(28, 19, color_black); dpixel(29, 19, color_black);
|
||||||
dpixel(28, 24, Color_Black); dpixel(29, 24, Color_Black);
|
dpixel(28, 24, color_black); dpixel(29, 24, color_black);
|
||||||
dpixel(26, 21, Color_Black); dpixel(26, 22, Color_Black);
|
dpixel(26, 21, color_black); dpixel(26, 22, color_black);
|
||||||
dpixel(31, 21, Color_Black); dpixel(31, 22, Color_Black);
|
dpixel(31, 21, color_black); dpixel(31, 22, color_black);
|
||||||
|
|
||||||
// An horizontal line to separate parts of the keyboard.
|
// An horizontal line to separate parts of the keyboard.
|
||||||
dline(5, 28, 32, 28, Color_Black);
|
dline(5, 28, 32, 28, color_black);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -64,7 +64,7 @@ static void push_history(enhanced_event_t *history, int size, event_t event)
|
||||||
|
|
||||||
// Determining where the history ends.
|
// Determining where the history ends.
|
||||||
int length = 0;
|
int length = 0;
|
||||||
while(length < size && history[length].type != ET_None) length++;
|
while(length < size && history[length].type != event_none) length++;
|
||||||
|
|
||||||
// Checking if the previous event is being repeated.
|
// Checking if the previous event is being repeated.
|
||||||
if(length > 0 && event_eq(history[length - 1], event))
|
if(length > 0 && event_eq(history[length - 1], event))
|
||||||
|
@ -105,10 +105,10 @@ static void draw_events(enhanced_event_t *history, int size)
|
||||||
"None ", "User ", "Press", "Rept.", "Rel. ", "Timer"
|
"None ", "User ", "Press", "Rept.", "Rel. ", "Timer"
|
||||||
};
|
};
|
||||||
|
|
||||||
for(int i = 0; i < size && history[i].type != ET_None; i++)
|
for(int i = 0; i < size && history[i].type != event_none; i++)
|
||||||
{
|
{
|
||||||
print(8, 3 + i, "%s %s", event_names[history[i].type],
|
print(8, 3 + i, "%s %s", event_names[history[i].type],
|
||||||
key_names[keyid(history[i].key)]);
|
key_names[key_id(history[i].key)]);
|
||||||
if(history[i].repeats > 1)
|
if(history[i].repeats > 1)
|
||||||
print(19, 3 + i, "%d", history[i].repeats);
|
print(19, 3 + i, "%d", history[i].repeats);
|
||||||
}
|
}
|
||||||
|
@ -124,18 +124,19 @@ void test_keyboard_events(void)
|
||||||
int history_size = 5;
|
int history_size = 5;
|
||||||
event_t event;
|
event_t event;
|
||||||
|
|
||||||
for(int i = 0; i < history_size; i++) history[i].type = ET_None;
|
for(int i = 0; i < history_size; i++) history[i].type = event_none;
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
dclear();
|
dclear();
|
||||||
locate(1, 1, "Keyboard and events");
|
locate(1, 1, "Keyboard and events");
|
||||||
draw_keyboard(keystate());
|
draw_keyboard(keyboard_stateBuffer());
|
||||||
draw_events(history, history_size);
|
draw_events(history, history_size);
|
||||||
dupdate();
|
dupdate();
|
||||||
|
|
||||||
event = waitevent();
|
event = waitevent();
|
||||||
if(event.type == ET_KeyPress && event.key == KEY_EXIT) break;
|
if(event.type == event_key_press && event.key == KEY_EXIT)
|
||||||
|
break;
|
||||||
push_history(history, history_size, event);
|
push_history(history, history_size, event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
static void draw(rtc_time_t time)
|
static void draw(rtc_time_t time)
|
||||||
{
|
{
|
||||||
extern Image res_rtc_segments;
|
extern image_t res_rtc_segments;
|
||||||
|
|
||||||
const char *days[7] = {
|
const char *days[7] = {
|
||||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||||
|
@ -42,7 +42,7 @@ static void draw(rtc_time_t time)
|
||||||
12 * digits[i], 0, 11, 19);
|
12 * digits[i], 0, 11, 19);
|
||||||
// Drawing ':' between pairs of digits.
|
// Drawing ':' between pairs of digits.
|
||||||
for(i = 0; i < 16; i++) dpixel(47 + 32 * (i >= 8) + (i & 1),
|
for(i = 0; i < 16; i++) dpixel(47 + 32 * (i >= 8) + (i & 1),
|
||||||
14 + 5 * !!(i & 4) + !!(i & 2), Color_Black);
|
14 + 5 * !!(i & 4) + !!(i & 2), color_black);
|
||||||
|
|
||||||
// This should print time.year + 1900 but for the sake of this demo we
|
// This should print time.year + 1900 but for the sake of this demo we
|
||||||
// have tweaked the field so that it already contains time.year + 1900.
|
// have tweaked the field so that it already contains time.year + 1900.
|
||||||
|
@ -52,7 +52,7 @@ static void draw(rtc_time_t time)
|
||||||
|
|
||||||
static void callback(void)
|
static void callback(void)
|
||||||
{
|
{
|
||||||
extern Image res_opt_rtc;
|
extern image_t res_opt_rtc;
|
||||||
rtc_time_t time = rtc_getTime();
|
rtc_time_t time = rtc_getTime();
|
||||||
|
|
||||||
dclear();
|
dclear();
|
||||||
|
@ -115,8 +115,8 @@ static void set_region(rtc_time_t *time, int region, int value)
|
||||||
|
|
||||||
static void set(void)
|
static void set(void)
|
||||||
{
|
{
|
||||||
extern Image res_opt_rtc;
|
extern image_t res_opt_rtc;
|
||||||
Image *opt = &res_opt_rtc;
|
image_t *opt = &res_opt_rtc;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int x, y;
|
int x, y;
|
||||||
|
@ -136,8 +136,8 @@ static void set(void)
|
||||||
{
|
{
|
||||||
dclear();
|
dclear();
|
||||||
draw(time);
|
draw(time);
|
||||||
dreverse_area(regions[n].x, regions[n].y, regions[n].x
|
drect(regions[n].x, regions[n].y, regions[n].x + regions[n].w
|
||||||
+ regions[n].w - 1, regions[n].y + regions[n].h - 1);
|
- 1, regions[n].y + regions[n].h - 1, color_invert);
|
||||||
|
|
||||||
if(n == 6) dimage_part(0, 56, opt, 0, 9 * (1 + slide), 128, 8);
|
if(n == 6) dimage_part(0, 56, opt, 0, 9 * (1 + slide), 128, 8);
|
||||||
if(n == 7) dimage_part(0, 56, opt, 0, 9 * (3 + slide), 128, 8);
|
if(n == 7) dimage_part(0, 56, opt, 0, 9 * (3 + slide), 128, 8);
|
||||||
|
@ -191,9 +191,9 @@ static void set(void)
|
||||||
else leave = 0;
|
else leave = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if(isdigit(keychar(key))) // Numbers
|
else if(isdigit(key_char(key))) // Numbers
|
||||||
{
|
{
|
||||||
int val = keychar(key) - '0';
|
int val = key_char(key) - '0';
|
||||||
int ok = 1;
|
int ok = 1;
|
||||||
|
|
||||||
if(n == 0) ok = (val <= 2);
|
if(n == 0) ok = (val <= 2);
|
||||||
|
|
|
@ -27,7 +27,7 @@ static Font *select(Font *current)
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
text_configure(NULL, Color_Black);
|
text_configure(NULL, color_black);
|
||||||
|
|
||||||
dclear();
|
dclear();
|
||||||
locate(1, 1, "Select a font:");
|
locate(1, 1, "Select a font:");
|
||||||
|
@ -39,18 +39,18 @@ static Font *select(Font *current)
|
||||||
int height = fonts[i].font->line_height;
|
int height = fonts[i].font->line_height;
|
||||||
int y = (i + 2) * 8 - 8 + ((7 - height) >> 1);
|
int y = (i + 2) * 8 - 8 + ((7 - height) >> 1);
|
||||||
|
|
||||||
text_configure(fonts[i].font, Color_Black);
|
text_configure(fonts[i].font, color_black);
|
||||||
dtext(7, y, fonts[i].name);
|
dtext(7, y, fonts[i].name);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
text_configure(NULL, Color_Black);
|
text_configure(NULL, color_black);
|
||||||
locate(2, i + 2, fonts[i].name);
|
locate(2, i + 2, fonts[i].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dreverse_area(0, 8 * row + 8, 128, 8 * row + 15);
|
drect(0, 8 * row + 8, 128, 8 * row + 15, color_invert);
|
||||||
dupdate();
|
dupdate();
|
||||||
|
|
||||||
do
|
do
|
||||||
|
@ -80,9 +80,9 @@ static Font *select(Font *current)
|
||||||
|
|
||||||
void test_tales(void)
|
void test_tales(void)
|
||||||
{
|
{
|
||||||
enum Color colors[] = { Color_Black, Color_Dark, Color_Light,
|
color_t colors[] = { color_black, color_dark, color_light, color_white,
|
||||||
Color_White, Color_Invert };
|
color_invert };
|
||||||
extern Image res_opt_tales;
|
extern image_t res_opt_tales;
|
||||||
Font *font = NULL;
|
Font *font = NULL;
|
||||||
|
|
||||||
int black_bg = 0;
|
int black_bg = 0;
|
||||||
|
@ -94,7 +94,7 @@ void test_tales(void)
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
gclear();
|
gclear();
|
||||||
if(black_bg) greverse_area(0, 0, 127, 54);
|
if(black_bg) grect(0, 0, 127, 54, color_invert);
|
||||||
|
|
||||||
if(font)
|
if(font)
|
||||||
{
|
{
|
||||||
|
@ -119,10 +119,10 @@ void test_tales(void)
|
||||||
gimage(0, 56, &res_opt_tales);
|
gimage(0, 56, &res_opt_tales);
|
||||||
|
|
||||||
x = 45 + 8 * color;
|
x = 45 + 8 * color;
|
||||||
gline(x, 57, x + 5, 57, Color_Black);
|
gline(x, 57, x + 5, 57, color_black);
|
||||||
gline(x, 57, x, 62, Color_Black);
|
gline(x, 57, x, 62, color_black);
|
||||||
gline(x + 5, 57, x + 5, 62, Color_Black);
|
gline(x + 5, 57, x + 5, 62, color_black);
|
||||||
gline(x, 62, x + 5, 62, Color_Black);
|
gline(x, 62, x + 5, 62, color_black);
|
||||||
|
|
||||||
gupdate();
|
gupdate();
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ void test_tales(void)
|
||||||
|
|
||||||
case KEY_EXIT:
|
case KEY_EXIT:
|
||||||
gray_stop();
|
gray_stop();
|
||||||
text_configure(NULL, Color_Black);
|
text_configure(NULL, color_black);
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
leave = 0;
|
leave = 0;
|
||||||
|
|
|
@ -36,7 +36,7 @@ static void timing_timer(void)
|
||||||
|
|
||||||
static void timing_start(void)
|
static void timing_start(void)
|
||||||
{
|
{
|
||||||
uint32_t delay = clock_setting(64, Clock_Hz);
|
uint32_t delay = clock_setting(64, clock_Hz);
|
||||||
htimer = htimer_setup(timer_user, delay, timer_Po_4, 0);
|
htimer = htimer_setup(timer_user, delay, timer_Po_4, 0);
|
||||||
timer_attach(htimer, timing_timer, NULL);
|
timer_attach(htimer, timing_timer, NULL);
|
||||||
timer_start(htimer);
|
timer_start(htimer);
|
||||||
|
@ -59,8 +59,8 @@ static void timing_start(void)
|
||||||
*/
|
*/
|
||||||
static void small_text(int x, int y, const char *text, int alignment)
|
static void small_text(int x, int y, const char *text, int alignment)
|
||||||
{
|
{
|
||||||
extern Image res_clock_chars;
|
extern image_t res_clock_chars;
|
||||||
Image *chars = &res_clock_chars;
|
image_t *chars = &res_clock_chars;
|
||||||
const char *table = "0123456789kMHz*/";
|
const char *table = "0123456789kMHz*/";
|
||||||
|
|
||||||
if(alignment) x -= 2 * strlen(text) - 1, y -= 2;
|
if(alignment) x -= 2 * strlen(text) - 1, y -= 2;
|
||||||
|
@ -133,9 +133,9 @@ static void display_freq(int x, int y, int freq)
|
||||||
*/
|
*/
|
||||||
static void draw(int tab)
|
static void draw(int tab)
|
||||||
{
|
{
|
||||||
extern Image res_opt_timer;
|
extern image_t res_opt_timer;
|
||||||
extern Image res_clock_7705;
|
extern image_t res_clock_7705;
|
||||||
extern Image res_clock_7305;
|
extern image_t res_clock_7305;
|
||||||
|
|
||||||
char buffer[16];
|
char buffer[16];
|
||||||
|
|
||||||
|
@ -163,14 +163,14 @@ static void draw(int tab)
|
||||||
small_text(84, 34, buffer, 1);
|
small_text(84, 34, buffer, 1);
|
||||||
|
|
||||||
if(conf.Iphi_div1 == 1)
|
if(conf.Iphi_div1 == 1)
|
||||||
dline(85, 43, 99, 43, Color_Black);
|
dline(85, 43, 99, 43, color_black);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf(buffer, "/%d", conf.Iphi_div1);
|
sprintf(buffer, "/%d", conf.Iphi_div1);
|
||||||
small_text(89, 41, buffer, 0);
|
small_text(89, 41, buffer, 0);
|
||||||
}
|
}
|
||||||
if(conf.Pphi_div1 == 1)
|
if(conf.Pphi_div1 == 1)
|
||||||
dline(85, 50, 99, 50, Color_Black);
|
dline(85, 50, 99, 50, color_black);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sprintf(buffer, "/%d", conf.Pphi_div1);
|
sprintf(buffer, "/%d", conf.Pphi_div1);
|
||||||
|
@ -249,13 +249,13 @@ void test_timer(void)
|
||||||
elapsed_rtc = -1;
|
elapsed_rtc = -1;
|
||||||
cb_id = rtc_cb_add(RTCFreq_64Hz, timing_start, 0);
|
cb_id = rtc_cb_add(RTCFreq_64Hz, timing_start, 0);
|
||||||
|
|
||||||
text_configure(NULL, Color_Black);
|
text_configure(NULL, color_black);
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
draw(tab);
|
draw(tab);
|
||||||
|
|
||||||
switch(getkey_opt(Getkey_NoOption, 1))
|
switch(getkey_opt(getkey_none, 25))
|
||||||
{
|
{
|
||||||
case KEY_EXIT:
|
case KEY_EXIT:
|
||||||
rtc_cb_end(cb_id);
|
rtc_cb_end(cb_id);
|
||||||
|
|
|
@ -3,12 +3,14 @@
|
||||||
// standard library module: alloca
|
// standard library module: alloca
|
||||||
//
|
//
|
||||||
// Allows dynamic memory allocation on the stack. Memory is automatically
|
// Allows dynamic memory allocation on the stack. Memory is automatically
|
||||||
// freed when the calling function exits.
|
// freed when the calling function exits, but this function suffers from
|
||||||
|
// risks of stack overflow; make sure you don't inline functions that use
|
||||||
|
// alloca or allocate more than a few hundred bytes with it.
|
||||||
//
|
//
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _ALLOCA_H
|
#ifndef _ALLOCA_H
|
||||||
#define _ALLOCA_H 1
|
#define _ALLOCA_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
67
include/bopti.h
Normal file
67
include/bopti.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
//---
|
||||||
|
//
|
||||||
|
// gint drawing module: bopti
|
||||||
|
//
|
||||||
|
// This module is a powerful bitmap renderer. It *heavily* relies on the
|
||||||
|
// line-based structure of the video RAM as well as the high density of
|
||||||
|
// information. A single CPU access (longword operation) can affect 32
|
||||||
|
// pixels at once, which is crucial for performance. The same goes for all
|
||||||
|
// other drawing modules, but this one typically has 350 lines of code
|
||||||
|
// just to wrap these longword accesses -- and it's blazingly fast.
|
||||||
|
//
|
||||||
|
//---
|
||||||
|
|
||||||
|
#ifndef _BOPTI_H
|
||||||
|
#define _BOPTI_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
image_t
|
||||||
|
This structure holds meta-data of a bitmap encoded with fxconv. Data is
|
||||||
|
accessed using longword operations for performance considerations,
|
||||||
|
which requires that the all fields of the structure be properly aligned
|
||||||
|
and of a correct size.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t magic;
|
||||||
|
uint8_t format;
|
||||||
|
|
||||||
|
uint8_t width;
|
||||||
|
uint8_t height;
|
||||||
|
|
||||||
|
const uint32_t data[];
|
||||||
|
|
||||||
|
} __attribute__((packed, aligned(4))) image_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
dimage()
|
||||||
|
Displays a monochrome image in the vram. This function does a real lot
|
||||||
|
of optimization.
|
||||||
|
*/
|
||||||
|
void dimage(int x, int y, image_t *image);
|
||||||
|
|
||||||
|
/*
|
||||||
|
dimage_part()
|
||||||
|
Draws a portion of an image, defined by its bounding rectangle.
|
||||||
|
Point (left, top) is included, but (left + width, top + height) is
|
||||||
|
excluded.
|
||||||
|
*/
|
||||||
|
void dimage_part(int x, int y, image_t *img, int left, int top, int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
|
/*
|
||||||
|
gimage()
|
||||||
|
Displays a gray image in the dual-vram.
|
||||||
|
*/
|
||||||
|
void gimage(int x, int y, image_t *image);
|
||||||
|
|
||||||
|
/*
|
||||||
|
gimage_part()
|
||||||
|
Draws a portion of a gray image, defined by its bounding rectangle.
|
||||||
|
Point (left, top) is included, but (left + width, top + height) is
|
||||||
|
excluded.
|
||||||
|
*/
|
||||||
|
void gimage_part(int x, int y, image_t *image, int left, int top, int width,
|
||||||
|
int height);
|
||||||
|
|
||||||
|
#endif // _BOPTI_H
|
|
@ -2,8 +2,14 @@
|
||||||
//
|
//
|
||||||
// gint core module: clock
|
// gint core module: clock
|
||||||
//
|
//
|
||||||
// Measures the frequency of the MPU clocks. This module assumes that the
|
// This module interfaces with the MPU clocks and is used to measure the
|
||||||
// clock mode is 3 on SH7305 (as does FTune).
|
// clock frequencies at the beginning of execution. At this stage, it
|
||||||
|
// assumes that clock mode 3 is used on SH7305 (as does FTune), because
|
||||||
|
// there doesn't seem to be a way of getting this information.
|
||||||
|
//
|
||||||
|
// It also provides some sleep and time conversion functions, and access
|
||||||
|
// to how the clocks are configured. In the future, it would be the module
|
||||||
|
// that supports overclock.
|
||||||
//
|
//
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
@ -18,7 +24,12 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
sleep()
|
sleep()
|
||||||
Puts the processor to sleep until an interrupt request is issued.
|
Puts the processor to sleep until an interrupt request is accepted.
|
||||||
|
This function should be called every time the program because idle
|
||||||
|
because it doesn't have anything to do -- between two game frames or
|
||||||
|
while waiting for a keyboard event.
|
||||||
|
This function is called by getkey_opt(), getkey(), waitevent(), this
|
||||||
|
module's sleep functions among others.
|
||||||
*/
|
*/
|
||||||
void sleep(void);
|
void sleep(void);
|
||||||
|
|
||||||
|
@ -41,17 +52,29 @@ void sleep_us(int us_delay);
|
||||||
// Clock management.
|
// Clock management.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
enum ClockUnit
|
/*
|
||||||
|
clock_unit_t
|
||||||
|
Enumerated type used by the time conversion functions. It indicates the
|
||||||
|
type (delay or frequency) of a parameter.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
{
|
{
|
||||||
Clock_us = 0,
|
clock_us = 0,
|
||||||
Clock_ms = 1,
|
clock_ms = 1,
|
||||||
Clock_s = 2,
|
clock_s = 2,
|
||||||
|
|
||||||
Clock_Hz = 10,
|
clock_Hz = 10,
|
||||||
Clock_kHz = 11,
|
clock_kHz = 11,
|
||||||
Clock_MHz = 12,
|
clock_MHz = 12,
|
||||||
};
|
|
||||||
|
|
||||||
|
} clock_unit_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
clock_config_t
|
||||||
|
A copy of the Clock Pulse Generator (CPG) configuration. Be sure to
|
||||||
|
check which MPU the program is running on (using <mpu.h>) to access the
|
||||||
|
right fields.
|
||||||
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
|
@ -75,9 +98,9 @@ typedef struct
|
||||||
int RTCCLK_f; // SH7305
|
int RTCCLK_f; // SH7305
|
||||||
};
|
};
|
||||||
|
|
||||||
int Bphi_f;
|
int Bphi_f; // Bus clock frequency
|
||||||
int Iphi_f;
|
int Iphi_f; // Processor clock frequency
|
||||||
int Pphi_f;
|
int Pphi_f; // Peripheral clock frequency
|
||||||
|
|
||||||
} clock_config_t;
|
} clock_config_t;
|
||||||
|
|
||||||
|
@ -86,10 +109,8 @@ typedef struct
|
||||||
Returns the P_phi / 4 timer setting that will last for the given time.
|
Returns the P_phi / 4 timer setting that will last for the given time.
|
||||||
Several units can be used. Be aware that the result is approximate, and
|
Several units can be used. Be aware that the result is approximate, and
|
||||||
very high frequencies or very short delays will yield important errors.
|
very high frequencies or very short delays will yield important errors.
|
||||||
Normally you need not use this function when setting up timers because
|
|
||||||
timer_start() handles this conversion for you.
|
|
||||||
*/
|
*/
|
||||||
uint32_t clock_setting(int duration, enum ClockUnit unit);
|
uint32_t clock_setting(int duration, clock_unit_t unit);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
clock_config()
|
clock_config()
|
||||||
|
|
|
@ -7,78 +7,29 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _CTYPE_H
|
#ifndef _CTYPE_H
|
||||||
#define _CTYPE_H 1
|
#define _CTYPE_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
//---
|
|
||||||
// Character classes.
|
|
||||||
//---
|
|
||||||
|
|
||||||
extern uint8_t ctype_classes[0x80];
|
extern uint8_t ctype_classes[0x80];
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int isalnum(int c) {
|
// Character classes.
|
||||||
return ctype_classes[c] & 0xf0;
|
#define isalnum(c) (ctype_classes[(int)(c)] & 0xf0)
|
||||||
}
|
#define isalpha(c) (ctype_classes[(int)(c)] & 0x30)
|
||||||
|
#define iscntrl(c) (ctype_classes[(int)(c)] & 0x01)
|
||||||
|
#define isdigit(c) (ctype_classes[(int)(c)] & 0x40)
|
||||||
|
#define isgraph(c) (ctype_classes[(int)(c)] & 0xf4)
|
||||||
|
#define islower(c) (ctype_classes[(int)(c)] & 0x10)
|
||||||
|
#define isprint(c) (ctype_classes[(int)(c)] & 0x08)
|
||||||
|
#define ispunct(c) (ctype_classes[(int)(c)] & 0x04)
|
||||||
|
#define isspace(c) (ctype_classes[(int)(c)] & 0x02)
|
||||||
|
#define isupper(c) (ctype_classes[(int)(c)] & 0x20)
|
||||||
|
#define isxdigit(c) (ctype_classes[(int)(c)] & 0x80)
|
||||||
|
#define isascii(c) ((unsigned)c <= 0x7f)
|
||||||
|
#define isblank(c) (c == '\t' || c == ' ')
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int isalpha(int c) {
|
// Character manipulation.
|
||||||
return ctype_classes[c] & 0x30;
|
#define tolower(c) ((c) | isupper(c))
|
||||||
}
|
#define toupper(c) ((c) & ~(islower(c) << 1))
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int iscntrl(int c) {
|
|
||||||
return ctype_classes[c] & 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int isdigit(int c) {
|
|
||||||
return ctype_classes[c] & 0x40;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int isgraph(int c) {
|
|
||||||
return ctype_classes[c] & 0xf4;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int islower(int c) {
|
|
||||||
return ctype_classes[c] & 0x10;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int isprint(int c) {
|
|
||||||
return ctype_classes[c] & 0x08;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int ispunct(int c) {
|
|
||||||
return ctype_classes[c] & 0x04;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int isspace(int c) {
|
|
||||||
return ctype_classes[c] & 0x02;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int isupper(int c) {
|
|
||||||
return ctype_classes[c] & 0x20;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int isxdigit(int c) {
|
|
||||||
return ctype_classes[c] & 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int isascii(int c) {
|
|
||||||
return ((unsigned)c <= 0x7f);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int isblank(int c) {
|
|
||||||
return (c == '\t' || c == ' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
//---
|
|
||||||
// Character manipulation.
|
|
||||||
//---
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int tolower(int c) {
|
|
||||||
return c | isupper(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((always_inline)) static inline int toupper(int c) {
|
|
||||||
return c & ~(islower(c) << 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _CTYPE_H
|
#endif // _CTYPE_H
|
||||||
|
|
|
@ -2,94 +2,107 @@
|
||||||
//
|
//
|
||||||
// gint drawing module: display
|
// gint drawing module: display
|
||||||
//
|
//
|
||||||
// Handles vram manipulation and drawing for plain monochrome display.
|
// This module does most of the monochrome drawing. It manages the video
|
||||||
|
// memory although image rendering and text rendering, as complex tasks,
|
||||||
|
// are left to other modules (bopti and tales, respectively).
|
||||||
//
|
//
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _DISPLAY_H
|
#ifndef _DISPLAY_H
|
||||||
#define _DISPLAY_H 1
|
#define _DISPLAY_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Heading declarations.
|
// Drawing-related types and constants.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
enum Color
|
#define DWIDTH 128 /* Width of the screen */
|
||||||
{
|
#define DHEIGHT 64 /* Height of the screen */
|
||||||
Color_White = 0,
|
|
||||||
Color_Light = 1,
|
|
||||||
Color_Dark = 2,
|
|
||||||
Color_Black = 3,
|
|
||||||
Color_None = 4,
|
|
||||||
Color_Invert = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
// This header needs enum Color to be defined.
|
|
||||||
#include <tales.h>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
struct Image
|
color_t
|
||||||
This structure holds information about a bitmap encoded with fxconv.
|
Defines all colors that the library knows about:
|
||||||
Data is accessed using longword operations, which *requires* many
|
- white is exactly what you think it is;
|
||||||
sizes to be multiples of 4 (structure alignment, data alignment, layer
|
- light is a light gray used by the gray module;
|
||||||
size, ...).
|
- dark is a dark gray, also used by the gray engine;
|
||||||
|
- black is nothing more than black; (sorry)
|
||||||
|
- none means transparent, but is shorter to write.
|
||||||
|
There are also some transformation-associated colors:
|
||||||
|
- invert reverses the intensity of the color (white -> black, dark ->
|
||||||
|
light, etc);
|
||||||
|
- lighten is some kind of partially-transparent white. It lightens the
|
||||||
|
color which it is drawn onto (black -> dark, light -> light);
|
||||||
|
- lighten2 is the same as lighten, except it lightens more (black ->
|
||||||
|
light, light -> white);
|
||||||
|
- darken is the exact opposite of lighten (light -> dark, black ->
|
||||||
|
black).
|
||||||
|
- darken2 is the same to darken as lighten2 to lighten (white -> dark,
|
||||||
|
dark -> black);
|
||||||
|
All transformations except invert only operate when the gray engine is
|
||||||
|
running.
|
||||||
*/
|
*/
|
||||||
struct Image
|
typedef enum
|
||||||
{
|
{
|
||||||
uint8_t magic;
|
color_white = 0,
|
||||||
uint8_t format;
|
color_light = 1,
|
||||||
|
color_dark = 2,
|
||||||
|
color_black = 3,
|
||||||
|
color_none = 4,
|
||||||
|
|
||||||
uint8_t width;
|
color_invert = 5,
|
||||||
uint8_t height;
|
color_lighten = 6,
|
||||||
|
color_lighten2 = 7,
|
||||||
|
color_darken = 8,
|
||||||
|
color_darken2 = 9,
|
||||||
|
|
||||||
const uint32_t data[];
|
} color_t;
|
||||||
|
|
||||||
} __attribute__((packed, aligned(4)));
|
// The bopti module provides bitmap rendering functions.
|
||||||
// Useful shorthand for user code.
|
#include <bopti.h>
|
||||||
typedef struct Image Image;
|
|
||||||
|
|
||||||
|
// The tales module provides text rendering functions but requires the color_t
|
||||||
|
// type definition.
|
||||||
// A few other constants.
|
#include <tales.h>
|
||||||
#define DISPLAY_WIDTH 128
|
|
||||||
#define DISPLAY_HEIGHT 64
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Generic functions.
|
// Video RAM management.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
display_getLocalVRAM()
|
display_getLocalVRAM()
|
||||||
Returns the local video ram address. This function always return the
|
Returns gint's local video RAM address. Gint does not use the system's
|
||||||
same address.
|
buffer because it is misaligned. This function always returns the same
|
||||||
The buffer returned by this function should not be used directly when
|
address. Both the display and the gray module heavily use this buffer;
|
||||||
running the gray engine.
|
make sure you don't interfere with them if you access it.
|
||||||
|
This function does not necessarily returns the video ram that is
|
||||||
|
currently in use; call display_getCurrentVRAM() for this.
|
||||||
*/
|
*/
|
||||||
void *display_getLocalVRAM(void);
|
uint32_t *display_getLocalVRAM(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
display_getCurrentVRAM()
|
display_getCurrentVRAM()
|
||||||
Returns the current video ram. This function usually returns the
|
Returns the current monochrome video ram buffer. This function usually
|
||||||
parameter of the last call to display_useVRAM(), unless the gray engine
|
returns the parameter of the last call to display_useVRAM(), or the
|
||||||
is running (in which case the result is undefined). Returns the local
|
local vram address (which is default when the library starts).
|
||||||
vram address by default.
|
The return value of this function is undefined if the gray engine is
|
||||||
|
running.
|
||||||
*/
|
*/
|
||||||
void *display_getCurrentVRAM(void);
|
uint32_t *display_getCurrentVRAM(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
display_useVRAM()
|
display_useVRAM()
|
||||||
Changes the current video ram address. The argument MUST be a 4-
|
Changes the current monochrome video ram address. The argument must be
|
||||||
aligned 1024-byte buffer; otherwise any drawing operation will crash
|
a 4-aligned 1024-byte buffer because the library's design requires it.
|
||||||
the program.
|
This function refuses misaligned buffers but trusts that enough space
|
||||||
|
is available; failing to provide enough memory may crash the program.
|
||||||
This function will most likely have no effect when running the gray
|
This function will most likely have no effect when running the gray
|
||||||
engine.
|
engine.
|
||||||
*/
|
*/
|
||||||
void display_useVRAM(void *vram);
|
void display_useVRAM(uint32_t *vram);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,30 +112,24 @@ void display_useVRAM(void *vram);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dupdate()
|
dupdate()
|
||||||
Displays the vram on the physical screen. Does nothing when the gray
|
Pushes the video RAM to the physical screen. This function also works
|
||||||
engine is running.
|
when the gray engine is running, but that's probably not what you want.
|
||||||
*/
|
*/
|
||||||
void dupdate(void);
|
void dupdate(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dclear()
|
dclear()
|
||||||
Clears the whole video ram.
|
Clears the whole video ram, making all pixels white.
|
||||||
*/
|
*/
|
||||||
void dclear(void);
|
void dclear(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dclear_area()
|
drect()
|
||||||
Clears an area of the video ram. Both (x1, y1) and (x2, y2) are
|
Draws a rectangle on the screen. This function can use any color which
|
||||||
cleared.
|
is not associated with the gray engine, including the reverse operator.
|
||||||
|
Both end points (x1, y1) and (x2, y2) are affected as well.
|
||||||
*/
|
*/
|
||||||
void dclear_area(int x1, int y1, int x2, int y2);
|
void drect(int x1, int y1, int x2, int y2, color_t operator);
|
||||||
|
|
||||||
/*
|
|
||||||
dreverse_area()
|
|
||||||
Reverses an area of the vram. (x1, y1) and (x2, y2) are reversed as
|
|
||||||
well.
|
|
||||||
*/
|
|
||||||
void dreverse_area(int x1, int y1, int x2, int y2);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -132,9 +139,10 @@ void dreverse_area(int x1, int y1, int x2, int y2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dpixel()
|
dpixel()
|
||||||
Puts a pixel in the vram.
|
Changes a pixel's color in the video ram. The result may depend on the
|
||||||
|
current color of the pixel.
|
||||||
*/
|
*/
|
||||||
void dpixel(int x, int y, enum Color color);
|
void dpixel(size_t x, size_t y, color_t operator);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dline()
|
dline()
|
||||||
|
@ -143,22 +151,6 @@ void dpixel(int x, int y, enum Color color);
|
||||||
|
|
||||||
Uses an algorithm written by PierrotLL for MonochromeLib.
|
Uses an algorithm written by PierrotLL for MonochromeLib.
|
||||||
*/
|
*/
|
||||||
void dline(int x1, int y1, int x2, int y2, enum Color color);
|
void dline(int x1, int y1, int x2, int y2, color_t operator);
|
||||||
|
|
||||||
/*
|
|
||||||
dimage()
|
|
||||||
Displays a monochrome image in the vram. Does a real lot of
|
|
||||||
optimization.
|
|
||||||
*/
|
|
||||||
void dimage(int x, int y, struct Image *image);
|
|
||||||
|
|
||||||
/*
|
|
||||||
dimage_part()
|
|
||||||
Draws a portion of an image, defined by its bounding rectangle.
|
|
||||||
Point (left, top) is included, but (left + width, top + height) is
|
|
||||||
excluded.
|
|
||||||
*/
|
|
||||||
void dimage_part(int x, int y, struct Image *img, int left, int top,
|
|
||||||
int width, int height);
|
|
||||||
|
|
||||||
#endif // _DISPLAY_H
|
#endif // _DISPLAY_H
|
||||||
|
|
|
@ -2,7 +2,17 @@
|
||||||
//
|
//
|
||||||
// gint core module: events
|
// gint core module: events
|
||||||
//
|
//
|
||||||
// Finally some user-friendly API.
|
// Finally some user-friendly API. This module is in charge of managing
|
||||||
|
// the event queue. The waitevent() function should be particularly useful
|
||||||
|
// in program main loops to record key presses and releases in real-time
|
||||||
|
// games.
|
||||||
|
//
|
||||||
|
// Other functions such as the getkey() of the keyboard module provide
|
||||||
|
// more advanced features such as SHIFT and ALPHA modifiers, backlight
|
||||||
|
// control for instance; these functions rely on this module and they
|
||||||
|
// ignore all events that they do not handle. If you want to catch several
|
||||||
|
// types of events (eg. keyboard and serial communication), then you need
|
||||||
|
// to use directly this module.
|
||||||
//
|
//
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
@ -17,30 +27,24 @@
|
||||||
*/
|
*/
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
EventType_None = 0,
|
// Specific events.
|
||||||
ET_None = EventType_None,
|
event_none = 0,
|
||||||
|
event_user = 1,
|
||||||
|
|
||||||
EventType_User = 1,
|
// Keyboard events.
|
||||||
ET_User = EventType_User,
|
event_key_press = 2,
|
||||||
|
event_key_repeat = 3,
|
||||||
|
event_key_release = 4,
|
||||||
|
|
||||||
EventType_KeyPressed = 2,
|
// Other events.
|
||||||
ET_KeyPress = EventType_KeyPressed,
|
event_timer_underflow = 5,
|
||||||
|
|
||||||
EventType_KeyRepeated = 3,
|
|
||||||
ET_KeyRepeat = EventType_KeyRepeated,
|
|
||||||
|
|
||||||
EventType_KeyReleased = 4,
|
|
||||||
ET_KeyRel = EventType_KeyReleased,
|
|
||||||
|
|
||||||
EventType_TimerUnderflow = 5,
|
|
||||||
ET_Timer = EventType_TimerUnderflow,
|
|
||||||
|
|
||||||
} event_type_t;
|
} event_type_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
event_t
|
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 specified by the type attribute.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
@ -48,11 +52,11 @@ typedef struct
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
// For ET_User.
|
// For event_user.
|
||||||
void *data;
|
void *data;
|
||||||
// For ET_KeyPress, ET_KeyRepeat and ET_KeyRel.
|
// For event_key_press, event_key_repeat and event_key_release.
|
||||||
int key;
|
int key;
|
||||||
// For ET_Timer.
|
// For event_timer_underflow.
|
||||||
timer_t *timer;
|
timer_t *timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
//
|
//
|
||||||
// gint core module: interrupt handler
|
// gint core module: interrupt handler
|
||||||
//
|
//
|
||||||
// Central point of the library. Controls the interrupt handler and
|
// This module is the core of the gint library. It controls the interrupt
|
||||||
// defines a few functions to configure callbacks for some interrupts.
|
// handler, allows the user to customize interrupt management, provides
|
||||||
|
// peripheral register access and some information about the runtime
|
||||||
|
// environment.
|
||||||
//
|
//
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,14 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _GRAY_H
|
#ifndef _GRAY_H
|
||||||
#define _GRAY_H 1
|
#define _GRAY_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <display.h>
|
#include <display.h>
|
||||||
|
|
||||||
|
// This module provides bitmap rendering.
|
||||||
|
#include <bopti.h>
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Engine control.
|
// Engine control.
|
||||||
//---
|
//---
|
||||||
|
@ -39,13 +43,13 @@ void gray_stop(void);
|
||||||
gray_lightVRAM()
|
gray_lightVRAM()
|
||||||
Returns the module's light gray vram address.
|
Returns the module's light gray vram address.
|
||||||
*/
|
*/
|
||||||
void *gray_lightVRAM(void);
|
uint32_t *gray_lightVRAM(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_darkVRAM()
|
gray_darkVRAM()
|
||||||
Returns the module's dark gray vram address.
|
Returns the module's dark gray vram address.
|
||||||
*/
|
*/
|
||||||
void *gray_darkVRAM(void);
|
uint32_t *gray_darkVRAM(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_getDelays()
|
gray_getDelays()
|
||||||
|
@ -81,29 +85,26 @@ void gray_setDelays(int light, int dark);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gupdate()
|
gupdate()
|
||||||
Swaps the vram buffer sets.
|
Swaps the vram buffer sets. You need to call this function each time
|
||||||
|
you finish drawing something in the video ram. Unlike the monochrome
|
||||||
|
function dupdate(), gupdate() only does a quick operation indicating
|
||||||
|
that drawing and exposed buffers have been swapped, but nothing on the
|
||||||
|
screen will change until the gray timer fires.
|
||||||
*/
|
*/
|
||||||
void gupdate(void);
|
void gupdate(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gclear()
|
gclear()
|
||||||
Clears the video ram.
|
Clears the gray video ram, making all pixels white.
|
||||||
*/
|
*/
|
||||||
void gclear(void);
|
void gclear(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gclear_area()
|
grect()
|
||||||
Clears an area of the video ram. End points (x1, y1) and (x2, y2) are
|
Draws a rectangle in the gray video ram; this function accepts all
|
||||||
included.
|
values of the color_t type, including gray operators.
|
||||||
*/
|
*/
|
||||||
void gclear_area(int x1, int y1, int x2, int y2);
|
void grect(int x1, int y1, int x2, int y2, color_t operator);
|
||||||
|
|
||||||
/*
|
|
||||||
greverse_area()
|
|
||||||
Reverses an area of the vram. End points (x1, y1) and (x2, y2) are
|
|
||||||
included.
|
|
||||||
*/
|
|
||||||
void greverse_area(int x1, int y1, int x2, int y2);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,29 +114,18 @@ void greverse_area(int x1, int y1, int x2, int y2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gpixel()
|
gpixel()
|
||||||
Puts a pixel in the vram.
|
Puts a pixel in the vram. This function accepts all values of the
|
||||||
|
color_t type, including gray operators.
|
||||||
*/
|
*/
|
||||||
void gpixel(int x, int y, enum Color color);
|
void gpixel(size_t x, size_t y, color_t operator);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gline()
|
gline()
|
||||||
Draws a line in the vram. Automatically optimizes special cases.
|
Draws a line in the vram while automatically optimizing special cases.
|
||||||
|
This function supports all plain colors from the color_t type, but not
|
||||||
|
the gray operators. If you need them for horizontal or vertical lines,
|
||||||
|
you may want to use grect() as a replacement.
|
||||||
*/
|
*/
|
||||||
void gline(int x1, int y1, int x2, int y2, enum Color color);
|
void gline(int x1, int y1, int x2, int y2, color_t operator);
|
||||||
|
|
||||||
/*
|
|
||||||
gimage()
|
|
||||||
Displays a gray image in the vram.
|
|
||||||
*/
|
|
||||||
void gimage(int x, int y, struct Image *image);
|
|
||||||
|
|
||||||
/*
|
|
||||||
gimage_part()
|
|
||||||
Draws a portion of a gray image, defined by its bounding rectangle.
|
|
||||||
Point (left, top) is included, but (left + width, top + height) is
|
|
||||||
excluded.
|
|
||||||
*/
|
|
||||||
void gimage_part(int x, int y, struct Image *image, int left, int top,
|
|
||||||
int width, int height);
|
|
||||||
|
|
||||||
#endif // _GRAY_H
|
#endif // _GRAY_H
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _INTERNALS_BOPTI_H
|
#ifndef _INTERNALS_BOPTI_H
|
||||||
#define _INTERNALS_BOPTI_H 1
|
#define _INTERNALS_BOPTI_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <display.h>
|
#include <display.h>
|
||||||
|
@ -86,7 +86,7 @@ struct Command
|
||||||
// The video ram addresses are set by the public functions and used internally
|
// The video ram addresses are set by the public functions and used internally
|
||||||
// by the module.
|
// by the module.
|
||||||
// Monochrome video ram, light and dark buffers (in this order).
|
// Monochrome video ram, light and dark buffers (in this order).
|
||||||
extern int *bopti_vram, *bopti_v1, *bopti_v2;
|
extern uint32_t *bopti_vram, *bopti_v1, *bopti_v2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -155,6 +155,6 @@ void bopti(const unsigned char *layer, struct Structure *s, struct Command *c);
|
||||||
getStructure()
|
getStructure()
|
||||||
Determines the image size and data pointer.
|
Determines the image size and data pointer.
|
||||||
*/
|
*/
|
||||||
void getStructure(struct Image *img, struct Structure *structure);
|
void getStructure(image_t *img, struct Structure *structure);
|
||||||
|
|
||||||
#endif // _INTERNALS_BOPTI_H
|
#endif // _INTERNALS_BOPTI_H
|
||||||
|
|
|
@ -1,47 +1,40 @@
|
||||||
//---
|
|
||||||
//
|
|
||||||
// gint drawing module: display
|
|
||||||
//
|
|
||||||
// Handles vram manipulation and drawing.
|
|
||||||
//
|
|
||||||
//---
|
|
||||||
|
|
||||||
#ifndef _INTERNALS_DISPLAY_H
|
#ifndef _INTERNALS_DISPLAY_H
|
||||||
#define _INTERNALS_DISPLAY_H 1
|
#define _INTERNALS_DISPLAY_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
extern int *vram;
|
extern uint32_t *vram;
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Rectangle masks.
|
// Rectangle masks.
|
||||||
//
|
//
|
||||||
// The concept of 'rectangle masks' is used several times in this module.
|
// The concept of 'rectangle masks' is used several times in this module.
|
||||||
// It is based on the fact that an operation that affects a rectangle acts
|
// It relies on the fact that operations affecting a rectangle act the
|
||||||
// the same on all its lines. Therefore the behavior of the operation is
|
// same for all lines, and line operation is very optimized. A rectangle
|
||||||
// determined by its behavior on a single line, which is represented using
|
// mask is a set of integers, where each bit indicate whether a specific
|
||||||
// 'masks' whose bits indicate whether a pixel is affected (1) or not (0).
|
// pixel is affected (1) by the operation, or not (0).
|
||||||
//
|
//
|
||||||
// For example when clearing the screen rectangle (16, 16, 112, 48), the
|
// For example to clear a rectangle such as (14, 16, 112, 48), the masks
|
||||||
// masks will represent information '16 to 112 on x-axis', and will hold
|
// will need to hold 0003ffff ffffffff ffffffff ffff0000. Bitwise-
|
||||||
// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These
|
// combining them with video ram long entries yields very good performance
|
||||||
// masks can then be used by setting vram[offset] &= ~masks[i]. This
|
// as compared to operation on single pixels. Each bitwise operation will
|
||||||
// appears to be very flexible : for instance, vram[offset] ^= masks[i]
|
// produce different results, which is very flexible.
|
||||||
// will reverse the pixels in the same rectangle.
|
|
||||||
//
|
|
||||||
// This technique can also be used in more subtle cases with more complex
|
|
||||||
// patterns, but within this module it is unlikely to happen.
|
|
||||||
//
|
//
|
||||||
|
// This technique can also be used in subtle cases with patterns more
|
||||||
|
// complicated than rectangles, but within this module this is unlikely to
|
||||||
|
// happen.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
adjustRectangle()
|
adjustRectangle()
|
||||||
Adjusts the given rectangle coordinates to ensure that :
|
Adjusts the given rectangle coordinates to ensure that :
|
||||||
- the rectangle is entirely contained in the screen
|
- the rectangle is entirely contained in the screen;
|
||||||
- x1 < x2
|
- x1 < x2;
|
||||||
- y1 < y2
|
- y1 < y2,
|
||||||
which is needed when working with screen rectangles.
|
which is needed when working with screen rectangles. Returns non-zero
|
||||||
Returns non-zero if the rectangle is outside the screen.
|
if the rectangle is outside the screen, which usually means there is
|
||||||
|
nothing to do.
|
||||||
*/
|
*/
|
||||||
int adjustRectangle(int *x1, int *y1, int *x2, int *y2);
|
int adjustRectangle(int *x1, int *y1, int *x2, int *y2);
|
||||||
|
|
||||||
|
@ -51,6 +44,6 @@ int adjustRectangle(int *x1, int *y1, int *x2, int *y2);
|
||||||
and x2 (both included). The four masks are stored in the third argument
|
and x2 (both included). The four masks are stored in the third argument
|
||||||
(seen as an array).
|
(seen as an array).
|
||||||
*/
|
*/
|
||||||
void getMasks(int x1, int x2, uint32_t *masks);
|
void getMasks(size_t x1, size_t x2, uint32_t *masks);
|
||||||
|
|
||||||
#endif // _INTERNALS_DISPLAY_H
|
#endif // _INTERNALS_DISPLAY_H
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#ifndef _INTERNALS_GINT_H
|
#ifndef _INTERNALS_GINT_H
|
||||||
#define _INTERNALS_GINT_H 1
|
#define _INTERNALS_GINT_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <gint.h>
|
#include <gint.h>
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Interrupt handlers
|
// Interrupt handlers.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
// General exception handler.
|
// General exception handler.
|
||||||
|
@ -18,7 +18,7 @@ void gint_int(void);
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Assembler-level VBR management
|
// Assembler-level VBR management.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -37,7 +37,7 @@ void gint_setvbr(uint32_t vbr, void (*setup)(void));
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Initialization and termination routines
|
// Initialization and termination routines.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -58,8 +58,8 @@ void gint_quit(void);
|
||||||
Saves many registers into a buffer to ensure that the system is not
|
Saves many registers into a buffer to ensure that the system is not
|
||||||
upset by gint's configuration when the application ends.
|
upset by gint's configuration when the application ends.
|
||||||
*/
|
*/
|
||||||
//void gint_save_7705(gint_save_buffer_t *buffer);
|
// void gint_save_7705(gint_save_buffer_t *buffer);
|
||||||
//void gint_save_7305(gint_save_buffer_t *buffer);
|
// void gint_save_7305(gint_save_buffer_t *buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gint_setup()
|
gint_setup()
|
||||||
|
@ -74,8 +74,8 @@ void gint_setup_7305(void);
|
||||||
Restores the parameters saved in a save buffer to give back the
|
Restores the parameters saved in a save buffer to give back the
|
||||||
interrupt control to the system.
|
interrupt control to the system.
|
||||||
*/
|
*/
|
||||||
//void gint_restore_7705(gint_save_buffer_t *buffer);
|
// void gint_restore_7705(gint_save_buffer_t *buffer);
|
||||||
//void gint_restore_7305(gint_save_buffer_t *buffer);
|
// void gint_restore_7305(gint_save_buffer_t *buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gint_reg()
|
gint_reg()
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <internals/gint.h>
|
#include <internals/gint.h>
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Interrupt handlers
|
// Interrupt handlers.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -60,7 +60,7 @@ extern gint_interrupt_handler_t gint_handlers[];
|
||||||
|
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Interrupt maps
|
// Interrupt maps.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define _INTERNALS_KEYBOARD_H
|
#define _INTERNALS_KEYBOARD_H
|
||||||
|
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
|
#include <timer.h>
|
||||||
#include <clock.h>
|
#include <clock.h>
|
||||||
|
|
||||||
// Keyboard variables.
|
// Keyboard variables.
|
||||||
|
@ -10,10 +11,10 @@ extern volatile int interrupt_flag;
|
||||||
|
|
||||||
// Key statistics.
|
// Key statistics.
|
||||||
extern int repeat_first, repeat_next;
|
extern int repeat_first, repeat_next;
|
||||||
extern int last_key, last_repeats, last_events;
|
extern int last_key, last_repeats, last_time;
|
||||||
|
|
||||||
// RTC callback id.
|
// Virtual timer object.
|
||||||
extern unsigned cb_id;
|
extern timer_t *vtimer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
getPressedKey()
|
getPressedKey()
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
//
|
//
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _MMU_H
|
#ifndef _INTERNALS_MMU_H
|
||||||
#define _MMU_H 1
|
#define _INTERNALS_MMU_H
|
||||||
|
|
||||||
/*
|
/*
|
||||||
mmu_pseudoTLBInit()
|
mmu_pseudoTLBInit()
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _INTERNALS_STDIO_H
|
#ifndef _INTERNALS_STDIO_H
|
||||||
#define _INTERNALS_STDIO_H 1
|
#define _INTERNALS_STDIO_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef _INTERNALS_TALES_H
|
#ifndef _INTERNALS_TALES_H
|
||||||
#define _INTERNALS_TALES_H 1
|
#define _INTERNALS_TALES_H
|
||||||
|
|
||||||
#include <tales.h>
|
#include <tales.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -7,13 +7,14 @@
|
||||||
#define OPERATE_ARGS uint32_t *operators, int height, int x, int y
|
#define OPERATE_ARGS uint32_t *operators, int height, int x, int y
|
||||||
|
|
||||||
extern struct Font *font;
|
extern struct Font *font;
|
||||||
extern enum Color color;
|
extern color_t operator;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
tales_init()
|
tales_init()
|
||||||
Configures tales with the default font (which is part of gint).
|
Configures tales with the default font (which is part of gint).
|
||||||
*/
|
*/
|
||||||
void tales_init(void) __attribute__((constructor));
|
__attribute__((constructor))
|
||||||
|
void tales_init(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
getCharacterIndex()
|
getCharacterIndex()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef _INTERNALS_TIME_H
|
#ifndef _INTERNALS_TIME_H
|
||||||
#define _INTERNALS_TIME_H 1
|
#define _INTERNALS_TIME_H
|
||||||
|
|
||||||
/*
|
/*
|
||||||
isLeap()
|
isLeap()
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _KEYBOARD_H
|
#ifndef _KEYBOARD_H
|
||||||
#define _KEYBOARD_H 1
|
#define _KEYBOARD_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <rtc.h>
|
#include <rtc.h>
|
||||||
|
@ -20,92 +20,87 @@
|
||||||
// Keycodes and related.
|
// Keycodes and related.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
// The following codes are gint matrix codes. They are not compatible with the
|
|
||||||
// system's.
|
|
||||||
|
|
||||||
#define KEY_F1 0x69
|
|
||||||
#define KEY_F2 0x59
|
|
||||||
#define KEY_F3 0x49
|
|
||||||
#define KEY_F4 0x39
|
|
||||||
#define KEY_F4 0x39
|
|
||||||
#define KEY_F5 0x29
|
|
||||||
#define KEY_F6 0x19
|
|
||||||
|
|
||||||
#define KEY_SHIFT 0x68
|
|
||||||
#define KEY_OPTN 0x58
|
|
||||||
#define KEY_VARS 0x48
|
|
||||||
#define KEY_MENU 0x38
|
|
||||||
#define KEY_LEFT 0x28
|
|
||||||
#define KEY_UP 0x18
|
|
||||||
|
|
||||||
#define KEY_ALPHA 0x67
|
|
||||||
#define KEY_SQUARE 0x57
|
|
||||||
#define KEY_POWER 0x47
|
|
||||||
#define KEY_EXIT 0x37
|
|
||||||
#define KEY_DOWN 0x27
|
|
||||||
#define KEY_RIGHT 0x17
|
|
||||||
|
|
||||||
#define KEY_XOT 0x66
|
|
||||||
#define KEY_LOG 0x56
|
|
||||||
#define KEY_LN 0x46
|
|
||||||
#define KEY_SIN 0x36
|
|
||||||
#define KEY_COS 0x26
|
|
||||||
#define KEY_TAN 0x16
|
|
||||||
|
|
||||||
#define KEY_FRAC 0x65
|
|
||||||
#define KEY_FD 0x55
|
|
||||||
#define KEY_LEFTP 0x45
|
|
||||||
#define KEY_RIGHTP 0x35
|
|
||||||
#define KEY_COMMA 0x25
|
|
||||||
#define KEY_ARROW 0x15
|
|
||||||
|
|
||||||
#define KEY_7 0x64
|
|
||||||
#define KEY_8 0x54
|
|
||||||
#define KEY_9 0x44
|
|
||||||
#define KEY_DEL 0x34
|
|
||||||
#define KEY_AC_ON 0x24
|
|
||||||
|
|
||||||
#define KEY_4 0x63
|
|
||||||
#define KEY_5 0x53
|
|
||||||
#define KEY_6 0x43
|
|
||||||
#define KEY_MUL 0x33
|
|
||||||
#define KEY_DIV 0x23
|
|
||||||
|
|
||||||
#define KEY_1 0x62
|
|
||||||
#define KEY_2 0x52
|
|
||||||
#define KEY_3 0x42
|
|
||||||
#define KEY_PLUS 0x32
|
|
||||||
#define KEY_MINUS 0x22
|
|
||||||
|
|
||||||
#define KEY_0 0x61
|
|
||||||
#define KEY_DOT 0x51
|
|
||||||
#define KEY_EXP 0x41
|
|
||||||
#define KEY_NEG 0x31
|
|
||||||
#define KEY_EXE 0x21
|
|
||||||
|
|
||||||
// Key modifiers.
|
|
||||||
#define MOD_SHIFT 0x80
|
|
||||||
#define MOD_ALPHA 0x100
|
|
||||||
#define MOD_CLEAR ~(MOD_SHIFT | MOD_ALPHA)
|
|
||||||
|
|
||||||
// Key events.
|
|
||||||
#define KEY_NONE 0x00
|
|
||||||
#define KEY_NOEVENT 0xff
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
enum KeyboardFrequency
|
key_t
|
||||||
Possible values for the keyboard frequency.
|
The following codes are gint matrix codes. They are not compatible with
|
||||||
|
the system's. Some keycodes are special event codes; all others are
|
||||||
|
made of a key identifier and possibly one or more modifiers.
|
||||||
|
Binary-and a keycode with MOD_CLEAR to remove the modifiers; this will
|
||||||
|
not work with special event codes.
|
||||||
*/
|
*/
|
||||||
enum KeyboardFrequency
|
typedef enum
|
||||||
{
|
{
|
||||||
KeyboardFreq_500mHz = RTCFreq_500mHz,
|
// Special events codes.
|
||||||
KeyboardFreq_1Hz = RTCFreq_1Hz,
|
KEY_NONE = 0x00,
|
||||||
KeyboardFreq_2Hz = RTCFreq_2Hz,
|
KEY_NOEVENT = 0xff,
|
||||||
KeyboardFreq_4Hz = RTCFreq_4Hz,
|
|
||||||
KeyboardFreq_16Hz = RTCFreq_16Hz,
|
// Key modifiers.
|
||||||
KeyboardFreq_64Hz = RTCFreq_64Hz,
|
MOD_SHIFT = 0x80,
|
||||||
KeyboardFreq_256Hz = RTCFreq_256Hz,
|
MOD_ALPHA = 0x100,
|
||||||
};
|
MOD_CLEAR = ~(MOD_SHIFT | MOD_ALPHA),
|
||||||
|
|
||||||
|
// Key identifiers.
|
||||||
|
|
||||||
|
KEY_F1 = 0x69,
|
||||||
|
KEY_F2 = 0x59,
|
||||||
|
KEY_F3 = 0x49,
|
||||||
|
KEY_F4 = 0x39,
|
||||||
|
KEY_F5 = 0x29,
|
||||||
|
KEY_F6 = 0x19,
|
||||||
|
|
||||||
|
KEY_SHIFT = 0x68,
|
||||||
|
KEY_OPTN = 0x58,
|
||||||
|
KEY_VARS = 0x48,
|
||||||
|
KEY_MENU = 0x38,
|
||||||
|
KEY_LEFT = 0x28,
|
||||||
|
KEY_UP = 0x18,
|
||||||
|
|
||||||
|
KEY_ALPHA = 0x67,
|
||||||
|
KEY_SQUARE = 0x57,
|
||||||
|
KEY_POWER = 0x47,
|
||||||
|
KEY_EXIT = 0x37,
|
||||||
|
KEY_DOWN = 0x27,
|
||||||
|
KEY_RIGHT = 0x17,
|
||||||
|
|
||||||
|
KEY_XOT = 0x66,
|
||||||
|
KEY_LOG = 0x56,
|
||||||
|
KEY_LN = 0x46,
|
||||||
|
KEY_SIN = 0x36,
|
||||||
|
KEY_COS = 0x26,
|
||||||
|
KEY_TAN = 0x16,
|
||||||
|
|
||||||
|
KEY_FRAC = 0x65,
|
||||||
|
KEY_FD = 0x55,
|
||||||
|
KEY_LEFTP = 0x45,
|
||||||
|
KEY_RIGHTP = 0x35,
|
||||||
|
KEY_COMMA = 0x25,
|
||||||
|
KEY_ARROW = 0x15,
|
||||||
|
|
||||||
|
KEY_7 = 0x64,
|
||||||
|
KEY_8 = 0x54,
|
||||||
|
KEY_9 = 0x44,
|
||||||
|
KEY_DEL = 0x34,
|
||||||
|
KEY_AC_ON = 0x24,
|
||||||
|
|
||||||
|
KEY_4 = 0x63,
|
||||||
|
KEY_5 = 0x53,
|
||||||
|
KEY_6 = 0x43,
|
||||||
|
KEY_MUL = 0x33,
|
||||||
|
KEY_DIV = 0x23,
|
||||||
|
|
||||||
|
KEY_1 = 0x62,
|
||||||
|
KEY_2 = 0x52,
|
||||||
|
KEY_3 = 0x42,
|
||||||
|
KEY_PLUS = 0x32,
|
||||||
|
KEY_MINUS = 0x22,
|
||||||
|
|
||||||
|
KEY_0 = 0x61,
|
||||||
|
KEY_DOT = 0x51,
|
||||||
|
KEY_EXP = 0x41,
|
||||||
|
KEY_NEG = 0x31,
|
||||||
|
KEY_EXE = 0x21,
|
||||||
|
|
||||||
|
} key_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,23 +109,31 @@ enum KeyboardFrequency
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
keyboard_setFrequency()
|
keyboard_setAnalysisDelay()
|
||||||
Sets the keyboard frequency. The default frequency is 16 Hz. Very few
|
Sets the keyboard analysis delay, that is, the delay (in ms) between
|
||||||
applications will need to change this setting.
|
two keyboard analyzes. If a key is pressed then released in the lapse
|
||||||
At low frequencies, you will miss key hits. At high frequencies, you
|
between two analyzes, the program won't notice anything. On the other
|
||||||
may lose execution power.
|
hand, if the program spends too much time reading the keyboard, it will
|
||||||
|
lose a bit of execution power.
|
||||||
|
The default frequency is about 40 Hz; very few programs will need to
|
||||||
|
change this setting. Please note that the repeat delays should be
|
||||||
|
multiples of the analysis delay for better accuracy.
|
||||||
*/
|
*/
|
||||||
void keyboard_setFrequency(enum KeyboardFrequency frequency);
|
void keyboard_setAnalysisDelay(int analysis_delay_ms);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
keyboard_setRepeatRate()
|
keyboard_setRepeatRate()
|
||||||
Sets the default repeat rate for key events. The delay before the first
|
Sets the default repeat rate for key events. The delay before the first
|
||||||
repeat may have a different value (usually longer). The unit for the
|
repeat may have a different value (usually longer). The unit for the
|
||||||
argument is the keyboard period. For example at 32 Hz, values of
|
argument is ms, but the repeat events themselves may only be fired when
|
||||||
(20, 4) will imitate the system default.
|
a keyboard analysis is performed; which means that for better accuracy,
|
||||||
Set to 0 to disable repetition. If first = 0, no repetition will be
|
these delays should be a multiple of the keyboard period. The keyboard
|
||||||
allowed. If first != 0 and next = 0, only one repetition will be
|
period may be changed by calling keyboard_setAnalysisDelay().
|
||||||
allowed.
|
For instance, delays of (625 ms, 125 ms) will imitate the system's
|
||||||
|
default setting.
|
||||||
|
You can disable repetitions by passing 0 as arguments:
|
||||||
|
- if first = 0, no repetition will ever occur;
|
||||||
|
- if first != 0 and next = 0, only one repetition will occur.
|
||||||
*/
|
*/
|
||||||
void keyboard_setRepeatRate(int first, int next);
|
void keyboard_setRepeatRate(int first, int next);
|
||||||
|
|
||||||
|
@ -141,57 +144,74 @@ void keyboard_setRepeatRate(int first, int next);
|
||||||
//---
|
//---
|
||||||
|
|
||||||
/*
|
/*
|
||||||
enum GetKeyOpt
|
getkey_opt_t
|
||||||
Options available for use with getkey_opt().
|
Options available to customize the behavior of the getkey_opt()
|
||||||
|
function.
|
||||||
*/
|
*/
|
||||||
enum GetkeyOpt
|
typedef enum
|
||||||
{
|
{
|
||||||
Getkey_NoOption = 0x00,
|
getkey_none = 0x00,
|
||||||
|
|
||||||
// Consider [SHIFT] and [ALPHA] as modifiers instead of returning
|
// Consider [SHIFT] and [ALPHA] as modifiers. Returns key identifiers
|
||||||
// KEY_SHIFT and KEY_ALPHA.
|
// with MOD_SHIFT and MOD_ALPHA flags instead of returning KEY_SHIFT
|
||||||
Getkey_ShiftModifier = 0x01,
|
// and KEY_ALPHA.
|
||||||
Getkey_AlphaModifier = 0x02,
|
getkey_shift_modifier = 0x01,
|
||||||
|
getkey_alpha_modifier = 0x02,
|
||||||
|
|
||||||
// Allow changing the backlight status on [SHIFT] + [OPTN].
|
// Allow changing the backlight status on [SHIFT] + [OPTN] on
|
||||||
Getkey_ManageBacklight = 0x04,
|
// compatible models.
|
||||||
|
getkey_manage_backlight = 0x04,
|
||||||
|
|
||||||
// Key repetition. Notice that modifiers will never be repeated.
|
// Allow key repetition. This option does not control the generation of
|
||||||
Getkey_RepeatArrowKeys = 0x10,
|
// repeat events (use keyboard_setRepeatRate() for this) but filters
|
||||||
Getkey_RepeatCharKeys = 0x20,
|
// them. Please note that modifiers will never be repeated, even when
|
||||||
Getkey_RepeatCtrlKeys = 0x40,
|
// pressed continuously.
|
||||||
Getkey_RepeatFuncKeys = 0x80,
|
getkey_repeat_arrow_keys = 0x10,
|
||||||
|
getkey_repeat_char_keys = 0x20,
|
||||||
|
getkey_repeat_ctrl_keys = 0x40,
|
||||||
|
getkey_repeat_func_keys = 0x80,
|
||||||
// Shorthand for the four previous properties.
|
// Shorthand for the four previous properties.
|
||||||
Getkey_RepeatAllKeys = 0xf0,
|
getkey_repeat_all_keys = 0xf0,
|
||||||
};
|
|
||||||
|
} getkey_option_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
getkey()
|
getkey()
|
||||||
Blocking function with auto-repeat and SHIFT modifying functionalities.
|
Blocking function with auto-repeat that heeds for the SHIFT and ALPHA
|
||||||
Reproduces the behavior of the system's GetKey(). Returns the matrix
|
modifiers. In short, this function reproduces the behavior of the
|
||||||
code with a possible MOD_SHIFT bit.
|
system's GetKey() function. It returns a matrix code, possibly with
|
||||||
|
modifier bits.
|
||||||
|
This function does not return until a key is pressed.
|
||||||
*/
|
*/
|
||||||
int getkey(void);
|
int getkey(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
getkey_opt()
|
getkey_opt()
|
||||||
Enhances getkey() with most general functionalities. An OR-combination
|
Enhances getkey() with more general functionalities. An OR-combination
|
||||||
of options may be given as first argument.
|
of options of type getkey_option_t may be given as first argument.
|
||||||
If max_cycles is non-zero and positive, getkey_opt() will return
|
If delay is non-zero and positive, getkey_opt() will return KEY_NOEVENT
|
||||||
KEY_NOEVENT if no event occurs during max_cycle analyzes.
|
if no event occurs during the given delay. Please note that this
|
||||||
|
function can only ever return after a keyboard analysis is performed;
|
||||||
|
the actual delay may exceed the requested time if it's not a multiple
|
||||||
|
of the keyboard period (which can be changed by calling
|
||||||
|
keyboard_setAnalysisDelay()).
|
||||||
Like getkey(), returns the pressed key matrix code, possibly with
|
Like getkey(), returns the pressed key matrix code, possibly with
|
||||||
modifiers depending on the options.
|
modifiers depending on the options.
|
||||||
*/
|
*/
|
||||||
int getkey_opt(enum GetkeyOpt options, int max_cycles);
|
int getkey_opt(getkey_option_t options, int delay_ms);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
multigetkey()
|
multigetkey()
|
||||||
|
|
||||||
Listens the keyboard for simultaneous key hits. This functions fills
|
Listens the keyboard for simultaneous key hits. This functions fills
|
||||||
array `keys` with `count` keycodes, adding KEY_NONE at the end if
|
the 'keys' array with 'count' keycodes, padding with KEY_NONE values at
|
||||||
less than `count` keys are pressed.
|
the end if less that 'count' keys are detected.
|
||||||
If `max_cycles` is non-zero and nothing happens after `max_cycles`
|
If 'delay_ms' is positive and nothing happens during this delay, this
|
||||||
cycles, this function returns an array of KEY_NONE.
|
function returns an array of KEY_NONE. Please note that the delay
|
||||||
|
detection suffers the same limitation as getkey_opt().
|
||||||
|
|
||||||
|
This function suffers from severe limitations and may not be very
|
||||||
|
convenient to use. For more accuracy, consider using the event system.
|
||||||
|
|
||||||
WARNING:
|
WARNING:
|
||||||
Because of hardware limitations, this function generally yields poor
|
Because of hardware limitations, this function generally yields poor
|
||||||
|
@ -202,7 +222,7 @@ int getkey_opt(enum GetkeyOpt options, int max_cycles);
|
||||||
The results are guaranteed to be exact if two keys or less are pressed.
|
The results are guaranteed to be exact if two keys or less are pressed.
|
||||||
With three keys or more, column effects (on SH4) and rectangle effects
|
With three keys or more, column effects (on SH4) and rectangle effects
|
||||||
(on both platforms) mess up the results by making this function think
|
(on both platforms) mess up the results by making this function think
|
||||||
that some keys, which are actually unpressed, are pressed.
|
that some keys, which are actually released, are pressed.
|
||||||
|
|
||||||
This function is designed to make combinations of one or two arrow keys
|
This function is designed to make combinations of one or two arrow keys
|
||||||
with another key as viable as possible. On SH4, this works pretty well
|
with another key as viable as possible. On SH4, this works pretty well
|
||||||
|
@ -215,25 +235,26 @@ int getkey_opt(enum GetkeyOpt options, int max_cycles);
|
||||||
incorrect results. Please do not expect multigetkey() to work as an
|
incorrect results. Please do not expect multigetkey() to work as an
|
||||||
ideal multi-key analyzer.
|
ideal multi-key analyzer.
|
||||||
*/
|
*/
|
||||||
void multigetkey(int *keys, int count, int max_cycles);
|
void multigetkey(int *keys, int count, int delay_ms);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
keylast()
|
keyboard_stateBuffer()
|
||||||
Returns the matrix code of the last pressed key. If repeat_count is
|
|
||||||
non-NULL, it is set to the number of repetitions.
|
|
||||||
*/
|
|
||||||
int keylast(int *repeat_count);
|
|
||||||
|
|
||||||
/*
|
|
||||||
keystate()
|
|
||||||
Returns the address of the keyboard state array. The keyboard state
|
Returns the address of the keyboard state array. The keyboard state
|
||||||
consists in 10 bytes, in which every key is represented as a bit.
|
consists in 10 bytes, in which every key is represented as a bit.
|
||||||
The returned address is the original buffer address. You should avoid
|
The returned address is the original buffer address. You should avoid
|
||||||
editing the array. It wouldn't influence the behavior of the keyboard
|
editing the array. It wouldn't influence the behavior of the keyboard
|
||||||
functions, but the buffer data is very volatile. Therefore, data
|
functions, but the buffer data is very volatile and any data written to
|
||||||
written to the buffer could be replaced anytime.
|
it could be replaced anytime without prior notice.
|
||||||
|
|
||||||
|
If the user wishes to do really advanced keyboard management that they
|
||||||
|
can't achieve it using the library, they can access this buffer.
|
||||||
|
Updates of this buffer's contents can be detected by watching the
|
||||||
|
'interrupt_flag' variable defined in internals/keyboard.h. However, the
|
||||||
|
library will continue firing events so the user needs to catch them and
|
||||||
|
ignore them.
|
||||||
*/
|
*/
|
||||||
volatile uint8_t *keystate(void);
|
volatile uint8_t *keyboard_stateBuffer(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -241,32 +262,61 @@ volatile uint8_t *keystate(void);
|
||||||
// Key analysis.
|
// Key analysis.
|
||||||
//---
|
//---
|
||||||
|
|
||||||
enum KeyType
|
|
||||||
{
|
|
||||||
KeyType_Arrow = 1,
|
|
||||||
KeyType_Character = 2,
|
|
||||||
KeyType_Control = 4,
|
|
||||||
KeyType_Function = 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
keyid()
|
keyid()
|
||||||
Returns a non-matrix key code that can be used for array subscript.
|
Transforms a key identifier and returns a key code that is more
|
||||||
Ignores modifiers.
|
convenient for array subscript that the original matrix codes. The new
|
||||||
|
codes are laid out the following way:
|
||||||
|
|
||||||
|
+0 +1 +2 +3 +4 +5
|
||||||
|
------------------------------------
|
||||||
|
+0 | F1 F2 F3 F4 F5 F6
|
||||||
|
+6 | SHIFT OPTN VARS MENU Left Top
|
||||||
|
+12 | ALPHA x^2 ^ EXIT Down Right
|
||||||
|
+18 | X,O,T log ln sin cos tan
|
||||||
|
+24 | Frac F<>D ( ) , ->
|
||||||
|
+30 | 7 8 9 DEL AC/ON
|
||||||
|
+36 | 4 5 6 * /
|
||||||
|
+42 | 1 2 3 + -
|
||||||
|
+48 | 0 . x10^ (-) EXE
|
||||||
|
|
||||||
|
The returned key code is the sum of the line and column headings. For
|
||||||
|
instance key_id(KEY_SIN) would be 18 + 3 = 21. Please note that there
|
||||||
|
are a few holes in the numbering.
|
||||||
|
This function ignores modifiers and returns -1 on error.
|
||||||
*/
|
*/
|
||||||
int keyid(int key);
|
int key_id(int matrix_key);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
keychar()
|
key_char()
|
||||||
Returns the ASCII character associated with a character key; 0 for
|
Returns the ASCII character associated with a character key, and 0 for
|
||||||
other keys.
|
other keys. This function expects a matrix code and not a key_id()
|
||||||
|
code, and heeds for the ALPHA modifier.
|
||||||
*/
|
*/
|
||||||
int keychar(int key);
|
int key_char(int matrix_key);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
keytype()
|
key_type_t
|
||||||
Returns a key's type. Ignores modifiers.
|
Categorizes the keyboard's keys into several types:
|
||||||
|
- Arrow keys only include the REPLAY pad;
|
||||||
|
- Function keys only include the F1 .. F6 keys;
|
||||||
|
- Character keys are those which input characters;
|
||||||
|
- Control characters are all others.
|
||||||
*/
|
*/
|
||||||
enum KeyType keytype(int key);
|
typedef enum
|
||||||
|
{
|
||||||
|
key_type_arrow = 1,
|
||||||
|
key_type_character = 2,
|
||||||
|
key_type_control = 4,
|
||||||
|
key_type_function = 8,
|
||||||
|
|
||||||
|
} key_type_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
key_type()
|
||||||
|
Returns a key's type. This functions ignores modifiers and expects
|
||||||
|
matrix codes as argument, not key_id() codes.
|
||||||
|
*/
|
||||||
|
key_type_t key_type(int matrix_key);
|
||||||
|
|
||||||
#endif // _KEYBOARD_H
|
#endif // _KEYBOARD_H
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _MPU_H
|
#ifndef _MPU_H
|
||||||
#define _MPU_H 1
|
#define _MPU_H
|
||||||
|
|
||||||
/*
|
/*
|
||||||
mpu_t
|
mpu_t
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _RTC_H
|
#ifndef _RTC_H
|
||||||
#define _RTC_H 1
|
#define _RTC_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _SCREEN_H
|
#ifndef _SCREEN_H
|
||||||
#define _SCREEN_H 1
|
#define _SCREEN_H
|
||||||
|
|
||||||
/*
|
/*
|
||||||
screen_display()
|
screen_display()
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _SETJMP_H
|
#ifndef _SETJMP_H
|
||||||
#define _SETJMP_H 1
|
#define _SETJMP_H
|
||||||
|
|
||||||
// There are 16 CPU registers that *must* be saved to ensure a basically
|
// There are 16 CPU registers that *must* be saved to ensure a basically
|
||||||
// safe jump.
|
// safe jump.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _STDIO_H
|
#ifndef _STDIO_H
|
||||||
#define _STDIO_H 1
|
#define _STDIO_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _STDLIB_H
|
#ifndef _STDLIB_H
|
||||||
#define _STDLIB_H 1
|
#define _STDLIB_H
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// Common definitions.
|
// Common definitions.
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _STRING_H
|
#ifndef _STRING_H
|
||||||
#define _STRING_H 1
|
#define _STRING_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _TALES_H
|
#ifndef _TALES_H
|
||||||
#define _TALES_H 1
|
#define _TALES_H
|
||||||
|
|
||||||
#include <display.h>
|
#include <display.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -95,7 +95,7 @@ typedef struct Font Font;
|
||||||
Sets the font and color to use for subsequent text operations. Pass
|
Sets the font and color to use for subsequent text operations. Pass
|
||||||
font = NULL to use the default font.
|
font = NULL to use the default font.
|
||||||
*/
|
*/
|
||||||
void text_configure(struct Font *font, enum Color color);
|
void text_configure(struct Font *font, color_t operator);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dtext()
|
dtext()
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _TIME_H
|
#ifndef _TIME_H
|
||||||
#define _TIME_H 1
|
#define _TIME_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
//---
|
//---
|
||||||
|
|
||||||
#ifndef _TIMER_H
|
#ifndef _TIMER_H
|
||||||
#define _TIMER_H 1
|
#define _TIMER_H
|
||||||
|
|
||||||
#include <clock.h>
|
#include <clock.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -49,6 +49,16 @@ typedef struct timer_t timer_t;
|
||||||
*/
|
*/
|
||||||
timer_t *timer_create(int delay_ms, int repeats);
|
timer_t *timer_create(int delay_ms, int repeats);
|
||||||
|
|
||||||
|
/*
|
||||||
|
timer_reload()
|
||||||
|
Changes a virtual timer's delay. The timer is not stopped nor started:
|
||||||
|
it keeps running or waiting. Events that were waiting to be handled are
|
||||||
|
dropped and the number of repeats left is not changed. The timer
|
||||||
|
restarts counting from 0 regardless of how much time had elapsed since
|
||||||
|
it last fired.
|
||||||
|
*/
|
||||||
|
void timer_reload(timer_t *timer, int new_ms_delay);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
timer_destroy()
|
timer_destroy()
|
||||||
Destroys a virtual timer. This virtual timer pointer becomes invalid
|
Destroys a virtual timer. This virtual timer pointer becomes invalid
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <internals/bopti.h>
|
#include <internals/bopti.h>
|
||||||
|
|
||||||
// Monochrome video ram, light and dark buffers (in this order).
|
// Monochrome video ram, light and dark buffers (in this order).
|
||||||
int *bopti_vram, *bopti_v1, *bopti_v2;
|
uint32_t *bopti_vram, *bopti_v1, *bopti_v2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bopti_op()
|
bopti_op()
|
||||||
|
@ -285,7 +285,7 @@ void bopti(const unsigned char *layer, struct Structure *s, struct Command *c)
|
||||||
getStructure()
|
getStructure()
|
||||||
Determines the image size and data pointer.
|
Determines the image size and data pointer.
|
||||||
*/
|
*/
|
||||||
void getStructure(struct Image *img, struct Structure *s)
|
void getStructure(image_t *img, struct Structure *s)
|
||||||
{
|
{
|
||||||
int column_count, end, end_bytes, layer;
|
int column_count, end, end_bytes, layer;
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
Point (left, top) is included, but (left + width, top + height) is
|
Point (left, top) is included, but (left + width, top + height) is
|
||||||
excluded.
|
excluded.
|
||||||
*/
|
*/
|
||||||
void dimage_part(int x, int y, struct Image *img, int left, int top,
|
void dimage_part(int x, int y, image_t *img, int left, int top, int width,
|
||||||
int width, int height)
|
int height)
|
||||||
{
|
{
|
||||||
if(!img || img->magic != 0x01) return;
|
if(!img || img->magic != 0x01) return;
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ void dimage_part(int x, int y, struct Image *img, int left, int top,
|
||||||
dimage()
|
dimage()
|
||||||
Displays a monochrome image in the video ram.
|
Displays a monochrome image in the video ram.
|
||||||
*/
|
*/
|
||||||
void dimage(int x, int y, struct Image *img)
|
void dimage(int x, int y, image_t *img)
|
||||||
{
|
{
|
||||||
dimage_part(x, y, img, 0, 0, -1, -1);
|
dimage_part(x, y, img, 0, 0, -1, -1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
Point (left, top) is included, but (left + width, top + height) is
|
Point (left, top) is included, but (left + width, top + height) is
|
||||||
excluded.
|
excluded.
|
||||||
*/
|
*/
|
||||||
void gimage_part(int x, int y, struct Image *img, int left, int top,
|
void gimage_part(int x, int y, image_t *img, int left, int top, int width,
|
||||||
int width, int height)
|
int height)
|
||||||
{
|
{
|
||||||
if(!img || img->magic != 0x01) return;
|
if(!img || img->magic != 0x01) return;
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ void gimage_part(int x, int y, struct Image *img, int left, int top,
|
||||||
gimage()
|
gimage()
|
||||||
Displays a gray image in the video ram.
|
Displays a gray image in the video ram.
|
||||||
*/
|
*/
|
||||||
void gimage(int x, int y, struct Image *img)
|
void gimage(int x, int y, image_t *img)
|
||||||
{
|
{
|
||||||
gimage_part(x, y, img, 0, 0, -1, -1);
|
gimage_part(x, y, img, 0, 0, -1, -1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ static clock_config_t conf = {
|
||||||
Several units can be used. Be aware that the result is approximate, and
|
Several units can be used. Be aware that the result is approximate, and
|
||||||
very high frequencies or very short delays will yield important errors.
|
very high frequencies or very short delays will yield important errors.
|
||||||
*/
|
*/
|
||||||
uint32_t clock_setting(int duration, enum ClockUnit unit)
|
uint32_t clock_setting(int duration, clock_unit_t unit)
|
||||||
{
|
{
|
||||||
if(conf.Pphi_f <= 0) return 0xffffffff;
|
if(conf.Pphi_f <= 0) return 0xffffffff;
|
||||||
uint64_t f = conf.Pphi_f >> 2;
|
uint64_t f = conf.Pphi_f >> 2;
|
||||||
|
@ -27,23 +27,23 @@ uint32_t clock_setting(int duration, enum ClockUnit unit)
|
||||||
|
|
||||||
switch(unit)
|
switch(unit)
|
||||||
{
|
{
|
||||||
case Clock_us:
|
case clock_us:
|
||||||
result = (duration * f) / 1000000;
|
result = (duration * f) / 1000000;
|
||||||
break;
|
break;
|
||||||
case Clock_ms:
|
case clock_ms:
|
||||||
result = (duration * f) / 1000;
|
result = (duration * f) / 1000;
|
||||||
break;
|
break;
|
||||||
case Clock_s:
|
case clock_s:
|
||||||
result = (duration * f);
|
result = (duration * f);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Clock_Hz:
|
case clock_Hz:
|
||||||
result = f / duration;
|
result = f / duration;
|
||||||
break;
|
break;
|
||||||
case Clock_kHz:
|
case clock_kHz:
|
||||||
result = f / (duration * 1000);
|
result = f / (duration * 1000);
|
||||||
break;
|
break;
|
||||||
case Clock_MHz:
|
case clock_MHz:
|
||||||
result = f / (duration * 1000000);
|
result = f / (duration * 1000000);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ void sleep_ms(int ms_delay)
|
||||||
void sleep_us(int us_delay)
|
void sleep_us(int us_delay)
|
||||||
{
|
{
|
||||||
volatile int sleep_done = 0;
|
volatile int sleep_done = 0;
|
||||||
const uint32_t constant = clock_setting(us_delay, Clock_us);
|
const uint32_t constant = clock_setting(us_delay, clock_us);
|
||||||
|
|
||||||
timer_t *timer = htimer_setup(timer_user, constant, timer_Po_4, 1);
|
timer_t *timer = htimer_setup(timer_user, constant, timer_Po_4, 1);
|
||||||
timer_attach(timer, sleep_callback, (void *)&sleep_done);
|
timer_attach(timer, sleep_callback, (void *)&sleep_done);
|
||||||
|
|
|
@ -37,7 +37,7 @@ static void show_error(const char *name, uint32_t *access_mode, uint32_t *tea,
|
||||||
__asm__("stc ssr, %0" : "=rm"(ssr));
|
__asm__("stc ssr, %0" : "=rm"(ssr));
|
||||||
|
|
||||||
dclear();
|
dclear();
|
||||||
text_configure(NULL, Color_Black);
|
text_configure(NULL, color_black);
|
||||||
|
|
||||||
print(3, 1, "EXCEPTION RAISED!");
|
print(3, 1, "EXCEPTION RAISED!");
|
||||||
for(int i = 0; i < 36; i++) vram[i] = ~vram[i];
|
for(int i = 0; i < 36; i++) vram[i] = ~vram[i];
|
||||||
|
|
43
src/ctype/ctype_classes.c
Normal file
43
src/ctype/ctype_classes.c
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
// Let's save up some space and readability (That's Cake's idea, its a bit of a
|
||||||
|
// preprocessor trick but a rather nice trick).
|
||||||
|
#define r4(x) (x), (x), (x), (x)
|
||||||
|
#define r5(x) r4(x), (x)
|
||||||
|
#define r6(x) r5(x), (x)
|
||||||
|
#define r7(x) r6(x), (x)
|
||||||
|
#define r9(x) r7(x), (x), (x)
|
||||||
|
#define r10(x) r6(x), r4(x)
|
||||||
|
#define r15(x) r10(x), r4(x), (x)
|
||||||
|
#define r18(x) r9(x), r9(x)
|
||||||
|
#define r20(x) r10(x), r10(x)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
cntrl = 0x01,
|
||||||
|
space = 0x02,
|
||||||
|
punct = 0x04,
|
||||||
|
print = 0x08,
|
||||||
|
upper = 0x20,
|
||||||
|
lower = 0x10,
|
||||||
|
digit = 0x40,
|
||||||
|
xdigt = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t ctype_classes[0x80] = {
|
||||||
|
// Control characters.
|
||||||
|
r9(cntrl), r5(cntrl | space), r18(cntrl),
|
||||||
|
// Space and some punctuation.
|
||||||
|
space | print, r15(punct | print),
|
||||||
|
// Decimal digits.
|
||||||
|
r10(digit | xdigt | print),
|
||||||
|
// Some punctuation.
|
||||||
|
r7(punct | print),
|
||||||
|
// Uppercase alphabet.
|
||||||
|
r6(upper | xdigt | print), r20(upper | print),
|
||||||
|
// Other punctuation symbols.
|
||||||
|
r6(punct | print),
|
||||||
|
// Lowercase alphabet.
|
||||||
|
r6(lower | xdigt | print), r20(lower | print),
|
||||||
|
// Last punctuation characters and DEL.
|
||||||
|
r4(punct | print), cntrl,
|
||||||
|
};
|
71
src/ctype/ctype_functions.c
Normal file
71
src/ctype/ctype_functions.c
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
//---
|
||||||
|
// Character type functions.
|
||||||
|
// Normally this functions need not be linked because there are macros to
|
||||||
|
// optimize performance, but we still need them to get some pointers.
|
||||||
|
//---
|
||||||
|
|
||||||
|
// We don't want to include <ctype.h> because it defines all the macros...
|
||||||
|
#include <stdint.h>
|
||||||
|
extern uint8_t ctype_classes[0x80];
|
||||||
|
|
||||||
|
#define _inline __attribute__((always_inline)) inline
|
||||||
|
|
||||||
|
_inline int isalnum(int c) {
|
||||||
|
return ctype_classes[c] & 0xf0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int isalpha(int c) {
|
||||||
|
return ctype_classes[c] & 0x30;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int iscntrl(int c) {
|
||||||
|
return ctype_classes[c] & 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int isdigit(int c) {
|
||||||
|
return ctype_classes[c] & 0x40;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int isgraph(int c) {
|
||||||
|
return ctype_classes[c] & 0xf4;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int islower(int c) {
|
||||||
|
return ctype_classes[c] & 0x10;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int isprint(int c) {
|
||||||
|
return ctype_classes[c] & 0x08;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int ispunct(int c) {
|
||||||
|
return ctype_classes[c] & 0x04;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int isspace(int c) {
|
||||||
|
return ctype_classes[c] & 0x02;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int isupper(int c) {
|
||||||
|
return ctype_classes[c] & 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int isxdigit(int c) {
|
||||||
|
return ctype_classes[c] & 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int isascii(int c) {
|
||||||
|
return ((unsigned)c <= 0x7f);
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int isblank(int c) {
|
||||||
|
return (c == '\t' || c == ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int tolower(int c) {
|
||||||
|
return c | isupper(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline int toupper(int c) {
|
||||||
|
return c & ~(islower(c) << 1);
|
||||||
|
}
|
|
@ -3,10 +3,30 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dclear()
|
dclear()
|
||||||
Clears the whole vram.
|
Clears the whole vram, making all pixels white.
|
||||||
*/
|
*/
|
||||||
void dclear(void)
|
void dclear(void)
|
||||||
{
|
{
|
||||||
int i;
|
// I tend to use pre-decrement more than post-increment.
|
||||||
for(i = 0; i < 256; i++) vram[i] = 0;
|
uint32_t *index = vram + 256;
|
||||||
|
|
||||||
|
while(index > vram)
|
||||||
|
{
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
*--index = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
#include <internals/display.h>
|
|
||||||
#include <display.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
dclear_area()
|
|
||||||
Clears an area of the vram using rectangle masks. Both (x1, y1) and
|
|
||||||
(x2, y2) are cleared.
|
|
||||||
*/
|
|
||||||
void dclear_area(int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
uint32_t masks[4];
|
|
||||||
if(adjustRectangle(&x1, &y1, &x2, &y2)) return;
|
|
||||||
getMasks(x1, x2, masks);
|
|
||||||
|
|
||||||
int begin = y1 << 2;
|
|
||||||
int end = (y2 + 1) << 2;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < 4; i++) masks[i] = ~masks[i];
|
|
||||||
for(i = begin; i < end; i++) vram[i] &= masks[i & 3];
|
|
||||||
}
|
|
|
@ -1,43 +1,48 @@
|
||||||
#include <display.h>
|
#include <display.h>
|
||||||
|
|
||||||
// Program video ram. It resides in .bss section, therefore it is cleared at
|
// Program video ram. It resides in BSS section, therefore it is cleared at
|
||||||
// program initialization and stripped from the executable file.
|
// program initialization and stripped from the executable file.
|
||||||
static int local_vram[256];
|
static uint32_t local_vram[256];
|
||||||
int *vram = local_vram;
|
uint32_t *vram = local_vram;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
display_getLocalVRAM()
|
display_getLocalVRAM()
|
||||||
Returns the local video ram address. This function always return the
|
Returns gint's local video RAM address. Gint does not use the system's
|
||||||
same address.
|
buffer because it is misaligned. This function always returns the same
|
||||||
The buffer returned by this function should not be used directly when
|
address. Both the display and the gray module heavily use this buffer;
|
||||||
running the gray engine.
|
make sure you don't interfere with them if you access it.
|
||||||
|
This function does not necessarily returns the video ram that is
|
||||||
|
currently in use; call display_getCurrentVRAM() for this.
|
||||||
*/
|
*/
|
||||||
inline void *display_getLocalVRAM(void)
|
inline uint32_t *display_getLocalVRAM(void)
|
||||||
{
|
{
|
||||||
return (void *)local_vram;
|
return local_vram;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
display_getCurrentVRAM()
|
display_getCurrentVRAM()
|
||||||
Returns the current video ram. This function usually returns the
|
Returns the current monochrome video ram buffer. This function usually
|
||||||
parameter of the last call to display_useVRAM(), unless the gray engine
|
returns the parameter of the last call to display_useVRAM(), or the
|
||||||
is running (in which case the result is undefined). Returns the local
|
local vram address (which is default when the library starts).
|
||||||
vram address by default.
|
The return value of this function is undefined if the gray engine is
|
||||||
|
running.
|
||||||
*/
|
*/
|
||||||
inline void *display_getCurrentVRAM(void)
|
inline uint32_t *display_getCurrentVRAM(void)
|
||||||
{
|
{
|
||||||
return (void *)vram;
|
return vram;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
display_useVRAM()
|
display_useVRAM()
|
||||||
Changes the current video ram address. The argument MUST be a 4-
|
Changes the current monochrome video ram address. The argument must be
|
||||||
aligned 1024-byte buffer ; otherwise any drawing operation will crash
|
a 4-aligned 1024-byte buffer because the library's design requires it.
|
||||||
the program.
|
This function refuses misaligned buffers but trusts that enough space
|
||||||
|
is available; failing to provide enough memory may crash the program.
|
||||||
This function will most likely have no effect when running the gray
|
This function will most likely have no effect when running the gray
|
||||||
engine.
|
engine.
|
||||||
*/
|
*/
|
||||||
inline void display_useVRAM(void *ptr)
|
inline void display_useVRAM(uint32_t *ptr)
|
||||||
{
|
{
|
||||||
vram = (int *)ptr;
|
if((intptr_t)ptr & 3) return;
|
||||||
|
vram = ptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,41 @@
|
||||||
#include <internals/display.h>
|
#include <internals/display.h>
|
||||||
#include <display.h>
|
#include <display.h>
|
||||||
|
|
||||||
#define sgn(x) ((x) < 0 ? -1 : 1)
|
|
||||||
#define abs(x) ((x) < 0 ? -(x) : (x))
|
|
||||||
#define rnd(x) ((int)((x) + 0.5))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dline()
|
dhline()
|
||||||
Draws a line on the screen. Automatically optimizes horizontal and
|
Optimized procedure for drawing an horizontal line. Uses a rectangle
|
||||||
vertical lines.
|
mask.
|
||||||
*/
|
*/
|
||||||
|
static void dhline(size_t x1, size_t x2, int y, color_t operator)
|
||||||
static void dhline(int x1, int x2, int y, enum Color color)
|
|
||||||
{
|
{
|
||||||
uint32_t masks[4];
|
uint32_t masks[4];
|
||||||
int offset = y << 2;
|
uint32_t *video = vram + (y << 2) + 4;
|
||||||
int i;
|
|
||||||
|
|
||||||
// Swapping x1 and x2 if needed.
|
// Swapping x1 and x2 if needed.
|
||||||
if(x1 > x2) x1 ^= x2, x2 ^= x1, x1 ^= x2;
|
if(x1 > x2) x1 ^= x2, x2 ^= x1, x1 ^= x2;
|
||||||
getMasks(x1, x2, masks);
|
getMasks(x1, x2, masks);
|
||||||
|
|
||||||
switch(color)
|
switch(operator)
|
||||||
{
|
{
|
||||||
case Color_White:
|
case color_white:
|
||||||
for(i = 0; i < 4; i++) vram[offset + i] &= ~masks[i];
|
*--video &= ~masks[3];
|
||||||
|
*--video &= ~masks[2];
|
||||||
|
*--video &= ~masks[1];
|
||||||
|
*--video &= ~masks[0];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Color_Black:
|
case color_black:
|
||||||
for(i = 0; i < 4; i++) vram[offset + i] |= masks[i];
|
*--video |= masks[3];
|
||||||
|
*--video |= masks[2];
|
||||||
|
*--video |= masks[1];
|
||||||
|
*--video |= masks[0];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Color_Invert:
|
case color_invert:
|
||||||
for(i = 0; i < 4; i++) vram[offset + i] ^= masks[i];
|
*--video ^= masks[3];
|
||||||
|
*--video ^= masks[2];
|
||||||
|
*--video ^= masks[1];
|
||||||
|
*--video ^= masks[0];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -40,24 +43,30 @@ static void dhline(int x1, int x2, int y, enum Color color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dvline(int y1, int y2, int x, enum Color color)
|
/*
|
||||||
|
dvline()
|
||||||
|
Optimized procedure for drawing a vertical line. This one is far less
|
||||||
|
powerful than dhline() because the video ram is essentially line-
|
||||||
|
oriented. It also uses a mask.
|
||||||
|
*/
|
||||||
|
static void dvline(int y1, int y2, int x, color_t operator)
|
||||||
{
|
{
|
||||||
int offset = (y1 << 2) + (x >> 5);
|
uint32_t *base = vram + (y1 << 2) + (x >> 5);
|
||||||
int end = (y2 << 2) + (x >> 5);
|
uint32_t *video = vram + (y2 << 2) + (x >> 5) + 4;
|
||||||
int mask = 0x80000000 >> (x & 31);
|
uint32_t mask = 0x80000000 >> (x & 31);
|
||||||
|
|
||||||
switch(color)
|
switch(operator)
|
||||||
{
|
{
|
||||||
case Color_White:
|
case color_white:
|
||||||
while(offset <= end) vram[offset] &= ~mask, offset += 4;
|
while(video > base) video -= 4, *video &= ~mask;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Color_Black:
|
case color_black:
|
||||||
while(offset <= end) vram[offset] |= mask, offset += 4;
|
while(video > base) video -= 4, *video |= mask;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Color_Invert:
|
case color_invert:
|
||||||
while(offset <= end) vram[offset] ^= mask, offset += 4;
|
while(video > base) video -= 4, *video ^= mask;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -65,19 +74,28 @@ static void dvline(int y1, int y2, int x, enum Color color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dline(int x1, int y1, int x2, int y2, enum Color color)
|
#define sgn(x) ((x) < 0 ? -1 : 1)
|
||||||
|
#define abs(x) ((x) < 0 ? -(x) : (x))
|
||||||
|
|
||||||
|
/*
|
||||||
|
dline()
|
||||||
|
Line drawing algorithm more or less directly taken for MonochromeLib.
|
||||||
|
Thanks PierrotLL for this. Relies on dhline() and dvline() for specific
|
||||||
|
cases.
|
||||||
|
*/
|
||||||
|
void dline(int x1, int y1, int x2, int y2, color_t operator)
|
||||||
{
|
{
|
||||||
if(adjustRectangle(&x1, &y1, &x2, &y2)) return;
|
if(adjustRectangle(&x1, &y1, &x2, &y2)) return;
|
||||||
|
|
||||||
// Possible optimizations.
|
// Possible optimizations.
|
||||||
if(y1 == y2)
|
if(y1 == y2)
|
||||||
{
|
{
|
||||||
dhline(x1, x2, y1, color);
|
dhline(x1, x2, y1, operator);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(x1 == x2)
|
if(x1 == x2)
|
||||||
{
|
{
|
||||||
dvline(y1, y2, x1, color);
|
dvline(y1, y2, x1, operator);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +105,7 @@ void dline(int x1, int y1, int x2, int y2, enum Color color)
|
||||||
|
|
||||||
dx = abs(dx), dy = abs(dy);
|
dx = abs(dx), dy = abs(dy);
|
||||||
|
|
||||||
dpixel(x1, y1, color);
|
dpixel(x1, y1, operator);
|
||||||
|
|
||||||
if(dx >= dy)
|
if(dx >= dy)
|
||||||
{
|
{
|
||||||
|
@ -97,7 +115,7 @@ void dline(int x1, int y1, int x2, int y2, enum Color color)
|
||||||
x += sx;
|
x += sx;
|
||||||
cumul += dy;
|
cumul += dy;
|
||||||
if(cumul > dx) cumul -= dx, y += sy;
|
if(cumul > dx) cumul -= dx, y += sy;
|
||||||
dpixel(x, y, color);
|
dpixel(x, y, operator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -108,9 +126,9 @@ void dline(int x1, int y1, int x2, int y2, enum Color color)
|
||||||
y += sy;
|
y += sy;
|
||||||
cumul += dx;
|
cumul += dx;
|
||||||
if(cumul > dy) cumul -= dy, x += sx;
|
if(cumul > dy) cumul -= dy, x += sx;
|
||||||
dpixel(x, y, color);
|
dpixel(x, y, operator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dpixel(x2, y2, color);
|
dpixel(x2, y2, operator);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,30 +3,23 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
dpixel()
|
dpixel()
|
||||||
Puts a pixel in the vram.
|
Changes a pixel's color in the video ram. The result may depend on the
|
||||||
|
current color of the pixel.
|
||||||
*/
|
*/
|
||||||
void dpixel(int x, int y, enum Color color)
|
void dpixel(size_t x, size_t y, color_t operator)
|
||||||
{
|
{
|
||||||
if((unsigned int)x > 127 || (unsigned int)y > 63) return;
|
// Let's be honest, all this module's code *heavily* relies on the
|
||||||
|
// screen dimension in the end, so it's not that big a deal.
|
||||||
|
if(x > 127 || y > 63) return;
|
||||||
|
|
||||||
int offset = (y << 2) + (x >> 5);
|
uint32_t *video = vram + (y << 2) + (x >> 5);
|
||||||
int mask = 0x80000000 >> (x & 31);
|
uint32_t mask = 0x80000000 >> (x & 31);
|
||||||
|
|
||||||
switch(color)
|
switch(operator)
|
||||||
{
|
{
|
||||||
case Color_White:
|
case color_white: *video &= ~mask; break;
|
||||||
vram[offset] &= ~mask;
|
case color_black: *video |= mask; break;
|
||||||
break;
|
case color_invert: *video ^= mask; break;
|
||||||
|
default: return;
|
||||||
case Color_Black:
|
|
||||||
vram[offset] |= mask;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Color_Invert:
|
|
||||||
vram[offset] ^= mask;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
59
src/display/drect.c
Normal file
59
src/display/drect.c
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#include <internals/display.h>
|
||||||
|
#include <display.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
drect()
|
||||||
|
Draws a rectangle on the screen. This function can use any color which
|
||||||
|
is not associated with the gray engine, including the reverse operator.
|
||||||
|
*/
|
||||||
|
void drect(int x1, int y1, int x2, int y2, color_t operator)
|
||||||
|
{
|
||||||
|
// Avoid wasting time if the requested operation is invalid here.
|
||||||
|
if(operator != color_white && operator != color_black
|
||||||
|
&& operator != color_invert) return;
|
||||||
|
// Make sure the coordinates are in the right order, and that the
|
||||||
|
// requested rectangle crosses the screen.
|
||||||
|
if(adjustRectangle(&x1, &y1, &x2, &y2)) return;
|
||||||
|
|
||||||
|
uint32_t masks[4];
|
||||||
|
getMasks(x1, x2, masks);
|
||||||
|
|
||||||
|
uint32_t *base = vram + (y1 << 2);
|
||||||
|
uint32_t *video = vram + (y2 << 2) + 4;
|
||||||
|
|
||||||
|
switch(operator)
|
||||||
|
{
|
||||||
|
case color_white:
|
||||||
|
while(video > base)
|
||||||
|
{
|
||||||
|
*--video &= ~masks[3];
|
||||||
|
*--video &= ~masks[2];
|
||||||
|
*--video &= ~masks[1];
|
||||||
|
*--video &= ~masks[0];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case color_black:
|
||||||
|
while(video > base)
|
||||||
|
{
|
||||||
|
*--video |= masks[3];
|
||||||
|
*--video |= masks[2];
|
||||||
|
*--video |= masks[1];
|
||||||
|
*--video |= masks[0];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case color_invert:
|
||||||
|
while(video > base)
|
||||||
|
{
|
||||||
|
*--video ^= masks[3];
|
||||||
|
*--video ^= masks[2];
|
||||||
|
*--video ^= masks[1];
|
||||||
|
*--video ^= masks[0];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Avoid some warnings.
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +0,0 @@
|
||||||
#include <internals/display.h>
|
|
||||||
#include <display.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
dreverse_area()
|
|
||||||
Reverses an area of the vram. This function is a simple application of
|
|
||||||
the rectangle masks concept. (x1, y1) and (x2, y2) are reversed as
|
|
||||||
well.
|
|
||||||
*/
|
|
||||||
void dreverse_area(int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
uint32_t masks[4];
|
|
||||||
if(adjustRectangle(&x1, &y1, &x2, &y2)) return;
|
|
||||||
getMasks(x1, x2, masks);
|
|
||||||
|
|
||||||
int begin = y1 << 2;
|
|
||||||
int end = (y2 + 1) << 2;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = begin; i < end; i++) vram[i] ^= masks[i & 3];
|
|
||||||
}
|
|
|
@ -6,18 +6,18 @@
|
||||||
and x2 (both included). The four masks are stored in the third argument
|
and x2 (both included). The four masks are stored in the third argument
|
||||||
(seen as an array).
|
(seen as an array).
|
||||||
*/
|
*/
|
||||||
void getMasks(int x1, int x2, uint32_t *masks)
|
void getMasks(size_t x1, size_t x2, uint32_t *masks)
|
||||||
{
|
{
|
||||||
// Indexes of the first and last longs that are non-blank.
|
// Indexes of the first and last longs that are not empty.
|
||||||
int l1 = x1 >> 5;
|
size_t l1 = x1 >> 5;
|
||||||
int l2 = x2 >> 5;
|
size_t l2 = x2 >> 5;
|
||||||
int i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
// Setting the base masks. Those are the final values, except for the
|
// Setting the base masks. Those are the final values, except for the
|
||||||
// longs with indexes l1 and l2, that still need to be adjusted.
|
// longs between indexes l1 and l2, that still need to be adjusted.
|
||||||
while(i < l1) masks[i++] = 0x00000000;
|
while(i < l1) masks[i++] = 0x00000000;
|
||||||
while(i <= l2) masks[i++] = 0xffffffff;
|
while(i <= l2) masks[i++] = 0xffffffff;
|
||||||
while(i < 4) masks[i++] = 0x00000000;
|
while(i < 4) masks[i++] = 0x00000000;
|
||||||
|
|
||||||
// Removing the long number information in x1 and x2 (that is, the
|
// Removing the long number information in x1 and x2 (that is, the
|
||||||
// multiples of 32) to keep only the interesting information -- the
|
// multiples of 32) to keep only the interesting information -- the
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
event_t pollevent(void)
|
event_t pollevent(void)
|
||||||
{
|
{
|
||||||
event_t event = {
|
event_t event = {
|
||||||
.type = ET_None
|
.type = event_none,
|
||||||
};
|
};
|
||||||
if(queue_size <= 0) return event;
|
if(queue_size <= 0) return event;
|
||||||
|
|
||||||
|
@ -33,6 +33,6 @@ event_t waitevent(void)
|
||||||
{
|
{
|
||||||
event_t event;
|
event_t event;
|
||||||
|
|
||||||
while((event = pollevent()).type == ET_None) sleep();
|
while((event = pollevent()).type == event_none) sleep();
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ volatile int queue_size = 0;
|
||||||
int event_push(event_t 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 == event_none) return 2;
|
||||||
|
|
||||||
int index = queue_start + queue_size;
|
int index = queue_start + queue_size;
|
||||||
if(index >= EVENTS_QUEUE_SIZE) index -= EVENTS_QUEUE_SIZE;
|
if(index >= EVENTS_QUEUE_SIZE) index -= EVENTS_QUEUE_SIZE;
|
||||||
|
|
|
@ -6,9 +6,28 @@
|
||||||
*/
|
*/
|
||||||
void gclear(void)
|
void gclear(void)
|
||||||
{
|
{
|
||||||
int *v1 = gray_lightVRAM();
|
uint32_t *lbase = gray_lightVRAM();
|
||||||
int *v2 = gray_darkVRAM();
|
uint32_t *v1 = lbase + 256;
|
||||||
int i;
|
uint32_t *v2 = gray_darkVRAM() + 256;
|
||||||
|
|
||||||
for(i = 0; i < 256; i++) v1[i] = v2[i] = 0;
|
while(v1 > lbase)
|
||||||
|
{
|
||||||
|
*--v1 = 0;
|
||||||
|
*--v1 = 0;
|
||||||
|
*--v1 = 0;
|
||||||
|
*--v1 = 0;
|
||||||
|
*--v1 = 0;
|
||||||
|
*--v1 = 0;
|
||||||
|
*--v1 = 0;
|
||||||
|
*--v1 = 0;
|
||||||
|
|
||||||
|
*--v2 = 0;
|
||||||
|
*--v2 = 0;
|
||||||
|
*--v2 = 0;
|
||||||
|
*--v2 = 0;
|
||||||
|
*--v2 = 0;
|
||||||
|
*--v2 = 0;
|
||||||
|
*--v2 = 0;
|
||||||
|
*--v2 = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
#include <gray.h>
|
|
||||||
#include <display.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
gclear_area()
|
|
||||||
Clears an area of the video ram. End points (x1, y1) and (x2, y2) are
|
|
||||||
included.
|
|
||||||
*/
|
|
||||||
void gclear_area(int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
display_useVRAM(gray_lightVRAM());
|
|
||||||
dclear_area(x1, y1, x2, y2);
|
|
||||||
display_useVRAM(gray_darkVRAM());
|
|
||||||
dclear_area(x1, y1, x2, y2);
|
|
||||||
}
|
|
|
@ -3,22 +3,23 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gline()
|
gline()
|
||||||
Draws a line in the vram. Automatically optimizes special cases.
|
Draws a line in the vram. Automatically optimizes special cases. This
|
||||||
|
function does not support the light operators.
|
||||||
*/
|
*/
|
||||||
void gline(int x1, int y1, int x2, int y2, enum Color color)
|
void gline(int x1, int y1, int x2, int y2, color_t operator)
|
||||||
{
|
{
|
||||||
enum Color c1, c2;
|
color_t op1, op2;
|
||||||
|
|
||||||
if(color == Color_None) return;
|
if(operator == color_invert) op1 = op2 = color_invert;
|
||||||
else if(color == Color_Invert) c1 = c2 = Color_Invert;
|
else if(operator >= color_none) return;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
c1 = 3 * (color & 1);
|
op1 = 3 * (operator & 1);
|
||||||
c2 = 3 * (color >> 1);
|
op2 = 3 * (operator >> 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
display_useVRAM(gray_lightVRAM());
|
display_useVRAM(gray_lightVRAM());
|
||||||
dline(x1, y1, x2, y2, c1);
|
dline(x1, y1, x2, y2, op1);
|
||||||
display_useVRAM(gray_darkVRAM());
|
display_useVRAM(gray_darkVRAM());
|
||||||
dline(x1, y1, x2, y2, c2);
|
dline(x1, y1, x2, y2, op2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,44 +4,56 @@
|
||||||
gpixel()
|
gpixel()
|
||||||
Puts a pixel in the vram.
|
Puts a pixel in the vram.
|
||||||
*/
|
*/
|
||||||
void gpixel(int x, int y, enum Color color)
|
void gpixel(size_t x, size_t y, color_t operator)
|
||||||
{
|
{
|
||||||
if((unsigned int)x > 127 || (unsigned int)y > 63) return;
|
if(x > 127 || y > 63) return;
|
||||||
|
|
||||||
int offset = (y << 2) + (x >> 5);
|
uint32_t *light = gray_lightVRAM() + (y << 2) + (x >> 5);
|
||||||
int mask = 0x80000000 >> (x & 31);
|
uint32_t *dark = gray_darkVRAM() + (y << 2) + (x >> 5);
|
||||||
|
uint32_t mask = 0x80000000 >> (x & 31);
|
||||||
|
|
||||||
int *v1 = gray_lightVRAM();
|
switch(operator)
|
||||||
int *v2 = gray_lightVRAM();
|
|
||||||
|
|
||||||
switch(color)
|
|
||||||
{
|
{
|
||||||
case Color_White:
|
case color_white:
|
||||||
v1[offset] &= ~mask;
|
*light &= ~mask;
|
||||||
v2[offset] &= ~mask;
|
*dark &= ~mask;
|
||||||
break;
|
break;
|
||||||
|
case color_light:
|
||||||
case Color_Light:
|
*light |= mask;
|
||||||
v1[offset] |= mask;
|
*dark &= ~mask;
|
||||||
v2[offset] &= ~mask;
|
|
||||||
break;
|
break;
|
||||||
|
case color_dark:
|
||||||
case Color_Dark:
|
*light &= ~mask;
|
||||||
v1[offset] &= ~mask;
|
*dark |= mask;
|
||||||
v2[offset] |= mask;
|
|
||||||
break;
|
break;
|
||||||
|
case color_black:
|
||||||
case Color_Black:
|
*light |= mask;
|
||||||
v1[offset] |= mask;
|
*dark |= mask;
|
||||||
v2[offset] |= mask;
|
|
||||||
break;
|
break;
|
||||||
|
case color_none:
|
||||||
|
return;
|
||||||
|
|
||||||
case Color_Invert:
|
case color_invert:
|
||||||
v1[offset] ^= mask;
|
*light ^= mask;
|
||||||
v2[offset] ^= mask;
|
*dark ^= mask;
|
||||||
break;
|
break;
|
||||||
|
case color_lighten:;
|
||||||
default:
|
uint32_t old_light_1 = *light;
|
||||||
|
*light &= *dark | ~mask;
|
||||||
|
*dark = (old_light_1 | ~mask) & (mask ^ *dark);
|
||||||
|
break;
|
||||||
|
case color_lighten2:
|
||||||
|
*dark &= *light | ~mask;
|
||||||
|
*light &= ~mask;
|
||||||
|
break;
|
||||||
|
case color_darken:;
|
||||||
|
uint32_t old_light_2 = *light;
|
||||||
|
*light |= *dark & mask;
|
||||||
|
*dark = (old_light_2 & mask) | (mask ^ *dark);
|
||||||
|
break;
|
||||||
|
case color_darken2:
|
||||||
|
*dark |= *light | mask;
|
||||||
|
*light |= mask;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
#include <timer.h>
|
#include <timer.h>
|
||||||
#include <mpu.h>
|
#include <mpu.h>
|
||||||
|
|
||||||
static int internal_vrams[3][256];
|
static uint32_t internal_vrams[3][256];
|
||||||
static const void *vrams[4];
|
static uint32_t *vrams[4];
|
||||||
|
|
||||||
static int current = 0;
|
static int current = 0;
|
||||||
static int delays[2];
|
static int delays[2];
|
||||||
|
@ -45,10 +45,10 @@ void gray_interrupt(void)
|
||||||
*/
|
*/
|
||||||
__attribute__((constructor)) void gray_init(void)
|
__attribute__((constructor)) void gray_init(void)
|
||||||
{
|
{
|
||||||
vrams[0] = (const void *)display_getLocalVRAM();
|
vrams[0] = display_getLocalVRAM();
|
||||||
vrams[1] = (const void *)internal_vrams[0];
|
vrams[1] = internal_vrams[0];
|
||||||
vrams[2] = (const void *)internal_vrams[1];
|
vrams[2] = internal_vrams[1];
|
||||||
vrams[3] = (const void *)internal_vrams[2];
|
vrams[3] = internal_vrams[2];
|
||||||
|
|
||||||
delays[0] = 912;
|
delays[0] = 912;
|
||||||
delays[1] = 1343;
|
delays[1] = 1343;
|
||||||
|
@ -119,18 +119,18 @@ inline int gray_runs(void)
|
||||||
gray_lightVRAM()
|
gray_lightVRAM()
|
||||||
Returns the module's gray vram address.
|
Returns the module's gray vram address.
|
||||||
*/
|
*/
|
||||||
void *gray_lightVRAM(void)
|
uint32_t *gray_lightVRAM(void)
|
||||||
{
|
{
|
||||||
return (void *)vrams[~current & 2];
|
return vrams[~current & 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gray_lightVRAM()
|
gray_lightVRAM()
|
||||||
Returns the module's dark vram address.
|
Returns the module's dark vram address.
|
||||||
*/
|
*/
|
||||||
void *gray_darkVRAM(void)
|
uint32_t *gray_darkVRAM(void)
|
||||||
{
|
{
|
||||||
return (void *)vrams[(~current & 2) | 1];
|
return vrams[(~current & 2) | 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
70
src/gray/grect.c
Normal file
70
src/gray/grect.c
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#include <internals/display.h>
|
||||||
|
#include <gray.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
grect()
|
||||||
|
Draws a rectangle on the screen. This function can use all colors.
|
||||||
|
*/
|
||||||
|
void grect(int x1, int y1, int x2, int y2, color_t operator)
|
||||||
|
{
|
||||||
|
if(operator == color_none) return;
|
||||||
|
if(adjustRectangle(&x1, &y1, &x2, &y2)) return;
|
||||||
|
|
||||||
|
uint32_t masks[4];
|
||||||
|
getMasks(x1, x2, masks);
|
||||||
|
|
||||||
|
uint32_t *lbase = gray_lightVRAM() + (y1 << 2);
|
||||||
|
uint32_t *lvideo = gray_lightVRAM() + (y2 << 2) + 4;
|
||||||
|
uint32_t *dvideo = gray_darkVRAM() + (y2 << 2) + 4;
|
||||||
|
|
||||||
|
// Doing things in this order will be slower, but man, I can't stand
|
||||||
|
// writing that many lines of code for such a simple task. It will be
|
||||||
|
// terribly heavy in the binary file...
|
||||||
|
while(lvideo > lbase) for(int i = 0; i < 4; i++) switch(operator)
|
||||||
|
{
|
||||||
|
case color_white:
|
||||||
|
*--lvideo &= ~masks[i];
|
||||||
|
*--dvideo &= ~masks[i];
|
||||||
|
break;
|
||||||
|
case color_light:
|
||||||
|
*--lvideo |= masks[i];
|
||||||
|
*--dvideo &= ~masks[i];
|
||||||
|
break;
|
||||||
|
case color_dark:
|
||||||
|
*--lvideo &= ~masks[i];
|
||||||
|
*--dvideo |= masks[i];
|
||||||
|
break;
|
||||||
|
case color_black:
|
||||||
|
*--lvideo |= masks[i];
|
||||||
|
*--dvideo |= masks[i];
|
||||||
|
break;
|
||||||
|
case color_none: return;
|
||||||
|
|
||||||
|
case color_invert:
|
||||||
|
*--lvideo ^= masks[i];
|
||||||
|
*--dvideo ^= masks[i];
|
||||||
|
break;
|
||||||
|
case color_lighten:;
|
||||||
|
uint32_t light_1 = *lvideo;
|
||||||
|
dvideo--;
|
||||||
|
*--lvideo &= *dvideo | ~masks[i];
|
||||||
|
*dvideo = (light_1 | ~masks[i]) & (masks[i] ^ *dvideo);
|
||||||
|
break;
|
||||||
|
case color_lighten2:
|
||||||
|
lvideo--;
|
||||||
|
*--dvideo &= *lvideo | ~masks[i];
|
||||||
|
*lvideo &= ~masks[i];
|
||||||
|
break;
|
||||||
|
case color_darken:;
|
||||||
|
uint32_t light_2 = *lvideo;
|
||||||
|
dvideo--;
|
||||||
|
*--lvideo |= *dvideo & masks[i];
|
||||||
|
*dvideo = (light_2 & masks[i]) | (masks[i] ^ *dvideo);
|
||||||
|
break;
|
||||||
|
case color_darken2:
|
||||||
|
lvideo--;
|
||||||
|
*--dvideo |= *lvideo | masks[i];
|
||||||
|
*lvideo |= masks[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
#include <gray.h>
|
|
||||||
#include <display.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
greverse_area()
|
|
||||||
Reverses an area of the vram. End points (x1, y1) and (x2, y2) are
|
|
||||||
included.
|
|
||||||
*/
|
|
||||||
void greverse_area(int x1, int y1, int x2, int y2)
|
|
||||||
{
|
|
||||||
display_useVRAM(gray_lightVRAM());
|
|
||||||
dreverse_area(x1, y1, x2, y2);
|
|
||||||
display_useVRAM(gray_darkVRAM());
|
|
||||||
dreverse_area(x1, y1, x2, y2);
|
|
||||||
}
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <internals/keyboard.h>
|
#include <internals/keyboard.h>
|
||||||
|
#include <internals/timer.h>
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
#include <events.h>
|
#include <events.h>
|
||||||
#include <screen.h>
|
#include <screen.h>
|
||||||
|
@ -11,10 +12,11 @@
|
||||||
int getkey(void)
|
int getkey(void)
|
||||||
{
|
{
|
||||||
return getkey_opt(
|
return getkey_opt(
|
||||||
Getkey_ShiftModifier |
|
getkey_shift_modifier |
|
||||||
Getkey_AlphaModifier |
|
getkey_alpha_modifier |
|
||||||
Getkey_ManageBacklight |
|
getkey_manage_backlight |
|
||||||
Getkey_RepeatArrowKeys,
|
getkey_repeat_arrow_keys,
|
||||||
|
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -22,101 +24,92 @@ int getkey(void)
|
||||||
/*
|
/*
|
||||||
getkey_opt()
|
getkey_opt()
|
||||||
Enhances getkey() with more general functionalities.
|
Enhances getkey() with more general functionalities.
|
||||||
If max_cycles is non-zero and positive, getkey_opt() will return
|
If delay_ms 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 before delay_ms.
|
||||||
*/
|
*/
|
||||||
static void getkey_opt_wait(int *cycles)
|
static void getkey_opt_wait(int *delay_ms)
|
||||||
{
|
{
|
||||||
while(!interrupt_flag) sleep();
|
while(!interrupt_flag) sleep();
|
||||||
interrupt_flag = 0;
|
interrupt_flag = 0;
|
||||||
|
|
||||||
if(*cycles > 0) (*cycles)--;
|
if(*delay_ms > 0)
|
||||||
|
{
|
||||||
|
(*delay_ms) -= vtimer->ms_delay;
|
||||||
|
if(*delay_ms < 0) *delay_ms = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int getkey_opt(enum GetkeyOpt options, int cycles)
|
int getkey_opt(getkey_option_t options, int delay_ms)
|
||||||
{
|
{
|
||||||
event_t event;
|
event_t event;
|
||||||
int modifier = 0;
|
int modifier = 0, key;
|
||||||
static int event_ref = 0;
|
key_type_t type;
|
||||||
|
|
||||||
if(cycles <= 0) cycles = -1;
|
if(delay_ms <= 0) delay_ms = -1;
|
||||||
while(cycles != 0)
|
|
||||||
|
while(delay_ms != 0) switch((event = pollevent()).type)
|
||||||
{
|
{
|
||||||
event = pollevent();
|
case event_none:
|
||||||
switch(event.type)
|
getkey_opt_wait(&delay_ms);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case event_key_press:
|
||||||
|
key = event.key;
|
||||||
|
|
||||||
|
if(options & getkey_manage_backlight && key == KEY_OPTN
|
||||||
|
&& (modifier & MOD_SHIFT))
|
||||||
{
|
{
|
||||||
case ET_None:
|
screen_toggleBacklight();
|
||||||
if(last_key == KEY_NONE)
|
modifier &= ~MOD_SHIFT;
|
||||||
{
|
continue;
|
||||||
getkey_opt_wait(&cycles);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handling repetitions.
|
|
||||||
enum KeyType type = keytype(last_key);
|
|
||||||
if(!(options & (type << 4))) break;
|
|
||||||
|
|
||||||
if(event_ref <= 0)
|
|
||||||
{
|
|
||||||
getkey_opt_wait(&cycles);
|
|
||||||
event_ref++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_events++;
|
|
||||||
event_ref--;
|
|
||||||
|
|
||||||
if(last_events >= (last_repeats ? repeat_next :
|
|
||||||
repeat_first))
|
|
||||||
{
|
|
||||||
last_repeats++;
|
|
||||||
last_events = 0;
|
|
||||||
return last_key;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ET_KeyPress:
|
|
||||||
;
|
|
||||||
int key = event.key;
|
|
||||||
if(options & Getkey_ManageBacklight && key == KEY_OPTN
|
|
||||||
&& modifier & MOD_SHIFT)
|
|
||||||
{
|
|
||||||
screen_toggleBacklight();
|
|
||||||
modifier &= ~MOD_SHIFT;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(options & Getkey_ShiftModifier && key == KEY_SHIFT)
|
|
||||||
{
|
|
||||||
modifier ^= MOD_SHIFT;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(options & Getkey_AlphaModifier && key == KEY_ALPHA)
|
|
||||||
{
|
|
||||||
modifier ^= MOD_ALPHA;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_key = key;
|
|
||||||
last_repeats = 0;
|
|
||||||
last_events = 0;
|
|
||||||
event_ref = 0;
|
|
||||||
return key | modifier;
|
|
||||||
|
|
||||||
case ET_KeyRel:
|
|
||||||
if(event.key != last_key) break;
|
|
||||||
last_key = KEY_NONE;
|
|
||||||
last_repeats = 0;
|
|
||||||
last_events = 0;
|
|
||||||
event_ref = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
if(options & getkey_shift_modifier && key == KEY_SHIFT)
|
||||||
|
{
|
||||||
|
modifier ^= MOD_SHIFT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(options & getkey_alpha_modifier && key == KEY_ALPHA)
|
||||||
|
{
|
||||||
|
modifier ^= MOD_ALPHA;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_key = key;
|
||||||
|
last_repeats = 0;
|
||||||
|
last_time = 0;
|
||||||
|
return key | modifier;
|
||||||
|
|
||||||
|
case event_key_repeat:
|
||||||
|
key = event.key;
|
||||||
|
if(key != last_key) continue;
|
||||||
|
|
||||||
|
// Checking that this type of repetition is allowed.
|
||||||
|
type = key_type(key);
|
||||||
|
if(!(options & (type << 4))) break;
|
||||||
|
|
||||||
|
last_time += vtimer->ms_delay;
|
||||||
|
int cmp = last_repeats ? repeat_next : repeat_first;
|
||||||
|
|
||||||
|
if(last_time >= cmp)
|
||||||
|
{
|
||||||
|
last_repeats++;
|
||||||
|
last_time -= cmp;
|
||||||
|
return last_key;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case event_key_release:
|
||||||
|
if(event.key != last_key) break;
|
||||||
|
last_key = KEY_NONE;
|
||||||
|
last_repeats = 0;
|
||||||
|
last_time = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_key = KEY_NONE;
|
last_key = KEY_NONE;
|
||||||
last_repeats = 0;
|
last_repeats = 0;
|
||||||
last_events = 0;
|
last_time = 0;
|
||||||
event_ref = 0;
|
|
||||||
return KEY_NONE;
|
return KEY_NONE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
keychar()
|
key_char()
|
||||||
Returns the ASCII character associated with a key, or 0 for control
|
Returns the ASCII character associated with a character key, and 0 for
|
||||||
keys.
|
other keys. This function expects a matrix code and not a key_id()
|
||||||
|
code, and heeds for the ALPHA modifier.
|
||||||
*/
|
*/
|
||||||
int keychar(int key)
|
int key_char(int matrix_key)
|
||||||
{
|
{
|
||||||
char flat[] = {
|
char flat[] = {
|
||||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
@ -30,7 +31,6 @@ int keychar(int key)
|
||||||
'Z', ' ', '"', 0x0, 0x0, 0x0
|
'Z', ' ', '"', 0x0, 0x0, 0x0
|
||||||
};
|
};
|
||||||
|
|
||||||
int id = keyid(key);
|
int id = key_id(matrix_key);
|
||||||
|
return (matrix_key & MOD_ALPHA) ? alpha[id] : flat[id];
|
||||||
return (key & MOD_ALPHA) ? alpha[id] : flat[id];
|
|
||||||
}
|
}
|
19
src/keyboard/key_id.c
Normal file
19
src/keyboard/key_id.c
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#include <keyboard.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
keyid()
|
||||||
|
Transforms a key identifier and returns a key code that is more
|
||||||
|
convenient for array subscript that the original matrix codes. Please
|
||||||
|
note that there are a few holes in the numbering.
|
||||||
|
This function ignores modifiers and returns -1 on error.
|
||||||
|
*/
|
||||||
|
int key_id(int matrix_key)
|
||||||
|
{
|
||||||
|
if(matrix_key < 0) return -1;
|
||||||
|
matrix_key &= MOD_CLEAR;
|
||||||
|
|
||||||
|
int row = 9 - (matrix_key & 0x0f);
|
||||||
|
int column = 6 - ((matrix_key & 0xf0) >> 4);
|
||||||
|
|
||||||
|
return 6 * row + column;
|
||||||
|
}
|
24
src/keyboard/key_type.c
Normal file
24
src/keyboard/key_type.c
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include <keyboard.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
key_type()
|
||||||
|
Returns a key's type. This functions ignores modifiers and expects
|
||||||
|
matrix codes as argument, not key_id() codes.
|
||||||
|
*/
|
||||||
|
key_type_t key_type(int matrix_key)
|
||||||
|
{
|
||||||
|
matrix_key &= MOD_CLEAR;
|
||||||
|
|
||||||
|
// Arrow keys.
|
||||||
|
if(matrix_key == KEY_UP || matrix_key == KEY_RIGHT
|
||||||
|
|| matrix_key == KEY_DOWN || matrix_key == KEY_LEFT)
|
||||||
|
{
|
||||||
|
return key_type_arrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function keys (F1 .. F6) are ton only keys of the ninth row.
|
||||||
|
if((matrix_key & 0x0f) == 0x09) return key_type_function;
|
||||||
|
|
||||||
|
// Then character keys are those that have an associated character. =p
|
||||||
|
return key_char(matrix_key) ? key_type_character : key_type_control;
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
#include <internals/keyboard.h>
|
|
||||||
#include <keyboard.h>
|
|
||||||
#include <clock.h>
|
|
||||||
#include <rtc.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
keyboard_setRepeatRate()
|
|
||||||
Sets the default repeat rate for key events. The unit for the argument
|
|
||||||
is the keyboard period.
|
|
||||||
For example at 32 Hz, values of (20, 4) will imitate the system
|
|
||||||
default.
|
|
||||||
*/
|
|
||||||
void keyboard_setRepeatRate(int first, int next)
|
|
||||||
{
|
|
||||||
if(first < 0) first = 0;
|
|
||||||
if(next < 0) next = 0;
|
|
||||||
|
|
||||||
repeat_first = first;
|
|
||||||
repeat_next = next;
|
|
||||||
}
|
|
181
src/keyboard/keyboard_core.c
Normal file
181
src/keyboard/keyboard_core.c
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
#include <internals/keyboard.h>
|
||||||
|
#include <keyboard.h>
|
||||||
|
#include <timer.h>
|
||||||
|
#include <mpu.h>
|
||||||
|
#include <clock.h>
|
||||||
|
#include <events.h>
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Keyboard variables.
|
||||||
|
//---
|
||||||
|
|
||||||
|
// Current keyboard state: each element represents a row, and each bit a key,
|
||||||
|
// but not all bits are used.
|
||||||
|
volatile uint8_t keyboard_state[10] = { 0 };
|
||||||
|
// Interrupt flag: set when an interrupt occurs, and cleared by functions such
|
||||||
|
// as getkey() that watch it (because such functions will wake up every time an
|
||||||
|
// interrupt occurs, and they need to know whether it was the keyboard).
|
||||||
|
volatile int interrupt_flag = 0;
|
||||||
|
|
||||||
|
// Delays, in milliseconds, before repeating keys (the first repetition may
|
||||||
|
// have a different delay).
|
||||||
|
int repeat_first = 625, repeat_next = 125;
|
||||||
|
|
||||||
|
// Which key was pressed last, how many times it has been repeated, and how
|
||||||
|
// much time (in milliseconds) has elapsed since it was last repeated.
|
||||||
|
int last_key = KEY_NONE, last_repeats = 0, last_time = 0;
|
||||||
|
|
||||||
|
// Virtual timer object.
|
||||||
|
timer_t *vtimer = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Interrupt management.
|
||||||
|
//---
|
||||||
|
|
||||||
|
static inline void push_press(int keycode)
|
||||||
|
{
|
||||||
|
event_t event = {
|
||||||
|
.type = event_key_press,
|
||||||
|
.key = keycode,
|
||||||
|
};
|
||||||
|
event_push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void push_repeat(int keycode)
|
||||||
|
{
|
||||||
|
event_t event = {
|
||||||
|
.type = event_key_repeat,
|
||||||
|
.key = keycode,
|
||||||
|
};
|
||||||
|
event_push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void push_release(int keycode)
|
||||||
|
{
|
||||||
|
event_t event = {
|
||||||
|
.type = event_key_release,
|
||||||
|
.key = keycode,
|
||||||
|
};
|
||||||
|
event_push(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
keyboard_interrupt()
|
||||||
|
Callback function for keyboard update; called by the timer manager when
|
||||||
|
the keyboard's virtual timer fires. Ideally this function should be
|
||||||
|
interrupt-driven but the PINT interrupts seem to fire continuously,
|
||||||
|
which is annoying.
|
||||||
|
*/
|
||||||
|
void keyboard_interrupt(void)
|
||||||
|
{
|
||||||
|
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];
|
||||||
|
|
||||||
|
if(pressed & 1) push_press(KEY_AC_ON);
|
||||||
|
if(released & 1) push_release(KEY_AC_ON);
|
||||||
|
}
|
||||||
|
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];
|
||||||
|
keyboard_state[row] = state[row];
|
||||||
|
|
||||||
|
// Make this a bit faster.
|
||||||
|
if(!(pressed | repeated | released)) continue;
|
||||||
|
|
||||||
|
for(int column = 0; column < 8; column++)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
repeated >>= 1;
|
||||||
|
released >>= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal the interrupt to the higher-level functions.
|
||||||
|
interrupt_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//---
|
||||||
|
// Keyboard configuration.
|
||||||
|
//---
|
||||||
|
|
||||||
|
/*
|
||||||
|
keyboard_init()
|
||||||
|
Starts the keyboard timer.
|
||||||
|
*/
|
||||||
|
__attribute__((constructor)) void keyboard_init(void)
|
||||||
|
{
|
||||||
|
keyboard_setRepeatRate(625, 125);
|
||||||
|
|
||||||
|
vtimer = timer_create(25, 0);
|
||||||
|
timer_attach(vtimer, keyboard_interrupt, NULL);
|
||||||
|
timer_start(vtimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
keyboard_setAnalysisDelay()
|
||||||
|
Sets the keyboard analysis delay, that is, the delay (in ms) between
|
||||||
|
two keyboard analyzes. Please note that the repeat delays should be
|
||||||
|
multiples of the analysis delay for better accuracy.
|
||||||
|
*/
|
||||||
|
void keyboard_setAnalysisDelay(int analysis_delay_ms)
|
||||||
|
{
|
||||||
|
if(analysis_delay_ms <= 0) return;
|
||||||
|
timer_reload(vtimer, analysis_delay_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
keyboard_setRepeatRate()
|
||||||
|
Sets the default repeat rate for key events. The delay before the first
|
||||||
|
repeat may have a different value (usually longer). The unit for the
|
||||||
|
argument is ms, but the repeat events themselves may only be fired when
|
||||||
|
a keyboard analysis is performed; which means that for better accuracy,
|
||||||
|
these delays should be a multiple of the keyboard period.
|
||||||
|
For instance, delays of (625 ms, 125 ms) will imitate the system's
|
||||||
|
default setting.
|
||||||
|
*/
|
||||||
|
void keyboard_setRepeatRate(int first, int next)
|
||||||
|
{
|
||||||
|
repeat_first = (first > 0) ? first : 0;
|
||||||
|
repeat_next = (next > 0) ? next : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
keyboard_quit()
|
||||||
|
Stops the keyboard timer.
|
||||||
|
*/
|
||||||
|
__attribute__((destructor)) void keyboard_quit(void)
|
||||||
|
{
|
||||||
|
timer_destroy(vtimer);
|
||||||
|
vtimer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
keyboard_stateBuffer()
|
||||||
|
Returns the address of the keyboard state array. The returned address
|
||||||
|
is the handler's buffer, therefore it contains volatile data.
|
||||||
|
*/
|
||||||
|
volatile uint8_t *keyboard_stateBuffer(void)
|
||||||
|
{
|
||||||
|
return keyboard_state;
|
||||||
|
}
|
|
@ -1,132 +0,0 @@
|
||||||
#include <internals/keyboard.h>
|
|
||||||
#include <keyboard.h>
|
|
||||||
#include <timer.h>
|
|
||||||
#include <mpu.h>
|
|
||||||
#include <clock.h>
|
|
||||||
#include <events.h>
|
|
||||||
|
|
||||||
//---
|
|
||||||
// Keyboard variables.
|
|
||||||
//---
|
|
||||||
|
|
||||||
// These ones get modified by interrupts.
|
|
||||||
volatile uint8_t keyboard_state[10] = { 0 };
|
|
||||||
volatile int interrupt_flag = 0;
|
|
||||||
|
|
||||||
// Key statistics.
|
|
||||||
int repeat_first = 10, repeat_next = 2;
|
|
||||||
int last_key = KEY_NONE, last_repeats = 0, last_events = 0;
|
|
||||||
|
|
||||||
// RTC callback id.
|
|
||||||
unsigned cb_id;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---
|
|
||||||
// Interrupt management.
|
|
||||||
//---
|
|
||||||
|
|
||||||
static void push_press(int keycode)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
event_t event = {
|
|
||||||
.type = ET_KeyRel,
|
|
||||||
.key = keycode,
|
|
||||||
};
|
|
||||||
event_push(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
keyboard_interrupt()
|
|
||||||
Callback for keyboard update. Allows keyboard analysis functions to
|
|
||||||
wake only when keyboard interrupts happen.
|
|
||||||
*/
|
|
||||||
void keyboard_interrupt(void)
|
|
||||||
{
|
|
||||||
uint8_t state[10] = { 0 };
|
|
||||||
|
|
||||||
isSH3() ? keyboard_updateState_7705(state)
|
|
||||||
: keyboard_updateState_7305(state)
|
|
||||||
;
|
|
||||||
|
|
||||||
// Try to minimize number of operations in common cases... this 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];
|
|
||||||
|
|
||||||
if(pressed & 1) push_press(KEY_AC_ON);
|
|
||||||
if(released & 1) push_release(KEY_AC_ON);
|
|
||||||
}
|
|
||||||
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];
|
|
||||||
keyboard_state[row] = state[row];
|
|
||||||
|
|
||||||
// Fasten this a bit.
|
|
||||||
if(!(pressed | repeated | released)) continue;
|
|
||||||
|
|
||||||
for(int column = 0; column < 8; column++)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
repeated >>= 1;
|
|
||||||
released >>= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interrupt_flag = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
keyboard_init()
|
|
||||||
Starts the keyboard timer.
|
|
||||||
*/
|
|
||||||
__attribute__((constructor)) void keyboard_init(void)
|
|
||||||
{
|
|
||||||
cb_id = rtc_cb_add(RTCFreq_16Hz, keyboard_interrupt, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
keyboard_setFrequency()
|
|
||||||
Sets the keyboard frequency.
|
|
||||||
*/
|
|
||||||
void keyboard_setFrequency(enum KeyboardFrequency frequency)
|
|
||||||
{
|
|
||||||
if(frequency < 1 || frequency > 7) return;
|
|
||||||
rtc_cb_edit(cb_id, frequency, keyboard_interrupt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
keyboard_quit()
|
|
||||||
Stops the keyboard timer.
|
|
||||||
*/
|
|
||||||
__attribute__((destructor)) void keyboard_quit(void)
|
|
||||||
{
|
|
||||||
rtc_cb_end(cb_id);
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
#include <keyboard.h>
|
|
||||||
#include <internals/keyboard.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
keylast()
|
|
||||||
Returns the matrix code of the last pressed key. If repeat_count is
|
|
||||||
non-NULL, it is set to the number of repetitions.
|
|
||||||
*/
|
|
||||||
int keylast(int *repeat_count)
|
|
||||||
{
|
|
||||||
if(repeat_count) *repeat_count = last_repeats;
|
|
||||||
return last_key;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
keystate()
|
|
||||||
Returns the address of the keyboard state array. The returned address
|
|
||||||
is the handler's buffer, therefore it contains volatile data.
|
|
||||||
*/
|
|
||||||
volatile uint8_t *keystate(void)
|
|
||||||
{
|
|
||||||
return keyboard_state;
|
|
||||||
}
|
|
|
@ -10,6 +10,7 @@
|
||||||
//
|
//
|
||||||
//---
|
//---
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <keyboard.h>
|
#include <keyboard.h>
|
||||||
#include <7305.h>
|
#include <7305.h>
|
||||||
|
|
||||||
|
@ -61,20 +62,20 @@ static void kdelay(void)
|
||||||
*/
|
*/
|
||||||
static int krow(int row)
|
static int krow(int row)
|
||||||
{
|
{
|
||||||
volatile unsigned short *injector1 = (unsigned short *)0xa4050116;
|
volatile uint16_t *injector1 = (void *)0xa4050116;
|
||||||
volatile unsigned char *data1 = (unsigned char *)0xa4050136;
|
volatile uint8_t *data1 = (void *)0xa4050136;
|
||||||
|
|
||||||
volatile unsigned short *injector2 = (unsigned short *)0xa4050118;
|
volatile uint16_t *injector2 = (void *)0xa4050118;
|
||||||
volatile unsigned char *data2 = (unsigned char *)0xa4050138;
|
volatile uint8_t *data2 = (void *)0xa4050138;
|
||||||
|
|
||||||
volatile unsigned short *detector = (unsigned short *)0xa405014c;
|
volatile uint16_t *detector = (void *)0xa405014c;
|
||||||
volatile unsigned char *keys = (unsigned char *)0xa405016c;
|
volatile uint8_t *keys = (void *)0xa405016c;
|
||||||
|
|
||||||
volatile unsigned char *key_register = (unsigned char *)0xa40501c6;
|
volatile uint8_t *key_register = (void *)0xa40501c6;
|
||||||
// volatile unsigned short *hizcrb = (unsigned short *)0xa405015a;
|
// volatile uint16_t *hizcrb = (void *)0xa405015a;
|
||||||
|
|
||||||
unsigned short smask;
|
uint16_t smask;
|
||||||
unsigned char cmask;
|
uint8_t cmask;
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if(row < 0 || row > 9) return 0;
|
if(row < 0 || row > 9) return 0;
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
#include <keyboard.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
keyid()
|
|
||||||
Returns a non-matrix key code that can be used for array subscript.
|
|
||||||
Ignores modifiers.
|
|
||||||
*/
|
|
||||||
int keyid(int key)
|
|
||||||
{
|
|
||||||
if(key < 0) return -1;
|
|
||||||
key &= MOD_CLEAR;
|
|
||||||
|
|
||||||
int row = 9 - (key & 0x0f);
|
|
||||||
int column = 6 - ((key & 0xf0) >> 4);
|
|
||||||
|
|
||||||
return 6 * row + column;
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
#include <keyboard.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
keytype()
|
|
||||||
Returns a key's type. Ignores modifiers.
|
|
||||||
*/
|
|
||||||
enum KeyType keytype(int key)
|
|
||||||
{
|
|
||||||
key &= MOD_CLEAR;
|
|
||||||
|
|
||||||
if(key == KEY_UP || key == KEY_RIGHT || key == KEY_DOWN ||
|
|
||||||
key == KEY_LEFT) return KeyType_Arrow;
|
|
||||||
|
|
||||||
if((key & 0x0f) == 0x09) return KeyType_Function;
|
|
||||||
|
|
||||||
return keychar(key) ? KeyType_Character : KeyType_Control;
|
|
||||||
}
|
|
|
@ -40,7 +40,7 @@ void multigetkey(int *keys, int count, int cycles)
|
||||||
{
|
{
|
||||||
last_key = keys[0];
|
last_key = keys[0];
|
||||||
last_repeats = 0;
|
last_repeats = 0;
|
||||||
last_events = 0;
|
last_time = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(number) break;
|
if(number) break;
|
||||||
|
@ -48,7 +48,7 @@ void multigetkey(int *keys, int count, int cycles)
|
||||||
}
|
}
|
||||||
|
|
||||||
do event = pollevent();
|
do event = pollevent();
|
||||||
while(event.type != ET_None);
|
while(event.type != event_none);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
enum {
|
|
||||||
cntrl = 0x01,
|
|
||||||
space = 0x02,
|
|
||||||
punct = 0x04,
|
|
||||||
print = 0x08,
|
|
||||||
upper = 0x20,
|
|
||||||
lower = 0x10,
|
|
||||||
digit = 0x40,
|
|
||||||
xdigt = 0x80,
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t ctype_classes[0x80] = {
|
|
||||||
// Control characters.
|
|
||||||
cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl,
|
|
||||||
cntrl | space, // Tabulation
|
|
||||||
cntrl | space, cntrl | space, cntrl | space, cntrl | space,
|
|
||||||
cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl,
|
|
||||||
cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl, cntrl,
|
|
||||||
|
|
||||||
// Space and some punctuation.
|
|
||||||
space | print,
|
|
||||||
punct | print, punct | print, punct | print, punct | print,
|
|
||||||
punct | print, punct | print, punct | print, punct | print,
|
|
||||||
punct | print, punct | print, punct | print, punct | print,
|
|
||||||
punct | print, punct | print, punct | print,
|
|
||||||
|
|
||||||
// Decimal digits.
|
|
||||||
digit | xdigt | print, digit | xdigt | print, digit | xdigt | print,
|
|
||||||
digit | xdigt | print, digit | xdigt | print, digit | xdigt | print,
|
|
||||||
digit | xdigt | print, digit | xdigt | print, digit | xdigt | print,
|
|
||||||
digit | xdigt | print,
|
|
||||||
|
|
||||||
// Some punctuation.
|
|
||||||
punct | print, punct | print, punct | print, punct | print,
|
|
||||||
punct | print, punct | print, punct | print,
|
|
||||||
|
|
||||||
// Uppercase alphabet.
|
|
||||||
upper | xdigt | print, upper | xdigt | print, upper | xdigt | print,
|
|
||||||
upper | xdigt | print, upper | xdigt | print, upper | xdigt | print,
|
|
||||||
upper | print, upper | print, upper | print, upper | print,
|
|
||||||
upper | print, upper | print, upper | print, upper | print,
|
|
||||||
upper | print, upper | print, upper | print, upper | print,
|
|
||||||
upper | print, upper | print, upper | print, upper | print,
|
|
||||||
upper | print, upper | print, upper | print, upper | print,
|
|
||||||
|
|
||||||
// Other punctuation symbols.
|
|
||||||
punct | print, punct | print, punct | print, punct | print,
|
|
||||||
punct | print, punct | print,
|
|
||||||
|
|
||||||
// Lowercase alphabet.
|
|
||||||
lower | xdigt | print, lower | xdigt | print, lower | xdigt | print,
|
|
||||||
lower | xdigt | print, lower | xdigt | print, lower | xdigt | print,
|
|
||||||
lower | print, lower | print, lower | print, lower | print,
|
|
||||||
lower | print, lower | print, lower | print, lower | print,
|
|
||||||
lower | print, lower | print, lower | print, lower | print,
|
|
||||||
lower | print, lower | print, lower | print, lower | print,
|
|
||||||
lower | print, lower | print, lower | print, lower | print,
|
|
||||||
|
|
||||||
// Last punctuation characters and DEL.
|
|
||||||
punct | print, punct | print, punct | print, punct | print,
|
|
||||||
cntrl
|
|
||||||
};
|
|
|
@ -5,11 +5,11 @@
|
||||||
text_configure()
|
text_configure()
|
||||||
Sets the font and mode to use for the following print operations.
|
Sets the font and mode to use for the following print operations.
|
||||||
*/
|
*/
|
||||||
void text_configure(struct Font *next_font, enum Color next_color)
|
void text_configure(struct Font *next_font, color_t next_operator)
|
||||||
{
|
{
|
||||||
extern Font gint_font_system;
|
extern Font gint_font_system;
|
||||||
if(next_font) font = next_font;
|
if(next_font) font = next_font;
|
||||||
else font = &gint_font_system;
|
else font = &gint_font_system;
|
||||||
|
|
||||||
color = next_color;
|
operator = next_operator;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,42 +4,61 @@
|
||||||
|
|
||||||
void operate_gray(OPERATE_ARGS)
|
void operate_gray(OPERATE_ARGS)
|
||||||
{
|
{
|
||||||
int *vl = gray_lightVRAM();
|
size_t vram_offset = (x >> 5) + (y << 2);
|
||||||
int *vd = gray_darkVRAM();
|
uint32_t *light = gray_lightVRAM() + vram_offset;
|
||||||
int vram_offset = (x >> 5) + (y << 2);
|
uint32_t *dark = gray_darkVRAM() + vram_offset;
|
||||||
uint32_t op;
|
uint32_t op, old_light;
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < height; i++)
|
for(int i = 0; i < height; i++)
|
||||||
{
|
{
|
||||||
op = operators[i];
|
op = operators[i];
|
||||||
|
|
||||||
switch(color)
|
switch(operator)
|
||||||
{
|
{
|
||||||
case Color_White:
|
case color_white:
|
||||||
vl[vram_offset] &= ~op;
|
*light &= ~op;
|
||||||
vd[vram_offset] &= ~op;
|
*dark &= ~op;
|
||||||
break;
|
break;
|
||||||
case Color_Light:
|
case color_light:
|
||||||
vl[vram_offset] |= op;
|
*light |= op;
|
||||||
vd[vram_offset] &= ~op;
|
*dark &= ~op;
|
||||||
break;
|
break;
|
||||||
case Color_Dark:
|
case color_dark:
|
||||||
vl[vram_offset] &= ~op;
|
*light &= ~op;
|
||||||
vd[vram_offset] |= op;
|
*dark |= op;
|
||||||
break;
|
break;
|
||||||
case Color_Black:
|
case color_black:
|
||||||
vl[vram_offset] |= op;
|
*light |= op;
|
||||||
vd[vram_offset] |= op;
|
*dark |= op;
|
||||||
break;
|
break;
|
||||||
case Color_Invert:
|
case color_none:
|
||||||
vl[vram_offset] ^= op;
|
return;
|
||||||
vd[vram_offset] ^= op;
|
|
||||||
|
case color_invert:
|
||||||
|
*light ^= op;
|
||||||
|
*dark ^= op;
|
||||||
break;
|
break;
|
||||||
default:
|
case color_lighten:
|
||||||
|
old_light = *light;
|
||||||
|
*light &= *dark | ~op;
|
||||||
|
*dark = (old_light | ~op) & (op ^ *dark);
|
||||||
|
break;
|
||||||
|
case color_lighten2:
|
||||||
|
*dark &= *light | ~op;
|
||||||
|
*light &= ~op;
|
||||||
|
break;
|
||||||
|
case color_darken:
|
||||||
|
old_light = *light;
|
||||||
|
*light |= *dark & op;
|
||||||
|
*dark = (old_light & op) | (op ^ *dark);
|
||||||
|
break;
|
||||||
|
case color_darken2:
|
||||||
|
*dark |= *light | op;
|
||||||
|
*light |= op;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
vram_offset += 4;
|
light += 4;
|
||||||
|
dark += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <gray.h>
|
#include <gray.h>
|
||||||
|
|
||||||
struct Font *font;
|
struct Font *font;
|
||||||
enum Color color;
|
color_t operator;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
tales_init()
|
tales_init()
|
||||||
|
@ -13,7 +13,7 @@ enum Color color;
|
||||||
*/
|
*/
|
||||||
void tales_init(void)
|
void tales_init(void)
|
||||||
{
|
{
|
||||||
text_configure(NULL, Color_Black);
|
text_configure(NULL, color_black);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -93,31 +93,36 @@ int getCharacterIndex(int c)
|
||||||
*/
|
*/
|
||||||
void operate_mono(OPERATE_ARGS)
|
void operate_mono(OPERATE_ARGS)
|
||||||
{
|
{
|
||||||
int *vram = display_getCurrentVRAM();
|
uint32_t *vram = display_getCurrentVRAM();
|
||||||
int vram_offset = (x >> 5) + (y << 2);
|
uint32_t *video = vram + (x >> 5) + (y << 2);
|
||||||
uint32_t op;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for(i = 0; i < height; i++)
|
switch(operator)
|
||||||
{
|
{
|
||||||
op = operators[i];
|
case color_white:
|
||||||
|
for(int i = 0; i < height; i++)
|
||||||
switch(color)
|
|
||||||
{
|
{
|
||||||
case Color_White:
|
*video &= ~operators[i];
|
||||||
vram[vram_offset] &= ~op;
|
video += 4;
|
||||||
break;
|
|
||||||
case Color_Black:
|
|
||||||
vram[vram_offset] |= op;
|
|
||||||
break;
|
|
||||||
case Color_Invert:
|
|
||||||
vram[vram_offset] ^= op;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
vram_offset += 4;
|
case color_black:
|
||||||
|
for(int i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
*video |= operators[i];
|
||||||
|
video += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case color_invert:
|
||||||
|
for(int i = 0; i < height; i++)
|
||||||
|
{
|
||||||
|
*video ^= operators[i];
|
||||||
|
video += 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ void timer_callback_event(timer_t *timer)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
event_t event = {
|
event_t event = {
|
||||||
.type = ET_Timer,
|
.type = event_timer_underflow,
|
||||||
.timer = timer
|
.timer = timer
|
||||||
};
|
};
|
||||||
event_push(event);
|
event_push(event);
|
||||||
|
|
|
@ -38,6 +38,24 @@ timer_t *timer_create(int ms_delay, int repeats)
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
timer_reload()
|
||||||
|
Changes a virtual timer's delay. The timer is not stopped nor started:
|
||||||
|
it keeps running or waiting. Events that were waiting to be handled are
|
||||||
|
dropped and the number of repeats left is not changed. The timer
|
||||||
|
restarts counting from 0 regardless of how much time had elapsed since
|
||||||
|
it last fired.
|
||||||
|
*/
|
||||||
|
void timer_reload(timer_t *timer, int new_ms_delay)
|
||||||
|
{
|
||||||
|
if(!timer->virtual) return;
|
||||||
|
|
||||||
|
timer->ms_delay = new_ms_delay;
|
||||||
|
timer->ms_elapsed = 0;
|
||||||
|
|
||||||
|
vtimer_updateAll();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
timer_destroy()
|
timer_destroy()
|
||||||
Destroys a virtual timer. This virtual timer pointer becomes invalid
|
Destroys a virtual timer. This virtual timer pointer becomes invalid
|
||||||
|
@ -136,7 +154,7 @@ static void vtimer_update(int new_delay)
|
||||||
timer_stop(timer);
|
timer_stop(timer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32_t new_constant = clock_setting(new_delay, Clock_ms);
|
uint32_t new_constant = clock_setting(new_delay, clock_ms);
|
||||||
|
|
||||||
// The transition needs to be as smooth as possible. We have probably
|
// The transition needs to be as smooth as possible. We have probably
|
||||||
// spent a lot of time calculating this new GCD delay so we want to
|
// spent a lot of time calculating this new GCD delay so we want to
|
||||||
|
@ -176,7 +194,7 @@ static void vtimer_update(int new_delay)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
gcd()
|
gcd()
|
||||||
Well, the Euclidean algorithm. That's a O(ln(a)) & O(ln(b)) FWIW.
|
Well, the Euclidean algorithm. That's O(ln(max(a, b))) FWIW.
|
||||||
*/
|
*/
|
||||||
static int gcd(int a, int b)
|
static int gcd(int a, int b)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue