diff --git a/app/Makefile b/app/Makefile index a47967991..fba1326d1 100644 --- a/app/Makefile +++ b/app/Makefile @@ -1,4 +1,6 @@ -app_objs += $(addprefix app/, app.o) +app_objs += $(addprefix app/,\ + app.o\ + text_input.o) products += $(app_objs) app.elf app.hex app.bin app.elf: $(app_objs) diff --git a/app/app.cpp b/app/app.cpp index 6a86d4cd6..043984995 100644 --- a/app/app.cpp +++ b/app/app.cpp @@ -6,6 +6,8 @@ extern "C" { #include +#include "text_input.h" + void draw_lines_from_center() { KDCoordinate width = SCREEN_WIDTH; KDCoordinate height = SCREEN_HEIGHT; @@ -41,7 +43,6 @@ void plot(Expression * e, float xMin, float xMax, float yMin, float yMax) { for (KDCoordinate i=0;iapproximate(plotContext); KDCoordinate j = ((y-yMin)/(yMax-yMin)*screenHeight); @@ -59,79 +60,38 @@ void funnyPlot() { delete e; } -void parseInlineExpression() { - char * expression = (char*) "1+2/3+4/5+6"; - Expression * e = Expression::parse(expression); - ExpressionLayout * l = e->createLayout(nullptr); - l->draw(KDPointMake(0,100)); - delete l; - delete e; +static void clear_screen() { + KDRect r; + r.x = 0; + r.y = 0; + r.width = SCREEN_WIDTH; + r.height = SCREEN_HEIGHT; + KDFillRect(r, 0x00); } -void interactive_expression_parsing() { - char input[255]; - int index = 0; - int max = 1; +static void interactive_expression_parsing() { while (1) { - char character = ion_getchar(); - if (character == '=') { - input[index] = 0; - index = 0; - max = index+1; - Expression * e = Expression::parse(input); - if (e) { - ExpressionLayout * l = e->createLayout(nullptr); - if (l) { - l->draw(KDPointMake(0,100)); - plot(e, 0.0f, 3.0f, 0.0f, 2.0f); - delete l; - } - delete e; - } else { - KDDrawString("PARSING ERROR", KDPointMake(10,10)); + char * text_input = get_text(); + clear_screen(); + Expression * e = Expression::parse(text_input); + if (e) { + ExpressionLayout * l = e->createLayout(nullptr); + if (l) { + l->draw(KDPointMake(0,10)); + delete l; } - } else if (character == LEFT_ARROW_KEY) { - index--; - if (index < 0) { - index = 0; - } - } else if (character == RIGHT_ARROW_KEY) { - if (index < max) { - index++; - } + delete e; } else { - if (index == 0) { - KDRect r; - r.x = 0; - r.y = 0; - r.width = SCREEN_WIDTH; - r.height = SCREEN_HEIGHT; - KDFillRect(r, 0x00); - } - input[index++] = character; - // We are at the end of the line. - if (index == max) { - input[max++] = ' '; - input[max+1] = 0; - } + KDDrawString("PARSING ERROR", KDPointMake(10,10)); } - // Here we draw the input and inverse the pixels under the cursor. - // FIXME: hard coded value - KDDrawLine(KDPointMake(0, SCREEN_HEIGHT - 30), - KDPointMake(SCREEN_WIDTH, SCREEN_HEIGHT - 30), 0xff); - KDDrawString(input, KDPointMake(0, SCREEN_HEIGHT - 15)); - KDDrawInverseChar(input[index] ? input[index] : ' ', - KDPointMake(index*7, SCREEN_HEIGHT - 15)); + // We dealocate the memory allocated by get_text; + free(text_input); } } void ion_app() { - KDDrawString("Hello, world!", KDPointMake(10,10)); interactive_expression_parsing(); - //parseInlineExpression(); - //funnyPlot(); - //interactive_expression_parsing(); while (1) { ion_sleep(); } diff --git a/app/text_input.cpp b/app/text_input.cpp new file mode 100644 index 000000000..36eb331d7 --- /dev/null +++ b/app/text_input.cpp @@ -0,0 +1,68 @@ +extern "C" { +#include +#include +#include +#include +} + +#define PROMPT_HEIGHT 30 + +static void clear_prompt() { + KDRect r; + r.x = 0; + r.y = SCREEN_HEIGHT - PROMPT_HEIGHT; + r.width = SCREEN_WIDTH; + r.height = PROMPT_HEIGHT; + KDFillRect(r, 0x00); +} + +static void print_prompt(char* text, int index) { + // Here we draw the input and inverse the pixels under the cursor. + // FIXME: hard coded value + KDDrawLine(KDPointMake(0, SCREEN_HEIGHT - PROMPT_HEIGHT), + KDPointMake(SCREEN_WIDTH, SCREEN_HEIGHT - PROMPT_HEIGHT), 0xff); + KDDrawString(text, KDPointMake(0, SCREEN_HEIGHT - (PROMPT_HEIGHT / 2))); + // The hardcoded 7 is the width of the font. + KDDrawInverseChar(text[index], + KDPointMake(index*7, SCREEN_HEIGHT - (PROMPT_HEIGHT / 2))); +} + +char* get_text() { + char input[255] = {0}; + int index = 0; + int max = 0; + input[max] = ' '; + input[max+1] = '\0'; + + while (1) { + clear_prompt(); + print_prompt(input, index); + ion_event_t event = ion_get_event(); + if (event == EQUAL) { + break; + } else if (event == LEFT_ARROW) { + index--; + if (index < 0) { + index = 0; + } + } else if (event == RIGHT_ARROW) { + if (index < max) { + index++; + } + } else if (event <= 0x7f) { + input[index++] = (char) event; + // We are at the end of the line. + if (index > max) { + max++; + input[max] = ' '; + input[max+1] = '\0'; + } + } + } + + clear_prompt(); + input[max] = '\0'; + char* output = (char*) malloc(sizeof(char) * (index + 1)); + memcpy(output, input, (size_t) (index + 1)); + return output; +} diff --git a/app/text_input.h b/app/text_input.h new file mode 100644 index 000000000..b7490c2ff --- /dev/null +++ b/app/text_input.h @@ -0,0 +1,8 @@ +#ifndef APP_TEXTINPUT_H +#define APP_TEXTINPUT_H + +/* Returns a pointer to an input text, allocated by the functions (it is thus + * the caller's role to free it). */ +char* get_text(); + +#endif // APP_TEXTINPUT_H diff --git a/ion/include/ion.h b/ion/include/ion.h index f17cbb36b..d0131844f 100644 --- a/ion/include/ion.h +++ b/ion/include/ion.h @@ -1,6 +1,7 @@ #ifndef ION_ION_H #define ION_ION_H +#include #include #include diff --git a/ion/include/ion/events.h b/ion/include/ion/events.h new file mode 100644 index 000000000..3758b742c --- /dev/null +++ b/ion/include/ion/events.h @@ -0,0 +1,84 @@ +#ifndef ION_EVENTS_H +#define ION_EVENTS_H + +typedef enum { + LEFT_PARENTHESIS = '(', // 0x28 + RIGHT_PARENTHESIS = ')', // 0x29 + PRODUCT = '*', // 0x2a + PLUS = '+', // 0x2b + MINUS = '-', // 0x2d + DOT = '.', // 0x2e + DIVISION = '/', // 0x2f + ZERO = '0', // 0x30 + ONE = '1', + TWO = '2', + THREE = '3', + FOUR = '4', + FIVE = '5', + SIX = '6', + SEVEN = '7', + EIGHT = '8', + NINE = '9', + EQUAL = '=', // 0x3d + UPPER_CASE_A = 'A', // 0x41 + UPPER_CASE_B, + UPPER_CASE_C, + UPPER_CASE_D, + UPPER_CASE_E, + UPPER_CASE_F, + UPPER_CASE_G, + UPPER_CASE_H, + UPPER_CASE_I, + UPPER_CASE_J, + UPPER_CASE_K, + UPPER_CASE_L, + UPPER_CASE_M, + UPPER_CASE_N, + UPPER_CASE_O, + UPPER_CASE_P, + UPPER_CASE_Q, + UPPER_CASE_R, + UPPER_CASE_S, + UPPER_CASE_T, + UPPER_CASE_U, + UPPER_CASE_V, + UPPER_CASE_W, + UPPER_CASE_X, + UPPER_CASE_Y, + UPPER_CASE_Z, + POWER = '^', // 0x5e + LOWER_CASE_A = 'a', // 0X61 + LOWER_CASE_B, + LOWER_CASE_C, + LOWER_CASE_D, + LOWER_CASE_E, + LOWER_CASE_F, + LOWER_CASE_G, + LOWER_CASE_H, + LOWER_CASE_I, + LOWER_CASE_J, + LOWER_CASE_K, + LOWER_CASE_L, + LOWER_CASE_M, + LOWER_CASE_N, + LOWER_CASE_O, + LOWER_CASE_P, + LOWER_CASE_Q, + LOWER_CASE_R, + LOWER_CASE_S, + LOWER_CASE_T, + LOWER_CASE_U, + LOWER_CASE_V, + LOWER_CASE_W, + LOWER_CASE_X, + LOWER_CASE_Y, + LOWER_CASE_Z, + LEFT_ARROW = 0x100, // events for things outside of ASCII. + RIGHT_ARROW, + MENU_TRIG, + ERROR = 0xffffffff, +} ion_event_t; + +ion_event_t ion_get_event(); + +#endif diff --git a/ion/include/ion/keyboard.h b/ion/include/ion/keyboard.h index e4ef2ab6f..d49a01536 100644 --- a/ion/include/ion/keyboard.h +++ b/ion/include/ion/keyboard.h @@ -49,13 +49,6 @@ typedef enum { #define ION_NUMBER_OF_KEYS 35 -#define LEFT_ARROW_KEY '@' -#define RIGHT_ARROW_KEY '?' - -// FIXME: Which state is "true"? bool ion_key_down(ion_key_t key); -// This is our keymap -char ion_getchar(); - #endif diff --git a/ion/src/device/keyboard/keyboard.c b/ion/src/device/keyboard/keyboard.c index 7da05f06f..fdcab0776 100644 --- a/ion/src/device/keyboard/keyboard.c +++ b/ion/src/device/keyboard/keyboard.c @@ -62,7 +62,7 @@ bool ion_key_down(ion_key_t key) { GPIO_ODR(GPIOA) = new_odr; // We changed the outputs, give the hardware some time to react to this change // FIXME: Real delay! - for (int i=0;i<1000; i++) { + for (volatile int i=0;i<1000; i++) { } } diff --git a/ion/src/shared/Makefile b/ion/src/shared/Makefile index cc8875e25..519560249 100644 --- a/ion/src/shared/Makefile +++ b/ion/src/shared/Makefile @@ -1 +1,2 @@ -objs += $(addprefix ion/src/shared/, keyboard.o) +objs += $(addprefix ion/src/shared/,\ + events.o) diff --git a/ion/src/shared/events.c b/ion/src/shared/events.c new file mode 100644 index 000000000..b9c18c27f --- /dev/null +++ b/ion/src/shared/events.c @@ -0,0 +1,69 @@ +#include + +// More event type will be added later. +typedef enum { + KEY_DOWN, +} ion_key_event_type_t; + +typedef struct { + ion_key_t key; + ion_key_event_type_t event; +} ion_key_event_t; + +// Debouncing, qnd change to get_key event. +static ion_key_event_t ion_get_key_event() { + // Let's start by saving which keys we've seen up + bool key_seen_up[ION_NUMBER_OF_KEYS]; + for (ion_key_t k=0; k -#include - -static const char kCharForKey[ION_NUMBER_OF_KEYS] = { - 'A', 'B', 'C', 'D', 'E', - 'F', 'G', 'H', 'I', 'J', - 'K', 'L', 'M', LEFT_ARROW_KEY, RIGHT_ARROW_KEY, - '7', '8', '9', '(', ')', - '4', '5', '6', '*', '/', - '1', '2', '3', '+', '-', - '0', '.', 'x', '^', '=' -}; - -char ion_getchar() { - // Let's start by saving which keys we've seen up - bool key_seen_up[ION_NUMBER_OF_KEYS]; - for (ion_key_t k=0; k