mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-28 04:23:36 +01:00
Some quality review. Made keyboard time milliseconds.
This commit is contained in:
parent
31e2b453dd
commit
a6e312a39c
79 changed files with 1482 additions and 1175 deletions
2
Makefile
2
Makefile
|
@ -13,7 +13,7 @@ include Makefile.cfg
|
|||
# Modules
|
||||
modules-gint = bopti clock core display events gray keyboard mmu rtc \
|
||||
screen tales timer
|
||||
modules-libc = setjmp stdio stdlib string time
|
||||
modules-libc = ctype setjmp stdio stdlib string time
|
||||
|
||||
# Targets
|
||||
target-lib = libgint.a
|
||||
|
|
4
TODO
4
TODO
|
@ -23,8 +23,8 @@ Larger improvements:
|
|||
* core: Allow return to menu
|
||||
- serial: Implement a driver
|
||||
- usb: Implement a driver
|
||||
- esper: Cleaner playback, synthetizing
|
||||
- clock: Handle overclocking (relaunch clocks when overclocking)
|
||||
- esper: Cleaner playback, synthesizing
|
||||
- clock: Handle overclock (relaunch clocks when overclocking)
|
||||
- project: Unify this hellish mess of register access!
|
||||
|
||||
Things to investigate:
|
||||
|
|
|
@ -288,7 +288,7 @@ void main_menu(int *category, int *app)
|
|||
// Quite a few things to declare...
|
||||
//---
|
||||
|
||||
extern Image res_opt_menu;
|
||||
extern image_t res_opt_menu;
|
||||
|
||||
const char *mpu, *mpu_names[] = {
|
||||
"Unknown",
|
||||
|
@ -332,7 +332,7 @@ void main_menu(int *category, int *app)
|
|||
int i;
|
||||
|
||||
mpu = mpu_names[MPU_CURRENT < 5 ? MPU_CURRENT : 5];
|
||||
text_configure(NULL, Color_Black);
|
||||
text_configure(NULL, color_black);
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
@ -386,8 +386,8 @@ void main_menu(int *category, int *app)
|
|||
if(scroll > 0) locate(20, 2, "\x0d");
|
||||
if(scroll + 6 < list_len) locate(20, 7, "\x0e");
|
||||
|
||||
dreverse_area(0, 8 * (index - scroll) + 8, 127,
|
||||
8 * (index - scroll) + 15);
|
||||
drect(0, 8 * (index - scroll) + 8, 127,
|
||||
8 * (index - scroll) + 15, color_invert);
|
||||
}
|
||||
|
||||
dupdate();
|
||||
|
@ -495,8 +495,6 @@ int main(void)
|
|||
{
|
||||
int category, app;
|
||||
|
||||
sleep_ms(2000);
|
||||
|
||||
while(1)
|
||||
{
|
||||
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;
|
||||
|
||||
|
@ -42,7 +42,7 @@ static void getwh(Image *img, int *width, int *height)
|
|||
*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;
|
||||
|
||||
|
@ -51,10 +51,10 @@ static void getxy(Image *img, int *x, int *y)
|
|||
*y = 28 - (height >> 1);
|
||||
}
|
||||
|
||||
static Image *select(Image *current)
|
||||
static image_t *select(image_t *current)
|
||||
{
|
||||
extern Image res_bopti_thumbs;
|
||||
extern Image
|
||||
extern image_t res_bopti_thumbs;
|
||||
extern image_t
|
||||
res_items,
|
||||
res_sprites,
|
||||
res_swords,
|
||||
|
@ -62,7 +62,7 @@ static Image *select(Image *current)
|
|||
res_isometric;
|
||||
|
||||
struct {
|
||||
Image *img;
|
||||
image_t *img;
|
||||
const char *name;
|
||||
const char *info;
|
||||
} images[] = {
|
||||
|
@ -74,7 +74,7 @@ static Image *select(Image *current)
|
|||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
Image *thumbs = &res_bopti_thumbs;
|
||||
image_t *thumbs = &res_bopti_thumbs;
|
||||
int items = 0;
|
||||
static int row = 0;
|
||||
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();
|
||||
|
||||
do
|
||||
|
@ -138,8 +138,8 @@ static Image *select(Image *current)
|
|||
|
||||
void test_bopti(void)
|
||||
{
|
||||
extern Image res_opt_bitmap;
|
||||
Image *img = NULL;
|
||||
extern image_t res_opt_bitmap;
|
||||
image_t *img = NULL;
|
||||
|
||||
int leave = 1;
|
||||
int black_bg = 0;
|
||||
|
@ -152,10 +152,10 @@ void test_bopti(void)
|
|||
gray_start();
|
||||
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);
|
||||
|
||||
gclear_area(0, 55, 127, 63);
|
||||
grect(0, 55, 127, 63, color_white);
|
||||
gimage(0, 56, &res_opt_bitmap);
|
||||
gupdate();
|
||||
}
|
||||
|
@ -164,10 +164,10 @@ void test_bopti(void)
|
|||
gray_stop();
|
||||
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);
|
||||
|
||||
dclear_area(0, 55, 127, 63);
|
||||
drect(0, 55, 127, 63, color_white);
|
||||
dimage(0, 56, &res_opt_bitmap);
|
||||
dupdate();
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
|
||||
static void draw(int delay1, int delay2, int selected)
|
||||
{
|
||||
extern Image res_opt_gray;
|
||||
unsigned int *vl = gray_lightVRAM();
|
||||
unsigned int *vd = gray_darkVRAM();
|
||||
extern image_t res_opt_gray;
|
||||
uint32_t *vl = gray_lightVRAM();
|
||||
uint32_t *vd = gray_darkVRAM();
|
||||
|
||||
gclear();
|
||||
locate(1, 1, "Gray engine");
|
||||
|
@ -58,7 +58,7 @@ void test_gray(void)
|
|||
}
|
||||
changed = 0;
|
||||
|
||||
key = getkey_opt(Getkey_RepeatArrowKeys, 1);
|
||||
key = getkey_opt(getkey_repeat_arrow_keys, 25);
|
||||
if(key == KEY_EXIT) break;
|
||||
|
||||
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++)
|
||||
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.
|
||||
else
|
||||
{
|
||||
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.
|
||||
dpixel(28, 19, Color_Black); dpixel(29, 19, Color_Black);
|
||||
dpixel(28, 24, Color_Black); dpixel(29, 24, Color_Black);
|
||||
dpixel(26, 21, Color_Black); dpixel(26, 22, Color_Black);
|
||||
dpixel(31, 21, Color_Black); dpixel(31, 22, Color_Black);
|
||||
dpixel(28, 19, color_black); dpixel(29, 19, color_black);
|
||||
dpixel(28, 24, color_black); dpixel(29, 24, color_black);
|
||||
dpixel(26, 21, color_black); dpixel(26, 22, color_black);
|
||||
dpixel(31, 21, color_black); dpixel(31, 22, color_black);
|
||||
|
||||
// An horizontal line to separate parts of the keyboard.
|
||||
dline(5, 28, 32, 28, Color_Black);
|
||||
dline(5, 28, 32, 28, color_black);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
|
@ -64,7 +64,7 @@ static void push_history(enhanced_event_t *history, int size, event_t event)
|
|||
|
||||
// Determining where the history ends.
|
||||
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.
|
||||
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"
|
||||
};
|
||||
|
||||
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],
|
||||
key_names[keyid(history[i].key)]);
|
||||
key_names[key_id(history[i].key)]);
|
||||
if(history[i].repeats > 1)
|
||||
print(19, 3 + i, "%d", history[i].repeats);
|
||||
}
|
||||
|
@ -124,18 +124,19 @@ void test_keyboard_events(void)
|
|||
int history_size = 5;
|
||||
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)
|
||||
{
|
||||
dclear();
|
||||
locate(1, 1, "Keyboard and events");
|
||||
draw_keyboard(keystate());
|
||||
draw_keyboard(keyboard_stateBuffer());
|
||||
draw_events(history, history_size);
|
||||
dupdate();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
static void draw(rtc_time_t time)
|
||||
{
|
||||
extern Image res_rtc_segments;
|
||||
extern image_t res_rtc_segments;
|
||||
|
||||
const char *days[7] = {
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
|
@ -42,7 +42,7 @@ static void draw(rtc_time_t time)
|
|||
12 * digits[i], 0, 11, 19);
|
||||
// Drawing ':' between pairs of digits.
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
extern Image res_opt_rtc;
|
||||
extern image_t res_opt_rtc;
|
||||
rtc_time_t time = rtc_getTime();
|
||||
|
||||
dclear();
|
||||
|
@ -115,8 +115,8 @@ static void set_region(rtc_time_t *time, int region, int value)
|
|||
|
||||
static void set(void)
|
||||
{
|
||||
extern Image res_opt_rtc;
|
||||
Image *opt = &res_opt_rtc;
|
||||
extern image_t res_opt_rtc;
|
||||
image_t *opt = &res_opt_rtc;
|
||||
|
||||
struct {
|
||||
int x, y;
|
||||
|
@ -136,8 +136,8 @@ static void set(void)
|
|||
{
|
||||
dclear();
|
||||
draw(time);
|
||||
dreverse_area(regions[n].x, regions[n].y, regions[n].x
|
||||
+ regions[n].w - 1, regions[n].y + regions[n].h - 1);
|
||||
drect(regions[n].x, regions[n].y, regions[n].x + regions[n].w
|
||||
- 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 == 7) dimage_part(0, 56, opt, 0, 9 * (3 + slide), 128, 8);
|
||||
|
@ -191,9 +191,9 @@ static void set(void)
|
|||
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;
|
||||
|
||||
if(n == 0) ok = (val <= 2);
|
||||
|
|
|
@ -27,7 +27,7 @@ static Font *select(Font *current)
|
|||
|
||||
while(1)
|
||||
{
|
||||
text_configure(NULL, Color_Black);
|
||||
text_configure(NULL, color_black);
|
||||
|
||||
dclear();
|
||||
locate(1, 1, "Select a font:");
|
||||
|
@ -39,18 +39,18 @@ static Font *select(Font *current)
|
|||
int height = fonts[i].font->line_height;
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
text_configure(NULL, Color_Black);
|
||||
text_configure(NULL, color_black);
|
||||
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();
|
||||
|
||||
do
|
||||
|
@ -80,9 +80,9 @@ static Font *select(Font *current)
|
|||
|
||||
void test_tales(void)
|
||||
{
|
||||
enum Color colors[] = { Color_Black, Color_Dark, Color_Light,
|
||||
Color_White, Color_Invert };
|
||||
extern Image res_opt_tales;
|
||||
color_t colors[] = { color_black, color_dark, color_light, color_white,
|
||||
color_invert };
|
||||
extern image_t res_opt_tales;
|
||||
Font *font = NULL;
|
||||
|
||||
int black_bg = 0;
|
||||
|
@ -94,7 +94,7 @@ void test_tales(void)
|
|||
while(1)
|
||||
{
|
||||
gclear();
|
||||
if(black_bg) greverse_area(0, 0, 127, 54);
|
||||
if(black_bg) grect(0, 0, 127, 54, color_invert);
|
||||
|
||||
if(font)
|
||||
{
|
||||
|
@ -119,10 +119,10 @@ void test_tales(void)
|
|||
gimage(0, 56, &res_opt_tales);
|
||||
|
||||
x = 45 + 8 * color;
|
||||
gline(x, 57, x + 5, 57, Color_Black);
|
||||
gline(x, 57, x, 62, Color_Black);
|
||||
gline(x + 5, 57, x + 5, 62, Color_Black);
|
||||
gline(x, 62, x + 5, 62, Color_Black);
|
||||
gline(x, 57, x + 5, 57, color_black);
|
||||
gline(x, 57, x, 62, color_black);
|
||||
gline(x + 5, 57, x + 5, 62, color_black);
|
||||
gline(x, 62, x + 5, 62, color_black);
|
||||
|
||||
gupdate();
|
||||
|
||||
|
@ -146,7 +146,7 @@ void test_tales(void)
|
|||
|
||||
case KEY_EXIT:
|
||||
gray_stop();
|
||||
text_configure(NULL, Color_Black);
|
||||
text_configure(NULL, color_black);
|
||||
return;
|
||||
default:
|
||||
leave = 0;
|
||||
|
|
|
@ -36,7 +36,7 @@ static void timing_timer(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);
|
||||
timer_attach(htimer, timing_timer, NULL);
|
||||
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)
|
||||
{
|
||||
extern Image res_clock_chars;
|
||||
Image *chars = &res_clock_chars;
|
||||
extern image_t res_clock_chars;
|
||||
image_t *chars = &res_clock_chars;
|
||||
const char *table = "0123456789kMHz*/";
|
||||
|
||||
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)
|
||||
{
|
||||
extern Image res_opt_timer;
|
||||
extern Image res_clock_7705;
|
||||
extern Image res_clock_7305;
|
||||
extern image_t res_opt_timer;
|
||||
extern image_t res_clock_7705;
|
||||
extern image_t res_clock_7305;
|
||||
|
||||
char buffer[16];
|
||||
|
||||
|
@ -163,14 +163,14 @@ static void draw(int tab)
|
|||
small_text(84, 34, buffer, 1);
|
||||
|
||||
if(conf.Iphi_div1 == 1)
|
||||
dline(85, 43, 99, 43, Color_Black);
|
||||
dline(85, 43, 99, 43, color_black);
|
||||
else
|
||||
{
|
||||
sprintf(buffer, "/%d", conf.Iphi_div1);
|
||||
small_text(89, 41, buffer, 0);
|
||||
}
|
||||
if(conf.Pphi_div1 == 1)
|
||||
dline(85, 50, 99, 50, Color_Black);
|
||||
dline(85, 50, 99, 50, color_black);
|
||||
else
|
||||
{
|
||||
sprintf(buffer, "/%d", conf.Pphi_div1);
|
||||
|
@ -249,13 +249,13 @@ void test_timer(void)
|
|||
elapsed_rtc = -1;
|
||||
cb_id = rtc_cb_add(RTCFreq_64Hz, timing_start, 0);
|
||||
|
||||
text_configure(NULL, Color_Black);
|
||||
text_configure(NULL, color_black);
|
||||
|
||||
while(1)
|
||||
{
|
||||
draw(tab);
|
||||
|
||||
switch(getkey_opt(Getkey_NoOption, 1))
|
||||
switch(getkey_opt(getkey_none, 25))
|
||||
{
|
||||
case KEY_EXIT:
|
||||
rtc_cb_end(cb_id);
|
||||
|
|
|
@ -3,12 +3,14 @@
|
|||
// standard library module: alloca
|
||||
//
|
||||
// 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
|
||||
#define _ALLOCA_H 1
|
||||
#define _ALLOCA_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
|
||||
//
|
||||
// Measures the frequency of the MPU clocks. This module assumes that the
|
||||
// clock mode is 3 on SH7305 (as does FTune).
|
||||
// This module interfaces with the MPU clocks and is used to measure the
|
||||
// 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()
|
||||
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);
|
||||
|
||||
|
@ -41,17 +52,29 @@ void sleep_us(int us_delay);
|
|||
// 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_ms = 1,
|
||||
Clock_s = 2,
|
||||
clock_us = 0,
|
||||
clock_ms = 1,
|
||||
clock_s = 2,
|
||||
|
||||
Clock_Hz = 10,
|
||||
Clock_kHz = 11,
|
||||
Clock_MHz = 12,
|
||||
};
|
||||
clock_Hz = 10,
|
||||
clock_kHz = 11,
|
||||
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
|
||||
{
|
||||
union
|
||||
|
@ -75,9 +98,9 @@ typedef struct
|
|||
int RTCCLK_f; // SH7305
|
||||
};
|
||||
|
||||
int Bphi_f;
|
||||
int Iphi_f;
|
||||
int Pphi_f;
|
||||
int Bphi_f; // Bus clock frequency
|
||||
int Iphi_f; // Processor clock frequency
|
||||
int Pphi_f; // Peripheral clock frequency
|
||||
|
||||
} clock_config_t;
|
||||
|
||||
|
@ -86,10 +109,8 @@ typedef struct
|
|||
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
|
||||
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()
|
||||
|
|
|
@ -7,78 +7,29 @@
|
|||
//---
|
||||
|
||||
#ifndef _CTYPE_H
|
||||
#define _CTYPE_H 1
|
||||
#define _CTYPE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//---
|
||||
// Character classes.
|
||||
//---
|
||||
|
||||
extern uint8_t ctype_classes[0x80];
|
||||
|
||||
__attribute__((always_inline)) static inline int isalnum(int c) {
|
||||
return ctype_classes[c] & 0xf0;
|
||||
}
|
||||
// Character classes.
|
||||
#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) {
|
||||
return ctype_classes[c] & 0x30;
|
||||
}
|
||||
|
||||
__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);
|
||||
}
|
||||
// Character manipulation.
|
||||
#define tolower(c) ((c) | isupper(c))
|
||||
#define toupper(c) ((c) & ~(islower(c) << 1))
|
||||
|
||||
#endif // _CTYPE_H
|
||||
|
|
|
@ -2,94 +2,107 @@
|
|||
//
|
||||
// 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
|
||||
#define _DISPLAY_H 1
|
||||
#define _DISPLAY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
//---
|
||||
// Heading declarations.
|
||||
// Drawing-related types and constants.
|
||||
//---
|
||||
|
||||
enum Color
|
||||
{
|
||||
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>
|
||||
#define DWIDTH 128 /* Width of the screen */
|
||||
#define DHEIGHT 64 /* Height of the screen */
|
||||
|
||||
/*
|
||||
struct Image
|
||||
This structure holds information about a bitmap encoded with fxconv.
|
||||
Data is accessed using longword operations, which *requires* many
|
||||
sizes to be multiples of 4 (structure alignment, data alignment, layer
|
||||
size, ...).
|
||||
color_t
|
||||
Defines all colors that the library knows about:
|
||||
- white is exactly what you think it is;
|
||||
- light is a light gray used by the gray module;
|
||||
- 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;
|
||||
uint8_t format;
|
||||
color_white = 0,
|
||||
color_light = 1,
|
||||
color_dark = 2,
|
||||
color_black = 3,
|
||||
color_none = 4,
|
||||
|
||||
uint8_t width;
|
||||
uint8_t height;
|
||||
color_invert = 5,
|
||||
color_lighten = 6,
|
||||
color_lighten2 = 7,
|
||||
color_darken = 8,
|
||||
color_darken2 = 9,
|
||||
|
||||
const uint32_t data[];
|
||||
} color_t;
|
||||
|
||||
} __attribute__((packed, aligned(4)));
|
||||
// Useful shorthand for user code.
|
||||
typedef struct Image Image;
|
||||
// The bopti module provides bitmap rendering functions.
|
||||
#include <bopti.h>
|
||||
|
||||
|
||||
|
||||
// A few other constants.
|
||||
#define DISPLAY_WIDTH 128
|
||||
#define DISPLAY_HEIGHT 64
|
||||
// The tales module provides text rendering functions but requires the color_t
|
||||
// type definition.
|
||||
#include <tales.h>
|
||||
|
||||
|
||||
|
||||
//---
|
||||
// Generic functions.
|
||||
// Video RAM management.
|
||||
//---
|
||||
|
||||
/*
|
||||
display_getLocalVRAM()
|
||||
Returns the local video ram address. This function always return the
|
||||
same address.
|
||||
The buffer returned by this function should not be used directly when
|
||||
running the gray engine.
|
||||
Returns gint's local video RAM address. Gint does not use the system's
|
||||
buffer because it is misaligned. This function always returns the same
|
||||
address. Both the display and the gray module heavily use this buffer;
|
||||
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()
|
||||
Returns the current video ram. This function usually returns the
|
||||
parameter of the last call to display_useVRAM(), unless the gray engine
|
||||
is running (in which case the result is undefined). Returns the local
|
||||
vram address by default.
|
||||
Returns the current monochrome video ram buffer. This function usually
|
||||
returns the parameter of the last call to display_useVRAM(), or the
|
||||
local vram address (which is default when the library starts).
|
||||
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()
|
||||
Changes the current video ram address. The argument MUST be a 4-
|
||||
aligned 1024-byte buffer; otherwise any drawing operation will crash
|
||||
the program.
|
||||
Changes the current monochrome video ram address. The argument must be
|
||||
a 4-aligned 1024-byte buffer because the library's design requires it.
|
||||
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
|
||||
engine.
|
||||
*/
|
||||
void display_useVRAM(void *vram);
|
||||
void display_useVRAM(uint32_t *vram);
|
||||
|
||||
|
||||
|
||||
|
@ -99,30 +112,24 @@ void display_useVRAM(void *vram);
|
|||
|
||||
/*
|
||||
dupdate()
|
||||
Displays the vram on the physical screen. Does nothing when the gray
|
||||
engine is running.
|
||||
Pushes the video RAM to the physical screen. This function also works
|
||||
when the gray engine is running, but that's probably not what you want.
|
||||
*/
|
||||
void dupdate(void);
|
||||
|
||||
/*
|
||||
dclear()
|
||||
Clears the whole video ram.
|
||||
Clears the whole video ram, making all pixels white.
|
||||
*/
|
||||
void dclear(void);
|
||||
|
||||
/*
|
||||
dclear_area()
|
||||
Clears an area of the video ram. Both (x1, y1) and (x2, y2) are
|
||||
cleared.
|
||||
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.
|
||||
Both end points (x1, y1) and (x2, y2) are affected as well.
|
||||
*/
|
||||
void dclear_area(int x1, int y1, int x2, int y2);
|
||||
|
||||
/*
|
||||
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);
|
||||
void drect(int x1, int y1, int x2, int y2, color_t operator);
|
||||
|
||||
|
||||
|
||||
|
@ -132,9 +139,10 @@ void dreverse_area(int x1, int y1, int x2, int y2);
|
|||
|
||||
/*
|
||||
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()
|
||||
|
@ -143,22 +151,6 @@ void dpixel(int x, int y, enum Color color);
|
|||
|
||||
Uses an algorithm written by PierrotLL for MonochromeLib.
|
||||
*/
|
||||
void dline(int x1, int y1, int x2, int y2, enum Color color);
|
||||
|
||||
/*
|
||||
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);
|
||||
void dline(int x1, int y1, int x2, int y2, color_t operator);
|
||||
|
||||
#endif // _DISPLAY_H
|
||||
|
|
|
@ -2,7 +2,17 @@
|
|||
//
|
||||
// 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
|
||||
{
|
||||
EventType_None = 0,
|
||||
ET_None = EventType_None,
|
||||
// Specific events.
|
||||
event_none = 0,
|
||||
event_user = 1,
|
||||
|
||||
EventType_User = 1,
|
||||
ET_User = EventType_User,
|
||||
// Keyboard events.
|
||||
event_key_press = 2,
|
||||
event_key_repeat = 3,
|
||||
event_key_release = 4,
|
||||
|
||||
EventType_KeyPressed = 2,
|
||||
ET_KeyPress = EventType_KeyPressed,
|
||||
|
||||
EventType_KeyRepeated = 3,
|
||||
ET_KeyRepeat = EventType_KeyRepeated,
|
||||
|
||||
EventType_KeyReleased = 4,
|
||||
ET_KeyRel = EventType_KeyReleased,
|
||||
|
||||
EventType_TimerUnderflow = 5,
|
||||
ET_Timer = EventType_TimerUnderflow,
|
||||
// Other events.
|
||||
event_timer_underflow = 5,
|
||||
|
||||
} event_type_t;
|
||||
|
||||
/*
|
||||
event_t
|
||||
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
|
||||
{
|
||||
|
@ -48,11 +52,11 @@ typedef struct
|
|||
|
||||
union
|
||||
{
|
||||
// For ET_User.
|
||||
// For event_user.
|
||||
void *data;
|
||||
// For ET_KeyPress, ET_KeyRepeat and ET_KeyRel.
|
||||
// For event_key_press, event_key_repeat and event_key_release.
|
||||
int key;
|
||||
// For ET_Timer.
|
||||
// For event_timer_underflow.
|
||||
timer_t *timer;
|
||||
};
|
||||
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
//
|
||||
// gint core module: interrupt handler
|
||||
//
|
||||
// Central point of the library. Controls the interrupt handler and
|
||||
// defines a few functions to configure callbacks for some interrupts.
|
||||
// This module is the core of the gint library. It controls the interrupt
|
||||
// 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
|
||||
#define _GRAY_H 1
|
||||
#define _GRAY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <display.h>
|
||||
|
||||
// This module provides bitmap rendering.
|
||||
#include <bopti.h>
|
||||
|
||||
//---
|
||||
// Engine control.
|
||||
//---
|
||||
|
@ -39,13 +43,13 @@ void gray_stop(void);
|
|||
gray_lightVRAM()
|
||||
Returns the module's light gray vram address.
|
||||
*/
|
||||
void *gray_lightVRAM(void);
|
||||
uint32_t *gray_lightVRAM(void);
|
||||
|
||||
/*
|
||||
gray_darkVRAM()
|
||||
Returns the module's dark gray vram address.
|
||||
*/
|
||||
void *gray_darkVRAM(void);
|
||||
uint32_t *gray_darkVRAM(void);
|
||||
|
||||
/*
|
||||
gray_getDelays()
|
||||
|
@ -81,29 +85,26 @@ void gray_setDelays(int light, int dark);
|
|||
|
||||
/*
|
||||
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);
|
||||
|
||||
/*
|
||||
gclear()
|
||||
Clears the video ram.
|
||||
Clears the gray video ram, making all pixels white.
|
||||
*/
|
||||
void gclear(void);
|
||||
|
||||
/*
|
||||
gclear_area()
|
||||
Clears an area of the video ram. End points (x1, y1) and (x2, y2) are
|
||||
included.
|
||||
grect()
|
||||
Draws a rectangle in the gray video ram; this function accepts all
|
||||
values of the color_t type, including gray operators.
|
||||
*/
|
||||
void gclear_area(int x1, int y1, int x2, int y2);
|
||||
|
||||
/*
|
||||
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);
|
||||
void grect(int x1, int y1, int x2, int y2, color_t operator);
|
||||
|
||||
|
||||
|
||||
|
@ -113,29 +114,18 @@ void greverse_area(int x1, int y1, int x2, int y2);
|
|||
|
||||
/*
|
||||
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()
|
||||
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);
|
||||
|
||||
/*
|
||||
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);
|
||||
void gline(int x1, int y1, int x2, int y2, color_t operator);
|
||||
|
||||
#endif // _GRAY_H
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _INTERNALS_BOPTI_H
|
||||
#define _INTERNALS_BOPTI_H 1
|
||||
#define _INTERNALS_BOPTI_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <display.h>
|
||||
|
@ -86,7 +86,7 @@ struct Command
|
|||
// The video ram addresses are set by the public functions and used internally
|
||||
// by the module.
|
||||
// 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()
|
||||
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
|
||||
|
|
|
@ -1,47 +1,40 @@
|
|||
//---
|
||||
//
|
||||
// gint drawing module: display
|
||||
//
|
||||
// Handles vram manipulation and drawing.
|
||||
//
|
||||
//---
|
||||
|
||||
#ifndef _INTERNALS_DISPLAY_H
|
||||
#define _INTERNALS_DISPLAY_H 1
|
||||
#define _INTERNALS_DISPLAY_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
extern int *vram;
|
||||
extern uint32_t *vram;
|
||||
|
||||
//---
|
||||
// Rectangle masks.
|
||||
//
|
||||
// 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
|
||||
// the same on all its lines. Therefore the behavior of the operation is
|
||||
// determined by its behavior on a single line, which is represented using
|
||||
// 'masks' whose bits indicate whether a pixel is affected (1) or not (0).
|
||||
// It relies on the fact that operations affecting a rectangle act the
|
||||
// same for all lines, and line operation is very optimized. A rectangle
|
||||
// mask is a set of integers, where each bit indicate whether a specific
|
||||
// pixel is affected (1) by the operation, or not (0).
|
||||
//
|
||||
// For example when clearing the screen rectangle (16, 16, 112, 48), the
|
||||
// masks will represent information '16 to 112 on x-axis', and will hold
|
||||
// the following values : 0000ffff, ffffffff, ffffffff and ffff0000. These
|
||||
// masks can then be used by setting vram[offset] &= ~masks[i]. This
|
||||
// appears to be very flexible : for instance, vram[offset] ^= masks[i]
|
||||
// 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.
|
||||
// For example to clear a rectangle such as (14, 16, 112, 48), the masks
|
||||
// will need to hold 0003ffff ffffffff ffffffff ffff0000. Bitwise-
|
||||
// combining them with video ram long entries yields very good performance
|
||||
// as compared to operation on single pixels. Each bitwise operation will
|
||||
// produce different results, which is very flexible.
|
||||
//
|
||||
// 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()
|
||||
Adjusts the given rectangle coordinates to ensure that :
|
||||
- the rectangle is entirely contained in the screen
|
||||
- x1 < x2
|
||||
- y1 < y2
|
||||
which is needed when working with screen rectangles.
|
||||
Returns non-zero if the rectangle is outside the screen.
|
||||
- the rectangle is entirely contained in the screen;
|
||||
- x1 < x2;
|
||||
- y1 < y2,
|
||||
which is needed when working with screen rectangles. Returns non-zero
|
||||
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);
|
||||
|
||||
|
@ -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
|
||||
(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
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#ifndef _INTERNALS_GINT_H
|
||||
#define _INTERNALS_GINT_H 1
|
||||
#define _INTERNALS_GINT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <gint.h>
|
||||
|
||||
//---
|
||||
// Interrupt handlers
|
||||
// Interrupt handlers.
|
||||
//---
|
||||
|
||||
// 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
|
||||
upset by gint's configuration when the application ends.
|
||||
*/
|
||||
//void gint_save_7705(gint_save_buffer_t *buffer);
|
||||
//void gint_save_7305(gint_save_buffer_t *buffer);
|
||||
// void gint_save_7705(gint_save_buffer_t *buffer);
|
||||
// void gint_save_7305(gint_save_buffer_t *buffer);
|
||||
|
||||
/*
|
||||
gint_setup()
|
||||
|
@ -74,8 +74,8 @@ void gint_setup_7305(void);
|
|||
Restores the parameters saved in a save buffer to give back the
|
||||
interrupt control to the system.
|
||||
*/
|
||||
//void gint_restore_7705(gint_save_buffer_t *buffer);
|
||||
//void gint_restore_7305(gint_save_buffer_t *buffer);
|
||||
// void gint_restore_7705(gint_save_buffer_t *buffer);
|
||||
// void gint_restore_7305(gint_save_buffer_t *buffer);
|
||||
|
||||
/*
|
||||
gint_reg()
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#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
|
||||
|
||||
#include <keyboard.h>
|
||||
#include <timer.h>
|
||||
#include <clock.h>
|
||||
|
||||
// Keyboard variables.
|
||||
|
@ -10,10 +11,10 @@ extern volatile int interrupt_flag;
|
|||
|
||||
// Key statistics.
|
||||
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.
|
||||
extern unsigned cb_id;
|
||||
// Virtual timer object.
|
||||
extern timer_t *vtimer;
|
||||
|
||||
/*
|
||||
getPressedKey()
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
//
|
||||
//---
|
||||
|
||||
#ifndef _MMU_H
|
||||
#define _MMU_H 1
|
||||
#ifndef _INTERNALS_MMU_H
|
||||
#define _INTERNALS_MMU_H
|
||||
|
||||
/*
|
||||
mmu_pseudoTLBInit()
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _INTERNALS_STDIO_H
|
||||
#define _INTERNALS_STDIO_H 1
|
||||
#define _INTERNALS_STDIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef _INTERNALS_TALES_H
|
||||
#define _INTERNALS_TALES_H 1
|
||||
#define _INTERNALS_TALES_H
|
||||
|
||||
#include <tales.h>
|
||||
#include <stdint.h>
|
||||
|
@ -7,13 +7,14 @@
|
|||
#define OPERATE_ARGS uint32_t *operators, int height, int x, int y
|
||||
|
||||
extern struct Font *font;
|
||||
extern enum Color color;
|
||||
extern color_t operator;
|
||||
|
||||
/*
|
||||
tales_init()
|
||||
Configures tales with the default font (which is part of gint).
|
||||
*/
|
||||
void tales_init(void) __attribute__((constructor));
|
||||
__attribute__((constructor))
|
||||
void tales_init(void);
|
||||
|
||||
/*
|
||||
getCharacterIndex()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef _INTERNALS_TIME_H
|
||||
#define _INTERNALS_TIME_H 1
|
||||
#define _INTERNALS_TIME_H
|
||||
|
||||
/*
|
||||
isLeap()
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _KEYBOARD_H
|
||||
#define _KEYBOARD_H 1
|
||||
#define _KEYBOARD_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <rtc.h>
|
||||
|
@ -20,92 +20,87 @@
|
|||
// 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
|
||||
Possible values for the keyboard frequency.
|
||||
key_t
|
||||
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,
|
||||
KeyboardFreq_1Hz = RTCFreq_1Hz,
|
||||
KeyboardFreq_2Hz = RTCFreq_2Hz,
|
||||
KeyboardFreq_4Hz = RTCFreq_4Hz,
|
||||
KeyboardFreq_16Hz = RTCFreq_16Hz,
|
||||
KeyboardFreq_64Hz = RTCFreq_64Hz,
|
||||
KeyboardFreq_256Hz = RTCFreq_256Hz,
|
||||
};
|
||||
// Special events codes.
|
||||
KEY_NONE = 0x00,
|
||||
KEY_NOEVENT = 0xff,
|
||||
|
||||
// Key modifiers.
|
||||
MOD_SHIFT = 0x80,
|
||||
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()
|
||||
Sets the keyboard frequency. The default frequency is 16 Hz. Very few
|
||||
applications will need to change this setting.
|
||||
At low frequencies, you will miss key hits. At high frequencies, you
|
||||
may lose execution power.
|
||||
keyboard_setAnalysisDelay()
|
||||
Sets the keyboard analysis delay, that is, the delay (in ms) between
|
||||
two keyboard analyzes. If a key is pressed then released in the lapse
|
||||
between two analyzes, the program won't notice anything. On the other
|
||||
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()
|
||||
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 the keyboard period. For example at 32 Hz, values of
|
||||
(20, 4) will imitate the system default.
|
||||
Set to 0 to disable repetition. If first = 0, no repetition will be
|
||||
allowed. If first != 0 and next = 0, only one repetition will be
|
||||
allowed.
|
||||
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. The keyboard
|
||||
period may be changed by calling keyboard_setAnalysisDelay().
|
||||
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);
|
||||
|
||||
|
@ -141,57 +144,74 @@ void keyboard_setRepeatRate(int first, int next);
|
|||
//---
|
||||
|
||||
/*
|
||||
enum GetKeyOpt
|
||||
Options available for use with getkey_opt().
|
||||
getkey_opt_t
|
||||
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
|
||||
// KEY_SHIFT and KEY_ALPHA.
|
||||
Getkey_ShiftModifier = 0x01,
|
||||
Getkey_AlphaModifier = 0x02,
|
||||
// Consider [SHIFT] and [ALPHA] as modifiers. Returns key identifiers
|
||||
// with MOD_SHIFT and MOD_ALPHA flags instead of returning KEY_SHIFT
|
||||
// and KEY_ALPHA.
|
||||
getkey_shift_modifier = 0x01,
|
||||
getkey_alpha_modifier = 0x02,
|
||||
|
||||
// Allow changing the backlight status on [SHIFT] + [OPTN].
|
||||
Getkey_ManageBacklight = 0x04,
|
||||
// Allow changing the backlight status on [SHIFT] + [OPTN] on
|
||||
// compatible models.
|
||||
getkey_manage_backlight = 0x04,
|
||||
|
||||
// Key repetition. Notice that modifiers will never be repeated.
|
||||
Getkey_RepeatArrowKeys = 0x10,
|
||||
Getkey_RepeatCharKeys = 0x20,
|
||||
Getkey_RepeatCtrlKeys = 0x40,
|
||||
Getkey_RepeatFuncKeys = 0x80,
|
||||
// Allow key repetition. This option does not control the generation of
|
||||
// repeat events (use keyboard_setRepeatRate() for this) but filters
|
||||
// them. Please note that modifiers will never be repeated, even when
|
||||
// pressed continuously.
|
||||
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.
|
||||
Getkey_RepeatAllKeys = 0xf0,
|
||||
};
|
||||
getkey_repeat_all_keys = 0xf0,
|
||||
|
||||
} getkey_option_t;
|
||||
|
||||
/*
|
||||
getkey()
|
||||
Blocking function with auto-repeat and SHIFT modifying functionalities.
|
||||
Reproduces the behavior of the system's GetKey(). Returns the matrix
|
||||
code with a possible MOD_SHIFT bit.
|
||||
Blocking function with auto-repeat that heeds for the SHIFT and ALPHA
|
||||
modifiers. In short, this function reproduces the behavior of the
|
||||
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);
|
||||
|
||||
/*
|
||||
getkey_opt()
|
||||
Enhances getkey() with most general functionalities. An OR-combination
|
||||
of options may be given as first argument.
|
||||
If max_cycles is non-zero and positive, getkey_opt() will return
|
||||
KEY_NOEVENT if no event occurs during max_cycle analyzes.
|
||||
Enhances getkey() with more general functionalities. An OR-combination
|
||||
of options of type getkey_option_t may be given as first argument.
|
||||
If delay is non-zero and positive, getkey_opt() will return KEY_NOEVENT
|
||||
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
|
||||
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()
|
||||
|
||||
Listens the keyboard for simultaneous key hits. This functions fills
|
||||
array `keys` with `count` keycodes, adding KEY_NONE at the end if
|
||||
less than `count` keys are pressed.
|
||||
If `max_cycles` is non-zero and nothing happens after `max_cycles`
|
||||
cycles, this function returns an array of KEY_NONE.
|
||||
the 'keys' array with 'count' keycodes, padding with KEY_NONE values at
|
||||
the end if less that 'count' keys are detected.
|
||||
If 'delay_ms' is positive and nothing happens during this delay, this
|
||||
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:
|
||||
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.
|
||||
With three keys or more, column effects (on SH4) and rectangle effects
|
||||
(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
|
||||
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
|
||||
ideal multi-key analyzer.
|
||||
*/
|
||||
void multigetkey(int *keys, int count, int max_cycles);
|
||||
void multigetkey(int *keys, int count, int delay_ms);
|
||||
|
||||
/*
|
||||
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);
|
||||
keyboard_stateBuffer()
|
||||
|
||||
/*
|
||||
keystate()
|
||||
Returns the address of the keyboard state array. The keyboard state
|
||||
consists in 10 bytes, in which every key is represented as a bit.
|
||||
The returned address is the original buffer address. You should avoid
|
||||
editing the array. It wouldn't influence the behavior of the keyboard
|
||||
functions, but the buffer data is very volatile. Therefore, data
|
||||
written to the buffer could be replaced anytime.
|
||||
functions, but the buffer data is very volatile and any data written to
|
||||
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.
|
||||
//---
|
||||
|
||||
enum KeyType
|
||||
{
|
||||
KeyType_Arrow = 1,
|
||||
KeyType_Character = 2,
|
||||
KeyType_Control = 4,
|
||||
KeyType_Function = 8,
|
||||
};
|
||||
|
||||
/*
|
||||
keyid()
|
||||
Returns a non-matrix key code that can be used for array subscript.
|
||||
Ignores modifiers.
|
||||
Transforms a key identifier and returns a key code that is more
|
||||
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()
|
||||
Returns the ASCII character associated with a character key; 0 for
|
||||
other keys.
|
||||
key_char()
|
||||
Returns the ASCII character associated with a character key, and 0 for
|
||||
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()
|
||||
Returns a key's type. Ignores modifiers.
|
||||
key_type_t
|
||||
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
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _MPU_H
|
||||
#define _MPU_H 1
|
||||
#define _MPU_H
|
||||
|
||||
/*
|
||||
mpu_t
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _RTC_H
|
||||
#define _RTC_H 1
|
||||
#define _RTC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _SCREEN_H
|
||||
#define _SCREEN_H 1
|
||||
#define _SCREEN_H
|
||||
|
||||
/*
|
||||
screen_display()
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _SETJMP_H
|
||||
#define _SETJMP_H 1
|
||||
#define _SETJMP_H
|
||||
|
||||
// There are 16 CPU registers that *must* be saved to ensure a basically
|
||||
// safe jump.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _STDIO_H
|
||||
#define _STDIO_H 1
|
||||
#define _STDIO_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _STDLIB_H
|
||||
#define _STDLIB_H 1
|
||||
#define _STDLIB_H
|
||||
|
||||
//---
|
||||
// Common definitions.
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _STRING_H
|
||||
#define _STRING_H 1
|
||||
#define _STRING_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _TALES_H
|
||||
#define _TALES_H 1
|
||||
#define _TALES_H
|
||||
|
||||
#include <display.h>
|
||||
#include <stdint.h>
|
||||
|
@ -95,7 +95,7 @@ typedef struct Font Font;
|
|||
Sets the font and color to use for subsequent text operations. Pass
|
||||
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()
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _TIME_H
|
||||
#define _TIME_H 1
|
||||
#define _TIME_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//---
|
||||
|
||||
#ifndef _TIMER_H
|
||||
#define _TIMER_H 1
|
||||
#define _TIMER_H
|
||||
|
||||
#include <clock.h>
|
||||
#include <stdint.h>
|
||||
|
@ -49,6 +49,16 @@ typedef struct timer_t timer_t;
|
|||
*/
|
||||
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()
|
||||
Destroys a virtual timer. This virtual timer pointer becomes invalid
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include <internals/bopti.h>
|
||||
|
||||
// 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()
|
||||
|
@ -285,7 +285,7 @@ void bopti(const unsigned char *layer, struct Structure *s, struct Command *c)
|
|||
getStructure()
|
||||
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;
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
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)
|
||||
void dimage_part(int x, int y, image_t *img, int left, int top, int width,
|
||||
int height)
|
||||
{
|
||||
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()
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
Point (left, top) is included, but (left + width, top + height) is
|
||||
excluded.
|
||||
*/
|
||||
void gimage_part(int x, int y, struct Image *img, int left, int top,
|
||||
int width, int height)
|
||||
void gimage_part(int x, int y, image_t *img, int left, int top, int width,
|
||||
int height)
|
||||
{
|
||||
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()
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ static clock_config_t conf = {
|
|||
Several units can be used. Be aware that the result is approximate, and
|
||||
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;
|
||||
uint64_t f = conf.Pphi_f >> 2;
|
||||
|
@ -27,23 +27,23 @@ uint32_t clock_setting(int duration, enum ClockUnit unit)
|
|||
|
||||
switch(unit)
|
||||
{
|
||||
case Clock_us:
|
||||
case clock_us:
|
||||
result = (duration * f) / 1000000;
|
||||
break;
|
||||
case Clock_ms:
|
||||
case clock_ms:
|
||||
result = (duration * f) / 1000;
|
||||
break;
|
||||
case Clock_s:
|
||||
case clock_s:
|
||||
result = (duration * f);
|
||||
break;
|
||||
|
||||
case Clock_Hz:
|
||||
case clock_Hz:
|
||||
result = f / duration;
|
||||
break;
|
||||
case Clock_kHz:
|
||||
case clock_kHz:
|
||||
result = f / (duration * 1000);
|
||||
break;
|
||||
case Clock_MHz:
|
||||
case clock_MHz:
|
||||
result = f / (duration * 1000000);
|
||||
break;
|
||||
|
||||
|
@ -103,7 +103,7 @@ void sleep_ms(int ms_delay)
|
|||
void sleep_us(int us_delay)
|
||||
{
|
||||
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_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));
|
||||
|
||||
dclear();
|
||||
text_configure(NULL, Color_Black);
|
||||
text_configure(NULL, color_black);
|
||||
|
||||
print(3, 1, "EXCEPTION RAISED!");
|
||||
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()
|
||||
Clears the whole vram.
|
||||
Clears the whole vram, making all pixels white.
|
||||
*/
|
||||
void dclear(void)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < 256; i++) vram[i] = 0;
|
||||
// I tend to use pre-decrement more than post-increment.
|
||||
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>
|
||||
|
||||
// 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.
|
||||
static int local_vram[256];
|
||||
int *vram = local_vram;
|
||||
static uint32_t local_vram[256];
|
||||
uint32_t *vram = local_vram;
|
||||
|
||||
/*
|
||||
display_getLocalVRAM()
|
||||
Returns the local video ram address. This function always return the
|
||||
same address.
|
||||
The buffer returned by this function should not be used directly when
|
||||
running the gray engine.
|
||||
Returns gint's local video RAM address. Gint does not use the system's
|
||||
buffer because it is misaligned. This function always returns the same
|
||||
address. Both the display and the gray module heavily use this buffer;
|
||||
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()
|
||||
Returns the current video ram. This function usually returns the
|
||||
parameter of the last call to display_useVRAM(), unless the gray engine
|
||||
is running (in which case the result is undefined). Returns the local
|
||||
vram address by default.
|
||||
Returns the current monochrome video ram buffer. This function usually
|
||||
returns the parameter of the last call to display_useVRAM(), or the
|
||||
local vram address (which is default when the library starts).
|
||||
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()
|
||||
Changes the current video ram address. The argument MUST be a 4-
|
||||
aligned 1024-byte buffer ; otherwise any drawing operation will crash
|
||||
the program.
|
||||
Changes the current monochrome video ram address. The argument must be
|
||||
a 4-aligned 1024-byte buffer because the library's design requires it.
|
||||
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
|
||||
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 <display.h>
|
||||
|
||||
#define sgn(x) ((x) < 0 ? -1 : 1)
|
||||
#define abs(x) ((x) < 0 ? -(x) : (x))
|
||||
#define rnd(x) ((int)((x) + 0.5))
|
||||
|
||||
/*
|
||||
dline()
|
||||
Draws a line on the screen. Automatically optimizes horizontal and
|
||||
vertical lines.
|
||||
dhline()
|
||||
Optimized procedure for drawing an horizontal line. Uses a rectangle
|
||||
mask.
|
||||
*/
|
||||
|
||||
static void dhline(int x1, int x2, int y, enum Color color)
|
||||
static void dhline(size_t x1, size_t x2, int y, color_t operator)
|
||||
{
|
||||
uint32_t masks[4];
|
||||
int offset = y << 2;
|
||||
int i;
|
||||
uint32_t *video = vram + (y << 2) + 4;
|
||||
|
||||
// Swapping x1 and x2 if needed.
|
||||
if(x1 > x2) x1 ^= x2, x2 ^= x1, x1 ^= x2;
|
||||
getMasks(x1, x2, masks);
|
||||
|
||||
switch(color)
|
||||
switch(operator)
|
||||
{
|
||||
case Color_White:
|
||||
for(i = 0; i < 4; i++) vram[offset + i] &= ~masks[i];
|
||||
case color_white:
|
||||
*--video &= ~masks[3];
|
||||
*--video &= ~masks[2];
|
||||
*--video &= ~masks[1];
|
||||
*--video &= ~masks[0];
|
||||
break;
|
||||
|
||||
case Color_Black:
|
||||
for(i = 0; i < 4; i++) vram[offset + i] |= masks[i];
|
||||
case color_black:
|
||||
*--video |= masks[3];
|
||||
*--video |= masks[2];
|
||||
*--video |= masks[1];
|
||||
*--video |= masks[0];
|
||||
break;
|
||||
|
||||
case Color_Invert:
|
||||
for(i = 0; i < 4; i++) vram[offset + i] ^= masks[i];
|
||||
case color_invert:
|
||||
*--video ^= masks[3];
|
||||
*--video ^= masks[2];
|
||||
*--video ^= masks[1];
|
||||
*--video ^= masks[0];
|
||||
break;
|
||||
|
||||
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);
|
||||
int end = (y2 << 2) + (x >> 5);
|
||||
int mask = 0x80000000 >> (x & 31);
|
||||
uint32_t *base = vram + (y1 << 2) + (x >> 5);
|
||||
uint32_t *video = vram + (y2 << 2) + (x >> 5) + 4;
|
||||
uint32_t mask = 0x80000000 >> (x & 31);
|
||||
|
||||
switch(color)
|
||||
switch(operator)
|
||||
{
|
||||
case Color_White:
|
||||
while(offset <= end) vram[offset] &= ~mask, offset += 4;
|
||||
case color_white:
|
||||
while(video > base) video -= 4, *video &= ~mask;
|
||||
break;
|
||||
|
||||
case Color_Black:
|
||||
while(offset <= end) vram[offset] |= mask, offset += 4;
|
||||
case color_black:
|
||||
while(video > base) video -= 4, *video |= mask;
|
||||
break;
|
||||
|
||||
case Color_Invert:
|
||||
while(offset <= end) vram[offset] ^= mask, offset += 4;
|
||||
case color_invert:
|
||||
while(video > base) video -= 4, *video ^= mask;
|
||||
break;
|
||||
|
||||
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;
|
||||
|
||||
// Possible optimizations.
|
||||
if(y1 == y2)
|
||||
{
|
||||
dhline(x1, x2, y1, color);
|
||||
dhline(x1, x2, y1, operator);
|
||||
return;
|
||||
}
|
||||
if(x1 == x2)
|
||||
{
|
||||
dvline(y1, y2, x1, color);
|
||||
dvline(y1, y2, x1, operator);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -87,7 +105,7 @@ void dline(int x1, int y1, int x2, int y2, enum Color color)
|
|||
|
||||
dx = abs(dx), dy = abs(dy);
|
||||
|
||||
dpixel(x1, y1, color);
|
||||
dpixel(x1, y1, operator);
|
||||
|
||||
if(dx >= dy)
|
||||
{
|
||||
|
@ -97,7 +115,7 @@ void dline(int x1, int y1, int x2, int y2, enum Color color)
|
|||
x += sx;
|
||||
cumul += dy;
|
||||
if(cumul > dx) cumul -= dx, y += sy;
|
||||
dpixel(x, y, color);
|
||||
dpixel(x, y, operator);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -108,9 +126,9 @@ void dline(int x1, int y1, int x2, int y2, enum Color color)
|
|||
y += sy;
|
||||
cumul += dx;
|
||||
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()
|
||||
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);
|
||||
int mask = 0x80000000 >> (x & 31);
|
||||
uint32_t *video = vram + (y << 2) + (x >> 5);
|
||||
uint32_t mask = 0x80000000 >> (x & 31);
|
||||
|
||||
switch(color)
|
||||
switch(operator)
|
||||
{
|
||||
case Color_White:
|
||||
vram[offset] &= ~mask;
|
||||
break;
|
||||
|
||||
case Color_Black:
|
||||
vram[offset] |= mask;
|
||||
break;
|
||||
|
||||
case Color_Invert:
|
||||
vram[offset] ^= mask;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
case color_white: *video &= ~mask; break;
|
||||
case color_black: *video |= mask; break;
|
||||
case color_invert: *video ^= mask; break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
|
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
|
||||
(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.
|
||||
int l1 = x1 >> 5;
|
||||
int l2 = x2 >> 5;
|
||||
int i = 0;
|
||||
// Indexes of the first and last longs that are not empty.
|
||||
size_t l1 = x1 >> 5;
|
||||
size_t l2 = x2 >> 5;
|
||||
size_t i = 0;
|
||||
|
||||
// Setting the base masks. Those are the final values, except for the
|
||||
// longs with indexes l1 and l2, that still need to be adjusted.
|
||||
while(i < l1) masks[i++] = 0x00000000;
|
||||
while(i <= l2) masks[i++] = 0xffffffff;
|
||||
while(i < 4) masks[i++] = 0x00000000;
|
||||
// longs between indexes l1 and l2, that still need to be adjusted.
|
||||
while(i < l1) masks[i++] = 0x00000000;
|
||||
while(i <= l2) masks[i++] = 0xffffffff;
|
||||
while(i < 4) masks[i++] = 0x00000000;
|
||||
|
||||
// Removing the long number information in x1 and x2 (that is, the
|
||||
// multiples of 32) to keep only the interesting information -- the
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
event_t pollevent(void)
|
||||
{
|
||||
event_t event = {
|
||||
.type = ET_None
|
||||
.type = event_none,
|
||||
};
|
||||
if(queue_size <= 0) return event;
|
||||
|
||||
|
@ -33,6 +33,6 @@ event_t waitevent(void)
|
|||
{
|
||||
event_t event;
|
||||
|
||||
while((event = pollevent()).type == ET_None) sleep();
|
||||
while((event = pollevent()).type == event_none) sleep();
|
||||
return event;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ volatile int queue_size = 0;
|
|||
int event_push(event_t event)
|
||||
{
|
||||
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;
|
||||
if(index >= EVENTS_QUEUE_SIZE) index -= EVENTS_QUEUE_SIZE;
|
||||
|
|
|
@ -6,9 +6,28 @@
|
|||
*/
|
||||
void gclear(void)
|
||||
{
|
||||
int *v1 = gray_lightVRAM();
|
||||
int *v2 = gray_darkVRAM();
|
||||
int i;
|
||||
uint32_t *lbase = gray_lightVRAM();
|
||||
uint32_t *v1 = lbase + 256;
|
||||
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()
|
||||
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;
|
||||
else if(color == Color_Invert) c1 = c2 = Color_Invert;
|
||||
if(operator == color_invert) op1 = op2 = color_invert;
|
||||
else if(operator >= color_none) return;
|
||||
else
|
||||
{
|
||||
c1 = 3 * (color & 1);
|
||||
c2 = 3 * (color >> 1);
|
||||
op1 = 3 * (operator & 1);
|
||||
op2 = 3 * (operator >> 1);
|
||||
}
|
||||
|
||||
display_useVRAM(gray_lightVRAM());
|
||||
dline(x1, y1, x2, y2, c1);
|
||||
dline(x1, y1, x2, y2, op1);
|
||||
display_useVRAM(gray_darkVRAM());
|
||||
dline(x1, y1, x2, y2, c2);
|
||||
dline(x1, y1, x2, y2, op2);
|
||||
}
|
||||
|
|
|
@ -4,44 +4,56 @@
|
|||
gpixel()
|
||||
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);
|
||||
int mask = 0x80000000 >> (x & 31);
|
||||
uint32_t *light = gray_lightVRAM() + (y << 2) + (x >> 5);
|
||||
uint32_t *dark = gray_darkVRAM() + (y << 2) + (x >> 5);
|
||||
uint32_t mask = 0x80000000 >> (x & 31);
|
||||
|
||||
int *v1 = gray_lightVRAM();
|
||||
int *v2 = gray_lightVRAM();
|
||||
|
||||
switch(color)
|
||||
switch(operator)
|
||||
{
|
||||
case Color_White:
|
||||
v1[offset] &= ~mask;
|
||||
v2[offset] &= ~mask;
|
||||
case color_white:
|
||||
*light &= ~mask;
|
||||
*dark &= ~mask;
|
||||
break;
|
||||
|
||||
case Color_Light:
|
||||
v1[offset] |= mask;
|
||||
v2[offset] &= ~mask;
|
||||
case color_light:
|
||||
*light |= mask;
|
||||
*dark &= ~mask;
|
||||
break;
|
||||
|
||||
case Color_Dark:
|
||||
v1[offset] &= ~mask;
|
||||
v2[offset] |= mask;
|
||||
case color_dark:
|
||||
*light &= ~mask;
|
||||
*dark |= mask;
|
||||
break;
|
||||
|
||||
case Color_Black:
|
||||
v1[offset] |= mask;
|
||||
v2[offset] |= mask;
|
||||
case color_black:
|
||||
*light |= mask;
|
||||
*dark |= mask;
|
||||
break;
|
||||
case color_none:
|
||||
return;
|
||||
|
||||
case Color_Invert:
|
||||
v1[offset] ^= mask;
|
||||
v2[offset] ^= mask;
|
||||
case color_invert:
|
||||
*light ^= mask;
|
||||
*dark ^= mask;
|
||||
break;
|
||||
|
||||
default:
|
||||
case color_lighten:;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#include <timer.h>
|
||||
#include <mpu.h>
|
||||
|
||||
static int internal_vrams[3][256];
|
||||
static const void *vrams[4];
|
||||
static uint32_t internal_vrams[3][256];
|
||||
static uint32_t *vrams[4];
|
||||
|
||||
static int current = 0;
|
||||
static int delays[2];
|
||||
|
@ -45,10 +45,10 @@ void gray_interrupt(void)
|
|||
*/
|
||||
__attribute__((constructor)) void gray_init(void)
|
||||
{
|
||||
vrams[0] = (const void *)display_getLocalVRAM();
|
||||
vrams[1] = (const void *)internal_vrams[0];
|
||||
vrams[2] = (const void *)internal_vrams[1];
|
||||
vrams[3] = (const void *)internal_vrams[2];
|
||||
vrams[0] = display_getLocalVRAM();
|
||||
vrams[1] = internal_vrams[0];
|
||||
vrams[2] = internal_vrams[1];
|
||||
vrams[3] = internal_vrams[2];
|
||||
|
||||
delays[0] = 912;
|
||||
delays[1] = 1343;
|
||||
|
@ -119,18 +119,18 @@ inline int gray_runs(void)
|
|||
gray_lightVRAM()
|
||||
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()
|
||||
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/timer.h>
|
||||
#include <keyboard.h>
|
||||
#include <events.h>
|
||||
#include <screen.h>
|
||||
|
@ -11,10 +12,11 @@
|
|||
int getkey(void)
|
||||
{
|
||||
return getkey_opt(
|
||||
Getkey_ShiftModifier |
|
||||
Getkey_AlphaModifier |
|
||||
Getkey_ManageBacklight |
|
||||
Getkey_RepeatArrowKeys,
|
||||
getkey_shift_modifier |
|
||||
getkey_alpha_modifier |
|
||||
getkey_manage_backlight |
|
||||
getkey_repeat_arrow_keys,
|
||||
|
||||
0
|
||||
);
|
||||
}
|
||||
|
@ -22,101 +24,92 @@ int getkey(void)
|
|||
/*
|
||||
getkey_opt()
|
||||
Enhances getkey() with more general functionalities.
|
||||
If max_cycles is non-zero and positive, getkey_opt() will return
|
||||
KEY_NOEVENT if no event occurs during max_cycle analysis.
|
||||
If delay_ms is non-zero and positive, getkey_opt() will return
|
||||
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();
|
||||
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;
|
||||
int modifier = 0;
|
||||
static int event_ref = 0;
|
||||
int modifier = 0, key;
|
||||
key_type_t type;
|
||||
|
||||
if(cycles <= 0) cycles = -1;
|
||||
while(cycles != 0)
|
||||
if(delay_ms <= 0) delay_ms = -1;
|
||||
|
||||
while(delay_ms != 0) switch((event = pollevent()).type)
|
||||
{
|
||||
event = pollevent();
|
||||
switch(event.type)
|
||||
case event_none:
|
||||
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:
|
||||
if(last_key == KEY_NONE)
|
||||
{
|
||||
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;
|
||||
screen_toggleBacklight();
|
||||
modifier &= ~MOD_SHIFT;
|
||||
continue;
|
||||
}
|
||||
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_repeats = 0;
|
||||
last_events = 0;
|
||||
event_ref = 0;
|
||||
last_time = 0;
|
||||
return KEY_NONE;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#include <keyboard.h>
|
||||
|
||||
/*
|
||||
keychar()
|
||||
Returns the ASCII character associated with a key, or 0 for control
|
||||
keys.
|
||||
key_char()
|
||||
Returns the ASCII character associated with a character key, and 0 for
|
||||
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[] = {
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
|
@ -30,7 +31,6 @@ int keychar(int key)
|
|||
'Z', ' ', '"', 0x0, 0x0, 0x0
|
||||
};
|
||||
|
||||
int id = keyid(key);
|
||||
|
||||
return (key & MOD_ALPHA) ? alpha[id] : flat[id];
|
||||
int id = key_id(matrix_key);
|
||||
return (matrix_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 <7305.h>
|
||||
|
||||
|
@ -61,20 +62,20 @@ static void kdelay(void)
|
|||
*/
|
||||
static int krow(int row)
|
||||
{
|
||||
volatile unsigned short *injector1 = (unsigned short *)0xa4050116;
|
||||
volatile unsigned char *data1 = (unsigned char *)0xa4050136;
|
||||
volatile uint16_t *injector1 = (void *)0xa4050116;
|
||||
volatile uint8_t *data1 = (void *)0xa4050136;
|
||||
|
||||
volatile unsigned short *injector2 = (unsigned short *)0xa4050118;
|
||||
volatile unsigned char *data2 = (unsigned char *)0xa4050138;
|
||||
volatile uint16_t *injector2 = (void *)0xa4050118;
|
||||
volatile uint8_t *data2 = (void *)0xa4050138;
|
||||
|
||||
volatile unsigned short *detector = (unsigned short *)0xa405014c;
|
||||
volatile unsigned char *keys = (unsigned char *)0xa405016c;
|
||||
volatile uint16_t *detector = (void *)0xa405014c;
|
||||
volatile uint8_t *keys = (void *)0xa405016c;
|
||||
|
||||
volatile unsigned char *key_register = (unsigned char *)0xa40501c6;
|
||||
// volatile unsigned short *hizcrb = (unsigned short *)0xa405015a;
|
||||
volatile uint8_t *key_register = (void *)0xa40501c6;
|
||||
// volatile uint16_t *hizcrb = (void *)0xa405015a;
|
||||
|
||||
unsigned short smask;
|
||||
unsigned char cmask;
|
||||
uint16_t smask;
|
||||
uint8_t cmask;
|
||||
int result = 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_repeats = 0;
|
||||
last_events = 0;
|
||||
last_time = 0;
|
||||
}
|
||||
|
||||
if(number) break;
|
||||
|
@ -48,7 +48,7 @@ void multigetkey(int *keys, int count, int cycles)
|
|||
}
|
||||
|
||||
do event = pollevent();
|
||||
while(event.type != ET_None);
|
||||
while(event.type != event_none);
|
||||
|
||||
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()
|
||||
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;
|
||||
if(next_font) font = next_font;
|
||||
else font = &gint_font_system;
|
||||
|
||||
color = next_color;
|
||||
operator = next_operator;
|
||||
}
|
||||
|
|
|
@ -4,42 +4,61 @@
|
|||
|
||||
void operate_gray(OPERATE_ARGS)
|
||||
{
|
||||
int *vl = gray_lightVRAM();
|
||||
int *vd = gray_darkVRAM();
|
||||
int vram_offset = (x >> 5) + (y << 2);
|
||||
uint32_t op;
|
||||
int i;
|
||||
size_t vram_offset = (x >> 5) + (y << 2);
|
||||
uint32_t *light = gray_lightVRAM() + vram_offset;
|
||||
uint32_t *dark = gray_darkVRAM() + vram_offset;
|
||||
uint32_t op, old_light;
|
||||
|
||||
for(i = 0; i < height; i++)
|
||||
for(int i = 0; i < height; i++)
|
||||
{
|
||||
op = operators[i];
|
||||
|
||||
switch(color)
|
||||
switch(operator)
|
||||
{
|
||||
case Color_White:
|
||||
vl[vram_offset] &= ~op;
|
||||
vd[vram_offset] &= ~op;
|
||||
case color_white:
|
||||
*light &= ~op;
|
||||
*dark &= ~op;
|
||||
break;
|
||||
case Color_Light:
|
||||
vl[vram_offset] |= op;
|
||||
vd[vram_offset] &= ~op;
|
||||
case color_light:
|
||||
*light |= op;
|
||||
*dark &= ~op;
|
||||
break;
|
||||
case Color_Dark:
|
||||
vl[vram_offset] &= ~op;
|
||||
vd[vram_offset] |= op;
|
||||
case color_dark:
|
||||
*light &= ~op;
|
||||
*dark |= op;
|
||||
break;
|
||||
case Color_Black:
|
||||
vl[vram_offset] |= op;
|
||||
vd[vram_offset] |= op;
|
||||
case color_black:
|
||||
*light |= op;
|
||||
*dark |= op;
|
||||
break;
|
||||
case Color_Invert:
|
||||
vl[vram_offset] ^= op;
|
||||
vd[vram_offset] ^= op;
|
||||
case color_none:
|
||||
return;
|
||||
|
||||
case color_invert:
|
||||
*light ^= op;
|
||||
*dark ^= op;
|
||||
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;
|
||||
}
|
||||
|
||||
vram_offset += 4;
|
||||
light += 4;
|
||||
dark += 4;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <gray.h>
|
||||
|
||||
struct Font *font;
|
||||
enum Color color;
|
||||
color_t operator;
|
||||
|
||||
/*
|
||||
tales_init()
|
||||
|
@ -13,7 +13,7 @@ enum Color color;
|
|||
*/
|
||||
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)
|
||||
{
|
||||
int *vram = display_getCurrentVRAM();
|
||||
int vram_offset = (x >> 5) + (y << 2);
|
||||
uint32_t op;
|
||||
int i;
|
||||
uint32_t *vram = display_getCurrentVRAM();
|
||||
uint32_t *video = vram + (x >> 5) + (y << 2);
|
||||
|
||||
for(i = 0; i < height; i++)
|
||||
switch(operator)
|
||||
{
|
||||
op = operators[i];
|
||||
|
||||
switch(color)
|
||||
case color_white:
|
||||
for(int i = 0; i < height; i++)
|
||||
{
|
||||
case Color_White:
|
||||
vram[vram_offset] &= ~op;
|
||||
break;
|
||||
case Color_Black:
|
||||
vram[vram_offset] |= op;
|
||||
break;
|
||||
case Color_Invert:
|
||||
vram[vram_offset] ^= op;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
*video &= ~operators[i];
|
||||
video += 4;
|
||||
}
|
||||
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
|
||||
{
|
||||
event_t event = {
|
||||
.type = ET_Timer,
|
||||
.type = event_timer_underflow,
|
||||
.timer = timer
|
||||
};
|
||||
event_push(event);
|
||||
|
|
|
@ -38,6 +38,24 @@ timer_t *timer_create(int ms_delay, int repeats)
|
|||
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()
|
||||
Destroys a virtual timer. This virtual timer pointer becomes invalid
|
||||
|
@ -136,7 +154,7 @@ static void vtimer_update(int new_delay)
|
|||
timer_stop(timer);
|
||||
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
|
||||
// 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()
|
||||
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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue