| Index: embios/branches/4g_compat/console.c | 
| — | — | @@ -24,10 +24,10 @@ | 
| 25 | 25 | #include "global.h" | 
| 26 | 26 | #include "console.h" | 
| 27 | 27 | #include "lcdconsole.h" | 
|  | 28 | +#include "usb/dbgconsole.h" | 
| 28 | 29 | #include "format.h" | 
| 29 |  | -#include <stdio.h>
 | 
|  | 30 | +#include "thread.h" | 
| 30 | 31 | #include <stdarg.h> | 
| 31 |  | -#include <stdbool.h>
 | 
| 32 | 32 | #include <limits.h> | 
| 33 | 33 |  | 
| 34 | 34 |  | 
| — | — | @@ -38,10 +38,27 @@ | 
| 39 | 39 | }; | 
| 40 | 40 |  | 
| 41 | 41 |  | 
|  | 42 | +struct mutex console_mutex; | 
|  | 43 | +struct mutex console_readmutex; | 
|  | 44 | + | 
|  | 45 | + | 
|  | 46 | +void console_init() | 
|  | 47 | +{ | 
|  | 48 | +    mutex_init(&console_mutex); | 
|  | 49 | +    mutex_init(&console_readmutex); | 
|  | 50 | +} | 
|  | 51 | + | 
|  | 52 | +void cputc_internal(unsigned int consoles, char string) ICODE_ATTR; | 
|  | 53 | +void cputc_internal(unsigned int consoles, char string) | 
|  | 54 | +{ | 
|  | 55 | +    if (consoles & 1) lcdconsole_putc(string, 0, -1); | 
|  | 56 | +    if (consoles & 2) dbgconsole_putc(string); | 
|  | 57 | +} | 
|  | 58 | + | 
| 42 | 59 | static int cprfunc(void* ptr, unsigned char letter) | 
| 43 | 60 | { | 
| 44 | 61 | struct for_cprintf* pr = (struct for_cprintf*)ptr; | 
| 45 |  | -    cputc_noblit(pr->consoles, letter);
 | 
|  | 62 | +    cputc_internal(pr->consoles, letter); | 
| 46 | 63 | pr->bytes++; | 
| 47 | 64 | return true; | 
| 48 | 65 | } | 
| — | — | @@ -54,11 +71,11 @@ | 
| 55 | 72 | pr.consoles = consoles; | 
| 56 | 73 | pr.bytes = 0; | 
| 57 | 74 |  | 
|  | 75 | +    mutex_lock(&console_mutex, TIMEOUT_BLOCK); | 
| 58 | 76 | va_start(ap, fmt); | 
| 59 | 77 | format(cprfunc, &pr, fmt, ap); | 
| 60 | 78 | va_end(ap); | 
| 61 |  | -    
 | 
| 62 |  | -    lcdconsole_update();
 | 
|  | 79 | +    mutex_unlock(&console_mutex); | 
| 63 | 80 |  | 
| 64 | 81 | return pr.bytes; | 
| 65 | 82 | } | 
| — | — | @@ -70,9 +87,9 @@ | 
| 71 | 88 | pr.consoles = consoles; | 
| 72 | 89 | pr.bytes = 0; | 
| 73 | 90 |  | 
|  | 91 | +    mutex_lock(&console_mutex, TIMEOUT_BLOCK); | 
| 74 | 92 | format(cprfunc, &pr, fmt, ap); | 
| 75 |  | -    
 | 
| 76 |  | -    lcdconsole_update();
 | 
|  | 93 | +    mutex_unlock(&console_mutex); | 
| 77 | 94 |  | 
| 78 | 95 | return pr.bytes; | 
| 79 | 96 | } | 
| — | — | @@ -79,25 +96,61 @@ | 
| 80 | 97 |  | 
| 81 | 98 | void cputc(unsigned int consoles, char string) | 
| 82 | 99 | { | 
| 83 |  | -  if (consoles & 1) lcdconsole_putc(string, 0, -1);
 | 
|  | 100 | +    mutex_lock(&console_mutex, TIMEOUT_BLOCK); | 
|  | 101 | +    cputc_internal(consoles, string); | 
|  | 102 | +    mutex_unlock(&console_mutex); | 
| 84 | 103 | } | 
| 85 | 104 |  | 
| 86 |  | -void cputc_noblit(unsigned int consoles, char string)
 | 
|  | 105 | +void cputs(unsigned int consoles, const char* string) | 
| 87 | 106 | { | 
| 88 |  | -  if (consoles & 1) lcdconsole_putc_noblit(string, 0, -1);
 | 
|  | 107 | +    mutex_lock(&console_mutex, TIMEOUT_BLOCK); | 
|  | 108 | +    if (consoles & 1) lcdconsole_puts(string, 0, -1); | 
|  | 109 | +    if (consoles & 2) dbgconsole_puts(string); | 
|  | 110 | +    mutex_unlock(&console_mutex); | 
| 89 | 111 | } | 
| 90 | 112 |  | 
| 91 |  | -void cputs(unsigned int consoles, const char* string)
 | 
|  | 113 | +void cwrite(unsigned int consoles, const char* string, size_t length) | 
| 92 | 114 | { | 
| 93 |  | -  if (consoles & 1) lcdconsole_puts(string, 0, -1);
 | 
|  | 115 | +    mutex_lock(&console_mutex, TIMEOUT_BLOCK); | 
|  | 116 | +    if (consoles & 1) lcdconsole_write(string, length, 0, -1); | 
|  | 117 | +    if (consoles & 2) dbgconsole_write(string, length); | 
|  | 118 | +    mutex_unlock(&console_mutex); | 
| 94 | 119 | } | 
| 95 | 120 |  | 
| 96 |  | -void cputs_noblit(unsigned int consoles, const char* string)
 | 
|  | 121 | +void cflush(unsigned int consoles) | 
| 97 | 122 | { | 
| 98 |  | -  if (consoles & 1) lcdconsole_puts_noblit(string, 0, -1);
 | 
|  | 123 | +    mutex_lock(&console_mutex, TIMEOUT_BLOCK); | 
|  | 124 | +    if (consoles & 1) lcdconsole_update(); | 
|  | 125 | +    mutex_unlock(&console_mutex); | 
| 99 | 126 | } | 
| 100 | 127 |  | 
| 101 |  | -void cflush(unsigned int consoles)
 | 
|  | 128 | +int cgetc(unsigned int consoles, int timeout) | 
| 102 | 129 | { | 
| 103 |  | -  if (consoles & 1) lcdconsole_update();
 | 
|  | 130 | +    int result; | 
|  | 131 | +    mutex_lock(&console_readmutex, TIMEOUT_BLOCK); | 
|  | 132 | +    if ((consoles & 2) && (result = dbgconsole_getc(timeout)) != -1) return result; | 
|  | 133 | +    mutex_unlock(&console_mutex); | 
| 104 | 134 | } | 
|  | 135 | + | 
|  | 136 | +int cread(unsigned int consoles, char* buffer, size_t length, int timeout) | 
|  | 137 | +{ | 
|  | 138 | +    int result; | 
|  | 139 | +    mutex_lock(&console_readmutex, TIMEOUT_BLOCK); | 
|  | 140 | +    if ((consoles & 2) && (result = dbgconsole_read(buffer, length, timeout))) return result; | 
|  | 141 | +    mutex_unlock(&console_mutex); | 
|  | 142 | +} | 
|  | 143 | + | 
|  | 144 | +void creada(unsigned int consoles, char* buffer, size_t length, int timeout) | 
|  | 145 | +{ | 
|  | 146 | +    int result; | 
|  | 147 | +    mutex_lock(&console_readmutex, TIMEOUT_BLOCK); | 
|  | 148 | +    while (length) | 
|  | 149 | +    { | 
|  | 150 | +        if (length && (consoles & 2) && (result = dbgconsole_read(buffer, length, timeout))) | 
|  | 151 | +        { | 
|  | 152 | +            buffer = &buffer[result]; | 
|  | 153 | +            length -= result; | 
|  | 154 | +        } | 
|  | 155 | +    } | 
|  | 156 | +    mutex_unlock(&console_mutex); | 
|  | 157 | +} | 
| Index: embios/branches/4g_compat/console.h | 
| — | — | @@ -26,16 +26,21 @@ | 
| 27 | 27 |  | 
| 28 | 28 |  | 
| 29 | 29 | #include "global.h" | 
|  | 30 | +#include "gcc_extensions.h" | 
| 30 | 31 | #include <stdarg.h> | 
| 31 | 32 |  | 
| 32 | 33 |  | 
|  | 34 | +void console_init() INITCODE_ATTR; | 
| 33 | 35 | void cputc(unsigned int consoles, char string) ICODE_ATTR; | 
| 34 |  | -void cputc_noblit(unsigned int consoles, char string) ICODE_ATTR;
 | 
| 35 | 36 | void cputs(unsigned int consoles, const char* string) ICODE_ATTR; | 
| 36 |  | -void cputs_noblit(unsigned int consoles, const char* string) ICODE_ATTR;
 | 
| 37 |  | -int cprintf(unsigned int consoles, const char* fmt, ...) ICODE_ATTR;
 | 
|  | 37 | +void cwrite(unsigned int consoles, const char* string, size_t length) ICODE_ATTR; | 
|  | 38 | +int cprintf(unsigned int consoles, const char* fmt, ...) ICODE_ATTR | 
|  | 39 | +            ATTRIBUTE_PRINTF(2, 3); | 
| 38 | 40 | int cvprintf(unsigned int consoles, const char* fmt, va_list ap) ICODE_ATTR; | 
| 39 | 41 | void cflush(unsigned int consoles) ICODE_ATTR; | 
|  | 42 | +int cgetc(unsigned int consoles, int timeout) ICODE_ATTR; | 
|  | 43 | +int cread(unsigned int consoles, char* buffer, size_t length, int timeout) ICODE_ATTR; | 
|  | 44 | +void creada(unsigned int consoles, char* buffer, size_t length, int timeout) ICODE_ATTR; | 
| 40 | 45 |  | 
| 41 | 46 |  | 
| 42 | 47 | #endif | 
| Index: embios/branches/4g_compat/drawing.h | 
| — | — | @@ -32,7 +32,7 @@ | 
| 33 | 33 | #define FONT_HEIGHT 8 | 
| 34 | 34 |  | 
| 35 | 35 |  | 
| 36 |  | -void rendertext(void* buffer, int fgcol, int bgcol, char* text, int stride);
 | 
|  | 36 | +void renderchar(void* buffer, int fgcol, int bgcol, char text, int stride); | 
| 37 | 37 | void renderbmp(void* buffer, void* bitmap, int stride); | 
| 38 | 38 |  | 
| 39 | 39 |  | 
| Index: embios/branches/4g_compat/SOURCES | 
| — | — | @@ -11,11 +11,12 @@ | 
| 12 | 12 | #ifdef TARGET_ipodnano4g | 
| 13 | 13 | target/ipodnano4g/mmu.c | 
| 14 | 14 | target/ipodnano4g/lcd.c | 
|  | 15 | +target/ipodnano4g/timer.c | 
| 15 | 16 | target/ipodnano4g/i2c.S | 
|  | 17 | +target/ipodnano4g/interrupt.c | 
|  | 18 | +target/ipodnano4g/power.c | 
| 16 | 19 | target/ipodnano4g/accel.c | 
| 17 | 20 | target/ipodnano4g/backlight.c | 
| 18 |  | -target/ipodnano4g/interrupt.c
 | 
| 19 |  | -target/ipodnano4g/timer.c
 | 
| 20 | 21 | usb/synopsysotg.c | 
| 21 | 22 | #endif | 
| 22 | 23 |  | 
| Index: embios/branches/4g_compat/target/ipodnano4g/lcd.h | 
| — | — | @@ -35,6 +35,7 @@ | 
| 36 | 36 | #define LCD_FRAMEBUFSIZE (LCD_WIDTH * LCD_HEIGHT * LCD_BYTESPERPIXEL) | 
| 37 | 37 |  | 
| 38 | 38 |  | 
|  | 39 | +void lcd_init(); | 
| 39 | 40 | void displaylcd(unsigned int startx, unsigned int endx, | 
| 40 | 41 | unsigned int starty, unsigned int endy, void* data, int color); | 
| 41 | 42 | void displaylcd_sync(); | 
| Index: embios/branches/4g_compat/target/ipodnano4g/lcd.S | 
| — | — | @@ -21,24 +21,14 @@ | 
| 22 | 22 | @ | 
| 23 | 23 |  | 
| 24 | 24 |  | 
| 25 |  | -.section .text.displaylcd_safe, "ax", %progbits
 | 
|  | 25 | +.section .initcode.lcd_init, "ax", %progbits | 
| 26 | 26 | .align 2 | 
| 27 |  | -.global displaylcd_safe
 | 
| 28 |  | -.type displaylcd_safe, %function
 | 
| 29 |  | -displaylcd_safe:
 | 
| 30 |  | -	mov	r0, #1
 | 
|  | 27 | +.global lcd_init | 
|  | 28 | +.type lcd_init, %function | 
|  | 29 | +lcd_init: | 
| 31 | 30 | mov	pc, lr | 
| 32 |  | -.size displaylcd_safe, .-displaylcd_safe
 | 
|  | 31 | +.size lcd_init, .-lcd_init | 
| 33 | 32 |  | 
| 34 |  | -.section .text.displaylcd_busy, "ax", %progbits
 | 
| 35 |  | -.align 2
 | 
| 36 |  | -.global displaylcd_busy
 | 
| 37 |  | -.type displaylcd_busy, %function
 | 
| 38 |  | -displaylcd_busy:
 | 
| 39 |  | -	mov	r0, #0
 | 
| 40 |  | -	mov	pc, lr
 | 
| 41 |  | -.size displaylcd_busy, .-displaylcd_busy
 | 
| 42 |  | -
 | 
| 43 | 33 | .section .icode.displaylcd, "ax", %progbits | 
| 44 | 34 | .align 2 | 
| 45 | 35 | .global displaylcd | 
| — | — | @@ -108,3 +98,22 @@ | 
| 109 | 99 | displaylcd_sync: | 
| 110 | 100 | mov	pc, lr | 
| 111 | 101 | .size displaylcd_sync, .-displaylcd_sync | 
|  | 102 | + | 
|  | 103 | +.section .icode.displaylcd_busy, "ax", %progbits | 
|  | 104 | +.align 2 | 
|  | 105 | +.global displaylcd_busy | 
|  | 106 | +.type displaylcd_busy, %function | 
|  | 107 | +displaylcd_busy: | 
|  | 108 | +	mov	r0, #0 | 
|  | 109 | +	mov	pc, lr | 
|  | 110 | +.size displaylcd_busy, .-displaylcd_busy | 
|  | 111 | + | 
|  | 112 | +.section .icode.displaylcd_safe, "ax", %progbits | 
|  | 113 | +.align 2 | 
|  | 114 | +.global displaylcd_safe | 
|  | 115 | +.type displaylcd_safe, %function | 
|  | 116 | +displaylcd_safe: | 
|  | 117 | +	mov	r0, #1 | 
|  | 118 | +	mov	pc, lr | 
|  | 119 | +.size displaylcd_safe, .-displaylcd_safe | 
|  | 120 | + | 
| Index: embios/branches/4g_compat/target/ipodnano4g/power.c | 
| — | — | @@ -22,9 +22,7 @@ | 
| 23 | 23 |  | 
| 24 | 24 |  | 
| 25 | 25 | #include "global.h" | 
| 26 |  | -#include "s5l8701.h"
 | 
| 27 | 26 | #include "power.h" | 
| 28 |  | -#include "pmu.h"
 | 
| 29 | 27 |  | 
| 30 | 28 |  | 
| 31 | 29 | void reset(); | 
| Index: embios/branches/4g_compat/lcdconsole.c | 
| — | — | @@ -25,6 +25,7 @@ | 
| 26 | 26 | #include "lcdconsole.h" | 
| 27 | 27 | #include "drawing.h" | 
| 28 | 28 | #include "util.h" | 
|  | 29 | +#include "contextswitch.h" | 
| 29 | 30 |  | 
| 30 | 31 |  | 
| 31 | 32 | #define OFFSETX LCDCONSOLE_OFFSETX | 
| — | — | @@ -37,62 +38,73 @@ | 
| 38 | 39 |  | 
| 39 | 40 |  | 
| 40 | 41 | static unsigned char framebuf[LCD_FRAMEBUFSIZE]; | 
| 41 |  | -static unsigned int current_row;
 | 
| 42 |  | -static unsigned int current_col;
 | 
|  | 42 | +static unsigned int current_row IBSS_ATTR; | 
|  | 43 | +static unsigned int current_col IBSS_ATTR; | 
|  | 44 | +static bool lcdconsole_needs_update IBSS_ATTR; | 
| 43 | 45 |  | 
| 44 | 46 |  | 
| 45 | 47 | void lcdconsole_init() | 
| 46 | 48 | { | 
| 47 |  | -  memset(framebuf, -1, sizeof(framebuf));
 | 
| 48 |  | -  current_row = 0;
 | 
| 49 |  | -  current_col = -1;
 | 
|  | 49 | +    memset(framebuf, -1, sizeof(framebuf)); | 
|  | 50 | +    current_row = 0; | 
|  | 51 | +    current_col = -1; | 
|  | 52 | +    lcdconsole_needs_update = false; | 
| 50 | 53 | } | 
| 51 | 54 |  | 
| 52 | 55 | void lcdconsole_putc_noblit(char string, int fgcolor, int bgcolor) | 
| 53 | 56 | { | 
| 54 |  | -  if (string == '\r')
 | 
| 55 |  | -  {
 | 
| 56 |  | -    current_col = 0;
 | 
| 57 |  | -    return;
 | 
| 58 |  | -  }
 | 
| 59 |  | -  current_col++;
 | 
| 60 |  | -  if (string == '\n')
 | 
| 61 |  | -  {
 | 
| 62 |  | -    current_col = -1;
 | 
| 63 |  | -    current_row++;
 | 
| 64 |  | -    return;
 | 
| 65 |  | -  }
 | 
| 66 |  | -  if (string == '\t')
 | 
| 67 |  | -  {
 | 
| 68 |  | -    current_col |= 3;
 | 
| 69 |  | -    return;
 | 
| 70 |  | -  }
 | 
| 71 |  | -  if (current_col >= LCDCONSOLE_COLS)
 | 
| 72 |  | -  {
 | 
| 73 |  | -    current_col = 0;
 | 
| 74 |  | -    current_row++;
 | 
| 75 |  | -  }
 | 
| 76 |  | -  if (current_row >= LCDCONSOLE_ROWS)
 | 
| 77 |  | -  {
 | 
| 78 |  | -    int offset = current_row - LCDCONSOLE_ROWS + 1;
 | 
| 79 |  | -    memcpy(&framebuf[LINEBYTES * OFFSETY], &framebuf[LINEBYTES * OFFSETY + ROWBYTES * offset],
 | 
| 80 |  | -           ROWBYTES * (LCDCONSOLE_ROWS - offset));
 | 
| 81 |  | -    memset(&framebuf[LINEBYTES * OFFSETY + ROWBYTES * (LCDCONSOLE_ROWS - offset)],
 | 
| 82 |  | -           -1, ROWBYTES * offset);
 | 
| 83 |  | -    current_row = LCDCONSOLE_ROWS - 1;
 | 
| 84 |  | -  }
 | 
| 85 |  | -  renderchar(&framebuf[OFFSETBYTES + ROWBYTES * current_row + COLBYTES * current_col],
 | 
| 86 |  | -             fgcolor, bgcolor, string, LINEBYTES);
 | 
|  | 57 | +    if (string == '\r') return; | 
|  | 58 | +    current_col++; | 
|  | 59 | +    if (string == '\n') | 
|  | 60 | +    { | 
|  | 61 | +        current_col = -1; | 
|  | 62 | +        current_row++; | 
|  | 63 | +        return; | 
|  | 64 | +    } | 
|  | 65 | +    if (string == '\t') | 
|  | 66 | +    { | 
|  | 67 | +        current_col |= 3; | 
|  | 68 | +        return; | 
|  | 69 | +    } | 
|  | 70 | +    if (current_col >= LCDCONSOLE_COLS) | 
|  | 71 | +    { | 
|  | 72 | +        current_col = 0; | 
|  | 73 | +        current_row++; | 
|  | 74 | +    } | 
|  | 75 | +    if (current_row >= LCDCONSOLE_ROWS) | 
|  | 76 | +    { | 
|  | 77 | +        int offset = current_row - LCDCONSOLE_ROWS + 1; | 
|  | 78 | +        memcpy(&framebuf[LINEBYTES * OFFSETY], &framebuf[LINEBYTES * OFFSETY + ROWBYTES * offset], | 
|  | 79 | +            ROWBYTES * (LCDCONSOLE_ROWS - offset)); | 
|  | 80 | +        memset(&framebuf[LINEBYTES * OFFSETY + ROWBYTES * (LCDCONSOLE_ROWS - offset)], | 
|  | 81 | +            -1, ROWBYTES * offset); | 
|  | 82 | +        current_row = LCDCONSOLE_ROWS - 1; | 
|  | 83 | +    } | 
|  | 84 | +    renderchar(&framebuf[OFFSETBYTES + ROWBYTES * current_row + COLBYTES * current_col], | 
|  | 85 | +        fgcolor, bgcolor, string, LINEBYTES); | 
| 87 | 86 | } | 
| 88 | 87 |  | 
| 89 | 88 | void lcdconsole_puts_noblit(const char* string, int fgcolor, int bgcolor) | 
| 90 | 89 | { | 
| 91 |  | -  while (*string) lcdconsole_putc_noblit(*string++, fgcolor, bgcolor);
 | 
|  | 90 | +    while (*string) lcdconsole_putc_noblit(*string++, fgcolor, bgcolor); | 
| 92 | 91 | } | 
| 93 | 92 |  | 
|  | 93 | +void lcdconsole_write_noblit(const char* string, size_t length, int fgcolor, int bgcolor) | 
|  | 94 | +{ | 
|  | 95 | +    while (length--) lcdconsole_putc_noblit(*string++, fgcolor, bgcolor); | 
|  | 96 | +} | 
|  | 97 | + | 
| 94 | 98 | void lcdconsole_update() | 
| 95 | 99 | { | 
| 96 |  | -  displaylcd(0, LCD_WIDTH - 1, 0, LCD_HEIGHT - 1, framebuf, 0);
 | 
|  | 100 | +    uint32_t mode = enter_critical_section(); | 
|  | 101 | +    if (displaylcd_busy()) | 
|  | 102 | +    { | 
|  | 103 | +        lcdconsole_needs_update = true; | 
|  | 104 | +        leave_critical_section(mode); | 
|  | 105 | +        return; | 
|  | 106 | +    } | 
|  | 107 | +    leave_critical_section(mode); | 
|  | 108 | +    displaylcd(0, LCD_WIDTH - 1, 0, LCD_HEIGHT - 1, framebuf, 0); | 
| 97 | 109 | } | 
| 98 | 110 |  | 
| 99 | 111 | void lcdconsole_putc(char string, int fgcolor, int bgcolor) | 
| — | — | @@ -106,3 +118,18 @@ | 
| 107 | 119 | while (*string) lcdconsole_putc_noblit(*string++, fgcolor, bgcolor); | 
| 108 | 120 | lcdconsole_update(); | 
| 109 | 121 | } | 
|  | 122 | + | 
|  | 123 | +void lcdconsole_write(const char* string, size_t length, int fgcolor, int bgcolor) | 
|  | 124 | +{ | 
|  | 125 | +    while (length--) lcdconsole_putc_noblit(*string++, fgcolor, bgcolor); | 
|  | 126 | +    lcdconsole_update(); | 
|  | 127 | +} | 
|  | 128 | + | 
|  | 129 | +void lcdconsole_callback() | 
|  | 130 | +{ | 
|  | 131 | +    if (lcdconsole_needs_update) | 
|  | 132 | +    { | 
|  | 133 | +        displaylcd(0, LCD_WIDTH - 1, 0, LCD_HEIGHT - 1, framebuf, 0); | 
|  | 134 | +        lcdconsole_needs_update = false; | 
|  | 135 | +    } | 
|  | 136 | +} | 
| Index: embios/branches/4g_compat/lcdconsole.h | 
| — | — | @@ -39,9 +39,12 @@ | 
| 40 | 40 | void lcdconsole_init(); | 
| 41 | 41 | void lcdconsole_putc(char string, int fgcolor, int bgcolor) ICODE_ATTR; | 
| 42 | 42 | void lcdconsole_puts(const char* string, int fgcolor, int bgcolor) ICODE_ATTR; | 
|  | 43 | +void lcdconsole_write(const char* string, size_t length, int fgcolor, int bgcolor) ICODE_ATTR; | 
| 43 | 44 | void lcdconsole_putc_noblit(char string, int fgcolor, int bgcolor) ICODE_ATTR; | 
| 44 | 45 | void lcdconsole_puts_noblit(const char* string, int fgcolor, int bgcolor) ICODE_ATTR; | 
|  | 46 | +void lcdconsole_write_noblit(const char* string, size_t length, int fgcolor, int bgcolor) ICODE_ATTR; | 
| 45 | 47 | void lcdconsole_update() ICODE_ATTR; | 
|  | 48 | +void lcdconsole_callback() ICODE_ATTR; | 
| 46 | 49 |  | 
| 47 | 50 |  | 
| 48 | 51 | #endif |