#include <t_services.h>
#include "newfont.h"
#include "ili9320.h"
#include <lpc23xx.h>
#include "lcd.h"
#include <string.h>
#include "kernel_id.h"
#include "fonts.h"
#include "player.h"

#ifdef LOW_SCALE
#define CLEVEL  16  /* Number of gray scale */
#define CSHIFT  4   /* 8 - log2(CLEVEL), number of right shift to produce CLEVEL scale */
#else
#define CLEVEL  64  /* Number of gray scale */
#define CSHIFT  2   /* 8 - log2(CLEVEL), number of right shift to produce CLEVEL scale */
#endif

typedef struct {
  UH fgcolor, bgcolor;
  UH mid_color[CLEVEL];
} t_colortab;

static t_colortab colortab;

static UH mid_vals[3][CLEVEL];

#define CHARTAB_SIZE    100
#define BITMAP_SIZE 300
struct char_desc chardesc_tab[CHARTAB_SIZE] __attribute__((section(".etherram")));
UB char_bitmap[BITMAP_SIZE] __attribute__((section(".etherram")));

static void gen_colortab(UH fgcolor, UH bgcolor, t_colortab *ptab)
{
    UH fg_val, bg_val;
    int i, diff;
    UH rval, gval, bval, wval;

    if (ptab->fgcolor != fgcolor || ptab->bgcolor != bgcolor) {
        /* Red */
        fg_val = ((fgcolor >> 11) & 0x1f) << 3;
        bg_val = ((bgcolor >> 11) & 0x1f) << 3;
        mid_vals[0][0] = bg_val;
        mid_vals[0][CLEVEL-1] = fg_val;
        if (fg_val > bg_val) {
            diff = (fg_val - bg_val)/(CLEVEL-1);
            for (i = 1; i < (CLEVEL-1); i++) {
                bg_val += diff;
                mid_vals[0][i] = bg_val;
            }
        } else {
            diff = (bg_val - fg_val)/(CLEVEL-1);
            for (i = 1; i < (CLEVEL-1); i++) {
                bg_val -= diff;
                mid_vals[0][i] = bg_val;
            }
        }
        /* Green */
        fg_val = ((fgcolor >> 5) & 0x3f) << 2;
        bg_val = ((bgcolor >> 5) & 0x3f) << 2;
        mid_vals[1][0] = bg_val;
        mid_vals[1][(CLEVEL-1)] = fg_val;
        if (fg_val > bg_val) {
            diff = (fg_val - bg_val)/(CLEVEL-1);
            for (i = 1; i < (CLEVEL-1); i++) {
                bg_val += diff;
                mid_vals[1][i] = bg_val;
            }
        } else {
            diff = (bg_val - fg_val)/(CLEVEL-1);
            for (i = 1; i < (CLEVEL-1); i++) {
                bg_val -= diff;
                mid_vals[1][i] = bg_val;
            }
        }
        /* Blue */
        fg_val = (fgcolor & 0x1f) << 3;
        bg_val = (bgcolor & 0x1f) << 3;
        mid_vals[2][0] = bg_val;
        mid_vals[2][(CLEVEL-1)] = fg_val;
        if (fg_val > bg_val) {
            diff = (fg_val - bg_val)/(CLEVEL-1);
            for (i = 1; i < (CLEVEL-1); i++) {
                bg_val += diff;
                mid_vals[2][i] = bg_val;
            }
        } else {
            diff = (bg_val - fg_val)/(CLEVEL-1);
            for (i = 1; i < (CLEVEL-1); i++) {
                bg_val -= diff;
                mid_vals[2][i] = bg_val;
            }
        }
        for (i = 0; i < CLEVEL; i++) {
#ifdef ORG_CODE
            rval = mid_vals[0][i];
            gval = mid_vals[1][i];
            bval = mid_vals[2][i];
            ptab->mid_color[i] = ((rval >> 3) << 11) |
                                 ((gval >> 2) << 5) |
                                 (bval >> 3);
#else
            wval = rval = mid_vals[0][i];
            rval = rval >> 3;
            if (rval == 0 && wval) rval = 1;
            wval = gval = mid_vals[1][i];
            gval = gval >> 2;
            if (gval == 0 && wval) gval = 1;
            wval = bval = mid_vals[2][i];
            bval = bval >> 3;
            if (bval == 0 && wval) bval = 1;
            ptab->mid_color[i] = (rval << 11) | (gval << 5) | bval;
#endif
        }
        ptab->fgcolor = fgcolor;
        ptab->bgcolor = bgcolor;
#ifdef GVDEBUG
        for (i = 0; i < CLEVEL; i++) {
          syslog(LOG_NOTICE, "%04x  %04x  %04x    %04x",
                mid_vals[0][i], mid_vals[1][i],
                mid_vals[2][i], ptab->mid_color[i]);
        }
#endif
    }
}

void romfont_open(struct font_desc *fdesc, int start_page)
{
    struct font_header fh_data;

    /* font_header is located at top of start_page */
    nand_load(start_page, 0, sizeof(struct font_header), (UB *)&fh_data);
    fdesc->startpage = start_page;
    fdesc->mincode = fh_data.mincode;
    fdesc->maxcode = fh_data.maxcode;
    fdesc->height = fh_data.height;
    fdesc->ascender = fh_data.ascender;
    fdesc->descender = fh_data.descender;
    fdesc->mono = 0;       /* ROM font is not MONO font */
    /* char_desc table is located next to font_header */
    fdesc->chartab = (struct char_desc *)sizeof(struct font_header);
    fdesc->baseaddr = 0;
}

/* Load char_desc information for given string. */
struct char_desc *load_rom_char_desc(struct font_desc *fdesc, int utf8, UH *str, UB **dp)
{
    struct char_desc *cdesc;
    struct font_desc *efdesc;
    UH code, *sp;
    UW offset;
    int (*f_index)();
    extern int code_index(), utf_index();

    if (utf8)
        f_index = utf_index;
    else
        f_index = code_index;
    efdesc = fdesc->efont;
    cdesc = chardesc_tab;
    while (*str) {
        code = *str;
#ifdef USE_IPAGUI
        if (code >= 0x20 && code < 0x80) {
            offset = sizeof(struct font_header) + code_index(code) * sizeof(struct char_desc);
            nand_load(efdesc->startpage, offset, sizeof(struct char_desc),
                (UB *)cdesc);
            cdesc++;
        } else if (code >= fdesc->mincode && code <= fdesc->maxcode) {
            offset = sizeof(struct font_header) + code_index(code) * sizeof(struct char_desc);
            nand_load(fdesc->startpage, offset, sizeof(struct char_desc),
                (UB *)cdesc);
            cdesc++;
        }
#else
        if (code >= fdesc->mincode && code <= fdesc->maxcode) {
            offset = sizeof(struct font_header) + f_index(code) * sizeof(struct char_desc);
            nand_load(fdesc->startpage, offset, sizeof(struct char_desc),
                (UB *)cdesc);
            cdesc++;
        }
#endif
        str++;
    }
    cdesc->offset = 0;
    cdesc++;
    *dp = (UB *)cdesc;
    return chardesc_tab;
}

inline void load_rom_bitmap(struct font_desc *fdesc, struct char_desc *cdesc, UB *dp)
{
    nand_load(fdesc->startpage, cdesc->offset,
    cdesc->width * cdesc->height, dp);
}

void romfont_string(struct font_desc *fdesc, int utf8, UH *str, int xpos, int ypos, int width, int fgcolor, int bgcolor)
{
    int i, j, oxpos;
    UB *data;
    UH code, color;
    struct char_desc *cdesc;

    oxpos = xpos;
    gen_colortab(fgcolor, bgcolor, &colortab);
    cdesc = load_rom_char_desc(fdesc, utf8, str, &data);
    while (*str) {
        code = *str;
        if (code >= fdesc->mincode && code <= fdesc->maxcode) {
            if (xpos + cdesc->left + cdesc->width - 1 > oxpos + width) {
syslog(LOG_NOTICE, "!! code : %x, xpos = %d, left = %d, width = %d", code, xpos, cdesc->left, cdesc->width);
                break;
            }
            if (ypos + fdesc->height - fdesc->descender > LCD_HEIGHT) {
syslog(LOG_NOTICE, "## %x", code);
                break;
            }
#ifdef USE_IPAGUI
            if (code < 0x80) {
                load_rom_bitmap(fdesc->efont, cdesc, char_bitmap);
            } else {
                load_rom_bitmap(fdesc, cdesc, char_bitmap);
            }
#else
            load_rom_bitmap(fdesc, cdesc, char_bitmap);
#endif
            data = char_bitmap;
#ifdef RDEBUG
            if (debug) {
                syslog(LOG_NOTICE, "code: %x", code);
                syslog(LOG_NOTICE, "width: %d, height: %d, top: %d, left: %d, advance: %d", cdesc->width, cdesc->height, cdesc->top, cdesc->top, cdesc->advance);
                syslog(LOG_NOTICE, "base: %x, offset: %x, data: %x", fdesc->baseaddr, cdesc->offset, data);
            }
#endif
            lcd_set_address(xpos + cdesc->left, ypos + fdesc->height - cdesc->top);
            lcd_set_register(H_ADDR_START_POSITION, xpos + cdesc->left);
            lcd_set_register(V_ADDR_START_POSITION, ypos + fdesc->height - cdesc->top);
            lcd_set_register(H_ADDR_END_POSITION, xpos + cdesc->left + cdesc->width - 1);
            lcd_set_register(V_ADDR_END_POSITION, ypos + fdesc->height - fdesc->descender);

            lcd_write_command(WRITE_DATA_TO_GRAM);
            for (i = 0; i < cdesc->height; i++) {
                for (j = 0; j < cdesc->width; j++) {
#ifdef CDEBUG
syslog(LOG_NOTICE, "data: %x --> %x", *data >> CSHIFT, colortab.mid_color[*data >> CSHIFT]);
dly_tsk(30);
#endif
                    color = colortab.mid_color[*data++ >> CSHIFT];
                    lcd_write_data(color);
                }
            }
            xpos += cdesc->advance;
            cdesc++;
        }
        str++;
    }
}

int romfont_string_width(struct font_desc *fdesc, int utf8, UH *str)
{
    int width;
    struct char_desc *cdesc;
    UB *data;

    cdesc = load_rom_char_desc(fdesc, utf8, str, &data);
    for (width = 0; cdesc->offset; cdesc++) {
        width += cdesc->advance;
    }

    return width;
}

void romfont_string_put(struct font_desc *fdesc, int utf8, UH *str, struct region *regionp, int fgcolor, int bgcolor, int align)
{
    int width;
    struct char_desc *cdesc, *wc;
    UB *data;

    cdesc = load_rom_char_desc(fdesc, utf8, str, &data);
    width = 0;
    for (wc = cdesc; wc->offset; wc++) {
        width += wc->advance;
    }
    if (width > regionp->width) align = AL_LEFT;
    lcd_reset_window();
    lcd_fill_rect(regionp->xpos, regionp->ypos, regionp->width, regionp->height, bgcolor);
    if (str == NULL)
        return;
    switch (align) {
    case AL_LEFT:
        romfont_string(fdesc, utf8, str, regionp->xpos, regionp->ypos, regionp->width, fgcolor, bgcolor);
        break;
    case AL_RIGHT:
        romfont_string(fdesc, utf8, str, regionp->xpos + regionp->width - width,
                regionp->ypos, regionp->width, fgcolor, bgcolor);
        break;
    case AL_CENTER:
        romfont_string(fdesc, utf8, str, regionp->xpos + (regionp->width -width)/2,
                regionp->ypos, regionp->width, fgcolor, bgcolor);
        break;
    }
}

void font_open(struct font_desc *fdesc, const UB *fdata)
{
    struct font_header *fh = (struct font_header *)fdata;
    struct char_desc *cdesc;

    fdesc->mincode = fh->mincode;
    fdesc->maxcode = fh->maxcode;
    fdesc->height = fh->height;
    fdesc->ascender = fh->ascender;
    fdesc->descender = fh->descender;
    fdesc->mono = 1;        /* Assume mono mode font */
    cdesc = fdesc->chartab = (struct char_desc *)(fdata + sizeof(struct font_header));
    fdesc->baseaddr = fdata;
    while (cdesc->width == 0) cdesc++;
    if (cdesc->width == cdesc->pitch) fdesc->mono = 0;
}

static int font_string_width(struct font_desc *fdesc, UH *str)
{
    int width = 0;
    UH code;
    struct char_desc *cdesc;

    while (*str) {
        code = *str;
        if (code >= fdesc->mincode && code <= fdesc->maxcode) {
            cdesc = fdesc->chartab + (code - fdesc->mincode);
            width += cdesc->advance;
        }
        str++;
    }
    return width;
}

int font_max_width(struct font_desc *fdesc)
{
    int width = 0;
    UH code;
    struct char_desc *cdesc;

    for (code = fdesc->mincode; code <= fdesc->maxcode; code++) {
        cdesc = fdesc->chartab + (code - fdesc->mincode);
        if (cdesc->advance > width)
            width = cdesc->advance;
    }
    return width;
}

void font_string(struct font_desc *fdesc, UH *str, int xpos, int ypos, int fgcolor, int bgcolor)
{
    int i, j;
    const UB *data;
    UH code, width, color, nb;
    struct char_desc *cdesc;

    if (fdesc->mono == 0) {
        gen_colortab(fgcolor, bgcolor, &colortab);
    }
    while (*str) {
        code = *str;
        if (code >= fdesc->mincode && code <= fdesc->maxcode) {
            cdesc = fdesc->chartab + (code - fdesc->mincode);
            width = cdesc->advance;
            data = fdesc->baseaddr + cdesc->offset;
#ifdef DEBUG
cons_printf("code: %x\n", code);
cons_printf("width: %d, height: %d, top: %d, left: %d, advance: %d\n", cdesc->width, cdesc->height, cdesc->top, cdesc->top, cdesc->advance);
cons_printf("base: %x, offset: %x, data: %x\n", fdesc->baseaddr, cdesc->offset, data);
#endif
            nb = cdesc->pitch;
            lcd_set_address(xpos + cdesc->left, ypos + fdesc->height - cdesc->top);
            lcd_set_register(H_ADDR_START_POSITION, xpos + cdesc->left);
            lcd_set_register(V_ADDR_START_POSITION, ypos + fdesc->height - cdesc->top);
            lcd_set_register(H_ADDR_END_POSITION, xpos + cdesc->left + cdesc->width - 1);
            lcd_set_register(V_ADDR_END_POSITION, ypos + fdesc->height - fdesc->descender);

            lcd_write_command(WRITE_DATA_TO_GRAM);
            if (fdesc->mono) {
                for (i = 0; i < cdesc->height; i++) {
                  for (j = 0; j < cdesc->width; j++) {
                    color = (data[j >> 3] & (0x80 >> (j&7)))? fgcolor : bgcolor;
                    lcd_write_data(color);
                  }
                  data += nb;
                }
            } else {
                for (i = 0; i < cdesc->height; i++) {
                  for (j = 0; j < cdesc->width; j++) {
                    color = colortab.mid_color[*data++ >> CSHIFT];
                    lcd_write_data(color);
                  }
                }
            }
            xpos += cdesc->advance;
        }
        str++;
    }
}

void font_string_put(struct font_desc *fdesc, UH *str, struct region *regionp, int fgcolor, int bgcolor, int align)
{
    int width;

    width = font_string_width(fdesc, str);
    if (width > regionp->width) align = AL_LEFT;
    lcd_reset_window();
    lcd_fill_rect(regionp->xpos, regionp->ypos, regionp->width, regionp->height, bgcolor);
    if (str == NULL)
        return;
    switch (align) {
    case AL_LEFT:
        font_string(fdesc, str, regionp->xpos, regionp->ypos, fgcolor, bgcolor);
        break;
    case AL_RIGHT:
        font_string(fdesc, str, regionp->xpos + regionp->width - width,
                regionp->ypos, fgcolor, bgcolor);
        break;
    case AL_CENTER:
        font_string(fdesc, str, regionp->xpos + (regionp->width -width)/2,
                regionp->ypos, fgcolor, bgcolor);
        break;
    }
}

void put_xval(UH **pstr, UH *xdigits, int val)
{
    UB vtemp[6];
    int ix;
    UH *str = *pstr;

    ix = 0;
    do {
        vtemp[ix++] = val % 10;
        val /= 10;
    } while (val != 0);
   
    if (ix < 2)
        *str++ = xdigits['0' - '/'];
    while (ix-- > 0) {
        *str++= xdigits[vtemp[ix] + '0' - '/'];
    }
    *str = 0;
    *pstr = str;
}

#include "fontdir/xstr_ipaexg25.h"
#include "fontdir/fdata_ipaexg25.c"
#include "fontdir/xstr_ipaexg10.h"
#include "fontdir/fdata_ipaexg10.c"

static struct font_desc tfont, dfont, afont;
static struct font_desc k10font, k13font;
static struct font_desc e10font, e13font;

/*
 * ROM fonts are burnt into NAND Flash. When open rom fonts, we specify
 * its starting page within the NAND flash. Below is the list of available
 * fonts and its startng page.
 *
 * ipagui10.fnt    Start@32
 * ipagui13.fnt    Start@1938
 * GenBasB10.fnt   Start@5100
 * GenBasB13.fnt   Start@5111
 * GenBkBasR10.fnt Start@5126
 * GenBkBasR13.fnt Start@5137
 * ipaexg10.fnt    Start@5152
 * ipaexg13.fnt    Start@7809
 * XXXX.fnt Start@11944
 *
 * All fonts are created from TrueType format files.
 *
 * In order to burn font images into NAND, use `copy' command.
 * See also fat.c for copy command.
 *
 *   ex. copy romdat10.fnt 32
 */

void font_init()
{
#ifdef USE_IPAGUI
    romfont_open(&k10font, 32);
    romfont_open(&k13font, 1938);
#else
    romfont_open(&k10font, 5152);
    romfont_open(&k13font, 7809);
#endif
    romfont_open(&e10font, 5126);
    romfont_open(&e13font, 5137);
    k10font.efont = &e10font;
    k13font.efont = &e13font;

    font_open(&tfont, fdata_ipaexg25);
    tfont.maxwidth = font_max_width(&tfont);
    font_open(&dfont, fdata_ipaexg10);
    dfont.maxwidth = font_max_width(&dfont);
}

static struct region freq_region = { 20, 160, 190, 50 };

void disp_station_freq(int freq)
{
    char freq_str[10];
    char *cp;
    UH Xfreq_str[10];
    UH *pxstr;

    str_printf(freq_str, "%d.%d", freq / 10, freq % 10);
    pxstr = Xfreq_str;
    for (cp = freq_str; *cp; cp++) {
        if (*cp == '.')
            *pxstr++ = XStrFreq[10];
        else
            *pxstr++ = XStrFreq[*cp - '0'];
    }
    memcpy(pxstr, XStrMHz, sizeof(XStrMHz));
    font_string_put(&tfont, Xfreq_str, &freq_region, C_BLACK, C_WHITE, AL_RIGHT);
}

static struct region title_region = { 10, TITLE_Y, 220, 50 };
static struct region performer_region = { PERFORMER_X, PERFORMER_Y, LCD_WIDTH-PERFORMER_X, 40 };
static struct region album_region = { ALBUM_X, ALBUM_Y, LCD_WIDTH-ALBUM_X, 40 };

void draw_info_line(int file_type, char *pstr, struct region *pregion)
{
    int width, utf8;
    struct font_desc *fdesc;
    unsigned char *cp;
    UH Xstrb[MAX_SONG_NAME+1], uval, *xp;

    xp = Xstrb;
    utf8 = (file_type == TYPE_M4A);
    for (cp = (unsigned char *)pstr; *cp; cp++) {
        if (*cp < 0x80)
            *xp++ = *cp;
        else {
            if (utf8) { /* three byte UTF-8 code */
                uval = (*cp++ & 0x0f) << 12;
                uval |= (*cp++ & 0x3f) << 6;
                uval |= (*cp & 0x3f);
            } else { /* two byte SJIS code */
                uval = *cp++ << 8;
                uval |= *cp & 0xff;
            }
            *xp++ = uval;
        }
    }
    *xp = 0;

    fdesc = &k13font;
    width = romfont_string_width(fdesc, utf8, Xstrb);
    if (width > pregion->width)
        fdesc = &k10font;
    romfont_string_put(fdesc, utf8, Xstrb, pregion, C_BLACK, C_WHITE, AL_CENTER);
}

static const char *ftype_str[] = { "MP3", "M4A", "WAV" };

void display_song_info(Player_Status *pst)
{
    unsigned char *cp;
    char work[20], *ftype;

    wai_sem(SEM_LCD);

    draw_info_line(pst->file_type, pst->song_name, &title_region);
    draw_info_line(pst->file_type, pst->performer_name, &performer_region);
    draw_info_line(pst->file_type, pst->album_name, &album_region);

    /* File type and song number within an album */
    str_printf(work, "%s  %d/%d", ftype_str[pst->file_type], pst->cur_track, pst->max_track);
    lcd_fill_rect(90, SNUMBER_Y+24, 60, 12, C_WHITE);
    lcd_string(work, FT_NORMAL, 90, SNUMBER_Y+24, C_BLACK, C_WHITE);

    lcd_fill_rect(18, BAR_Y-2, 203, 24, C_BLUE);
    lcd_fill_rect(20, BAR_Y, 200, 20, C_WHITE);
    sig_sem(SEM_LCD);
}

void display_volume(int level)
{
    wai_sem(SEM_LCD);
    lcd_fill_rect(58, VOL_Y+4, 123, 24, C_BLUE);
    lcd_fill_rect(60, VOL_Y+6, 120, 20, C_WHITE);
    lcd_fill_rect(60, VOL_Y+6, 12 * level, 20, C_LBLUE);
    sig_sem(SEM_LCD);
}

void display_progress_bar(int progress, int tpassed, int tleft)
{
    char stpassed[10], stleft[10];

    wai_sem(SEM_LCD);
    tpassed /= 1000;
    tleft /= 1000;
    lcd_fill_rect(20, BAR_Y, progress, 20, C_BLACK);

    str_printf(stpassed, "%d:%02d", tpassed / 60, tpassed % 60);
    str_printf(stleft, "-%d:%02d", tleft / 60, tleft % 60);
    lcd_fill_rect(20, METER_Y, 200, 10, C_WHITE);
    lcd_string(stpassed, FT_NORMAL, 20, METER_Y, C_BLACK, C_WHITE);
    lcd_string(stleft, FT_NORMAL, 220 - 8 * strlen(stleft), METER_Y, C_BLACK, C_WHITE);
    
    sig_sem(SEM_LCD);
}

#define	TIME_X	30
#define	TIME_Y	225
#define	TIME_W	190

#define	DATE_X	50
#define	DATE_Y	265

void show_time(int mode)
{
    UH Xtimestr[10], *pxstr;

    pxstr = Xtimestr;
    put_xval(&pxstr, XStrTDigits, (RTC_CTIME0 >> 16) & 0x1f);
    *pxstr++ = XStrTDigits[':' - '/'];
    put_xval(&pxstr, XStrTDigits, (RTC_CTIME0 >> 8) & 0x3f);
    *pxstr++ = XStrTDigits[':' - '/'];
    put_xval(&pxstr, XStrTDigits,  RTC_CTIME0 & 0x3f);

    wai_sem(SEM_LCD);
    if (mode) {
        lcd_fill_rect(160, 5, 80, dfont.height - dfont.descender, C_WHITE);
        font_string(&dfont, Xtimestr, 160, 5, C_BLACK, C_WHITE);
    } else {
        lcd_fill_rect(TIME_X, TIME_Y, TIME_W, tfont.height - tfont.descender, C_BLACK);
        font_string(&tfont, Xtimestr, TIME_X, TIME_Y, C_WHITE, C_BLACK);
    }
    lcd_reset_window();
    sig_sem(SEM_LCD);
}

void show_date(int mode)
{
    UH Xdatestr[12], *pxstr;

    pxstr = Xdatestr;
    put_xval(&pxstr, XStrDDigits, (RTC_CTIME1 >> 16) & 0x7ff);
    *pxstr++ = XStrDDigits['/' - '/'];
    put_xval(&pxstr, XStrDDigits, (RTC_CTIME1 >> 8) & 0x0f);
    *pxstr++ = XStrDDigits['/' - '/'];
    put_xval(&pxstr, XStrDDigits, RTC_CTIME1 & 0x1f);

    wai_sem(SEM_LCD);
    lcd_fill_rect(DATE_X, DATE_Y, dfont.maxwidth * 8, dfont.height - dfont.descender, C_BLACK);
    font_string(&dfont, Xdatestr, DATE_X, DATE_Y, C_WHITE, C_BLACK);

    Xdatestr[0] = XStrWeekdays[RTC_DOW];
    Xdatestr[1] = 0;
    lcd_fill_rect(DATE_X+dfont.maxwidth*8, DATE_Y, dfont.maxwidth * 2, dfont.height - dfont.descender, C_BLACK);
    font_string(&dfont, Xdatestr, DATE_X+dfont.maxwidth*7, DATE_Y, C_WHITE, C_BLACK);
    lcd_reset_window();
    sig_sem(SEM_LCD);
}

void hide_colon()
{
    UH Xtimestr[10], *pxstr;
    int w1, w2;

    pxstr = Xtimestr;
    put_xval(&pxstr, XStrTDigits, 0);
    w1 = font_string_width(&tfont, Xtimestr);
    *pxstr++ = XStrTDigits[':' - '/'];
    *pxstr = 0;
    w2 = font_string_width(&tfont, Xtimestr) - w1;
    wai_sem(SEM_LCD);
    lcd_fill_rect(TIME_X + w1, TIME_Y, w2, tfont.height - tfont.descender, C_BLACK);

    put_xval(&pxstr, XStrTDigits, 0);
    w1 = font_string_width(&tfont, Xtimestr);
    lcd_fill_rect(TIME_X + w1, TIME_Y, w2, tfont.height - tfont.descender, C_BLACK);
    lcd_reset_window();
    sig_sem(SEM_LCD);
}

void time_command(int argc, char **argv)
{
    show_time(0);
}

#ifdef TESTCODE
void new_test()
{
    struct region rg;

    rg.xpos = 15; rg.ypos = 50;
    rg.width = 210; rg.height = j1font.height + 4;
    lcd_reset_window();
    lcd_clear_screen(C_WHITE);
    font_string_put(&j1font, XStrJapan1, &rg, C_BLACK, C_WHITE, AL_CENTER);
    rg.xpos = 15; rg.ypos = 70;
    font_string_put(&j1font, XStrEng1, &rg, C_BLACK, C_WHITE, AL_CENTER);
    rg.xpos = 15; rg.ypos = 90;
    font_string_put(&j1sfont, XStrJapan1s, &rg, C_BLACK, C_WHITE, AL_CENTER);
    rg.xpos = 15; rg.ypos = 105;
    font_string_put(&j1sfont, XStrEng1s, &rg, C_BLACK, C_WHITE, AL_CENTER);

    rg.xpos = 15; rg.ypos = 160;
    font_string_put(&j2font, XStrJapan2, &rg, C_BLACK, C_WHITE, AL_CENTER);
    rg.xpos = 15; rg.ypos = 180;
    font_string_put(&j2font, XStrEng2, &rg, C_BLACK, C_WHITE, AL_CENTER);
    rg.xpos = 15; rg.ypos = 200;
    font_string_put(&j2sfont, XStrJapan2s, &rg, C_BLACK, C_WHITE, AL_CENTER);
    rg.xpos = 15; rg.ypos = 215;
    font_string_put(&j2sfont, XStrEng2s, &rg, C_BLACK, C_WHITE, AL_CENTER);
}
#endif

static const UH aastring[] = { 0x97ce, 0x82cc, 0x8b43, 0x947a, 0x0000 };
#ifdef TEST_CODE
UH kanji_str[60];

void rom_test(int argc)
{
    struct char_desc *cdesc;
    struct font_desc *fdesc;
    UB *data;
    UH code;
    int i, width;
    int xpos, ypos;
    extern UH sjis2uni[];

    romfont_open(&k10font, 32);
    romfont_open(&k13font, 1938);

    if (argc > 1) {
        fdesc = &k13font;
    } else {
        fdesc = &k10font;
    }
    cdesc = load_rom_char_desc(fdesc, 0, (UH *)aastring, &data);
    width = 0;
    while (cdesc->offset) {
        width += cdesc->advance;
        cdesc++;
    }
    width /= 2;
    xpos = 0; ypos = 3;
    code = 758;
    while (ypos < LCD_HEIGHT) {
        for (i = 0; i < LCD_WIDTH/width; i++) {
            kanji_str[i] = sjis2uni[code*2];
            code++;
        }
        kanji_str[i] = 0;
        romfont_string(fdesc, 0, kanji_str, xpos, ypos, LCD_WIDTH, C_BLACK, C_WHITE);
        ypos += width;
    }
}
#else
void rom_test(int argc)
{
    struct char_desc *cdesc;
    struct font_desc *fdesc;
    UB *data;
    UH code;
    int i, width;
    int xpos, ypos;

    if (argc > 1) {
        fdesc = &k13font;
    } else {
        fdesc = &k10font;
    }
    romfont_string(fdesc, 0, (UH *)aastring, 60, 30, LCD_WIDTH, C_WHITE, C_BLACK);
}
#endif

void ftest_command(int argc, char **argv)
{
#ifdef TESTCODE
    new_test();
    lcd_clear_screen(C_WHITE);
    rom_test(argc);
#endif
    rom_test(argc);
}
