| 
/***********************************(AQM1248A_v5.c)*******
 *     AQM1248A グラフィックライブラリ(spi-vRam付き)
 **********************************************************/
#include "myProject.h"
#include "Font_5x7.h"
#define VRAM_ADR    0x80000
#define LCG_C_SIZE  128
//---  フォントデータアドレス(GT20L16J1Y)  (EEPROM)
#define F_HALF  0x3E7E0     // 半角         0x00200
#define F_SYM   0x00000     // 記号         0x01000
#define F_SYM2  0x00BC0     // 記号2        0x01C00
#define F_NUM   0x01960     // 数字         0x01E00
#define F_ASC   0x01B80     // ASC(大)     0x02000
#define F_ASC2  0x01F80     // ASC2(小)    0x02400
#define F_HIRA  0x02340     // ひらかな     0x02800
#define F_KATA  0x02F00     // カタカナ     0x03260
#define F_KAN1  0x0AA40     // 漢字1水準   0x04000
#define F_KAN2  0x21CE0     // 漢字2水準   -------
#define U_MAP   0x8BC00     // usrFontMap   0x00C00
#define U_FONT  0x8C000     // usrFontDat   0x1C000
#define H_BLANK     0x007F0
static uint8_t vBf[32];     // フォントパターン用バッファー
static uint8_t uMap[128];
const char Z_Small_o[]=     // フォントスモール'o'
            {0x00,0x00,0x00,0x00,0x00,0xC0,0x20,0x10,
             0x10,0x20,0xC0,0x00,0x00,0x00,0x00,0x00,
             0x00,0x00,0x00,0x00,0x00,0x03,0x04,0x08,
             0x08,0x04,0x03,0x00,0x00,0x00,0x00,0x00 };
//--- SPI-vRam アクセス関数
uint8_t vRam_read(uint8_t xpos, uint8_t ypos){
    uint32_t adr;
    adr = VRAM_ADR + (uint32_t)ypos * LCG_C_SIZE + xpos;
    return SPI_Mem_Read(adr);
}
void vRam_write(uint8_t xpos, uint8_t ypos, uint8_t dat){
    uint32_t adr;
    adr = VRAM_ADR + (uint32_t)ypos * LCG_C_SIZE + xpos;
    SPI_Mem_Write(adr, dat);
}
void vRam_Nread(uint8_t xpos,uint8_t ypos,char *ptn,uint8_t n){
    uint32_t adr;
    adr = VRAM_ADR + (uint32_t)ypos * LCG_C_SIZE + xpos;
    SPI_Mem_NRead(adr,(uint8_t *)ptn,n);
}
void vRam_Nwrite(uint8_t xpos,uint8_t ypos,char *ptn,uint8_t n){
    uint32_t adr;
    adr = VRAM_ADR + (uint32_t)ypos * LCG_C_SIZE + xpos;
    SPI_Mem_NWrite(adr,(uint8_t *)ptn,n);
}
//-------- G-LCDを初期化 ------------------------------------
void gLCD_int(void){
    gCS_SetLow();                   // gLCDセレクト有効
    gRS_SetLow();                   // コマンドデータ指定
    SPI1_ExchangeByte(0xAE);        // Display = OFF
    SPI1_ExchangeByte(0xA0);        // ADC = normal
    SPI1_ExchangeByte(0xC8);        // C.output = revers
    SPI1_ExchangeByte(0xA3);        // bias = 1/7
    SPI1_ExchangeByte(0x2C);        // power control 1
    __delay_ms(2);                  // 2mS遅延
    SPI1_ExchangeByte(0x2E);        // power control 2
    __delay_ms(2);                  // 2mS遅延
    SPI1_ExchangeByte(0x2F);   	    // power control 3
    SPI1_ExchangeByte(0x23);        // Vo ratio set
    SPI1_ExchangeByte(0x81);        // E-volume mode
    SPI1_ExchangeByte(0x1C);        // E-volume value
    SPI1_ExchangeByte(0xA4);        // 全点灯しない
    SPI1_ExchangeByte(0x40);        // start line = 0
    SPI1_ExchangeByte(0xA6);        // 白黒反転しない
    SPI1_ExchangeByte(0xAF);        // Display = ON
    gCS_SetHigh();                  // gLCDセレクト無効
}
//-------- G-LCDのデータを全消去(指定データで埋める)---
void gLCD_clr(char dat){			
    uint8_t x, y;
    gCS_SetLow();                   // gLCDセレクト有効
    for(y = 0; y < 6; y++){
        gRS_SetLow();               // コマンド指定
        SPI1_ExchangeByte(0xB0 + y);
        SPI1_ExchangeByte(0x10);
        SPI1_ExchangeByte(0x00);
        gRS_SetHigh();              // 表示データ指定
        for(x = 0; x < 128; x++){
            SPI1_ExchangeByte(dat);
        }
    }
    gCS_SetHigh();                  // gLCDセレクト無効
    for(y = 0; y < 6; y++){
        for(x = 0; x < 128; x++){
            vRam_write(x,y,dat);    // vRamクリア
        }
    }
}
//-------- カーソル位置指定 -----------------------------------
void gLCD_posXY(uint8_t xpos, uint8_t ypos){
    gCS_SetLow();                   // チップセレクト有効
    gRS_SetLow();                   // コマンド指定
    SPI1_ExchangeByte(0xB0 | (ypos >> 3));
    SPI1_ExchangeByte(0x10 | (xpos >> 4));
    SPI1_ExchangeByte(xpos & 0x0F);
    gCS_SetHigh();                  // チップセレクト無効
}
//-------- バイト単位で文字表示(次xpos位置を返す) ---------
uint8_t gLCD_chrX(uint8_t xpos, uint8_t ypos, char chr){
    uint8_t i, sx, yAdr, ptn;
    chr -= 0x20;                    //配列アドレスを計算
    gLCD_posXY(xpos, ypos);         //表示位置を指定
    sx = xpos;                      // posxを保存
    yAdr = ypos >> 3;
    gCS_SetLow();                   // チップセレクト有効
    gRS_SetHigh();                  // 表示データ指定
    for(i = 0; i < 5; i++) {        //データを順に取得
        ptn = Font[chr][i];
        if(ptn == 0xFF)  break;     //幅狭文字なら抜ける
        vBf[i] = ptn;
        SPI1_ExchangeByte(ptn);
        xpos++;
    }
    vBf[i] = 0;
    SPI1_ExchangeByte(0);           //文字間隔を空ける
    xpos++;
    gCS_SetHigh();                  // チップセレクト無効
    vRam_Nwrite(sx,ypos,(char *)vBf, i);  // vRamに書き込む 
    return xpos;                    //次表示位置を返す
}
//-------- バイト単位で文字列表示(次xpos位置を返す)-----
uint8_t gLCD_strX(uint8_t xpos, uint8_t ypos, char *str){
    while(*str)  xpos = gLCD_chrX(xpos, ypos, *str++);
    return xpos;                    //次表示位置を返す
}
//-------- バイト単位でパターンを表示(次xpos位置を返す)-
uint8_t gLCD_ptnX(uint8_t xpos, uint8_t ypos, char *ptn, uint8_t n){
    uint8_t i, yAdr;
    gLCD_posXY(xpos, ypos);         // 表示位置を指定
    gCS_SetLow();                   // チップセレクト有効
    gRS_SetHigh();                  // 表示データ指定
    yAdr = ypos >> 3;
    for(i = 0; i < n; i++){
         SPI1_ExchangeByte(*(ptn + i));
    }
    gCS_SetHigh();                  // チップセレクト無効
    vRam_Nwrite(xpos,ypos,ptn,n);
    return xpos + n;                // 次表示位置を返す
}
//---- バイト単位でn個の指定データで埋める(次xpos位置を返す)
uint8_t LCD_clrX(uint8_t xpos, uint8_t ypos, char dat, uint8_t n){
    uint8_t i, yAdr;
    gLCD_posXY(xpos,ypos);          // 表示位置を指定
    gCS_SetLow();                   // チップセレクト有効
    gRS_SetHigh();                  // 表示データ指定
    yAdr = ypos >> 3;
    for(i = 0; i < n; i++) {
        SPI1_ExchangeByte(dat);
    }
    gCS_SetHigh();                  // チップセレクト無効
    for(i=0;i<// 次開始位置を返す
}
//---- バイト単位で(縦)16ドットパターン(漢字など)の表示
/*  xpos: X位置、   ypos: Y位置
 *  *pKj: 漢字パターンデータポインタ、 cdt: 漢字横ドット数
 *---------------------------------------------------- */
uint8_t gLCD_nk16X(uint8_t xpos, uint8_t ypos, char *pKj, uint8_t cdt){
    gLCD_ptnX(xpos, ypos,(char *)pKj, cdt); 
    xpos = gLCD_ptnX(xpos, ypos+8, (char *)(pKj + cdt),cdt);
    return xpos;
}
//---- 半角(8x16)文字表示(次xpos位置を返す)-----
uint8_t gLCD_HchrX(uint8_t xpos, uint8_t ypos, uint8_t chCode){
    uint32_t adr;
    if((chCode >= 0x20) & (chCode < 0x7F)){
        adr = (chCode - 0x20) * 16 + F_HALF;
    }else{
        adr = H_BLANK;              // 半角ブランク表示
    }
    SPI_Mem_NRead(adr,(uint8_t *)vBf,16);
    xpos = gLCD_nk16X(xpos, ypos, (char *)vBf, 8);        
    return xpos;
}
//-------- バイト単位で半角文字列表示(次xpos位置を返す)-----
uint8_t gLCD_HstrX(uint8_t xpos, uint8_t ypos, char *str){
    while(*str)  xpos = gLCD_HchrX(xpos, ypos, *str++);
    return xpos;                    //次表示位置を返す
}
//--- 行をクリアして半角文字列表示(次xpos位置を返す)
uint8_t prtHstr_LnClr(uint8_t xpos, uint8_t ypos,char* str){
    gLCD_clrX(0,ypos  ,0,LCG_C_SIZE);
    #ifdef FONT_ROM
        gLCD_clrX(0,ypos+8,0,LCG_C_SIZE);
        return gLCD_HstrX(xpos,ypos,str);
    #else
        return  gLCD_strX(xpos,ypos,str);
    #endif
}
//--- ユーザー漢字マップ読出し
void read_UsrMap(uint8_t p){
    uint32_t ad;
    ad = U_MAP + p * 128;
    SPI_Mem_NRead(ad,uMap,128);
}
//--- ユーザー文字格納アドレス取得
uint32_t get_UFntAdr(uint16_t kCode){
    uint8_t pg,i;
    uint16_t *usrP;
    usrP = (uint16_t*)uMap;
    for(pg = 0; pg < 8; pg++){
        read_UsrMap(pg);
        for(i = 0; i < 64; i++){
            if(*usrP == 0xFFFF) return 0;
            if(*usrP == kCode)  return U_FONT + pg * 2048 + i * 32;
            usrP++;
        }
    }
    return 0;
}
/*--- JISー>シフトJIS変換
uint16_t Jis2SJis(uint16_t jCd){
    uint8_t hi,lo;
    hi = jCd >> 8;
    lo = (uint8_t)jCd;
    if(hi && 1){
        if(lo < 0x60)   lo = lo + 0x1F;
        else            lo = lo + 0x20;
    }else{              lo = lo + 0x7E;
    }
    if(hi < 0x5F)       hi = (hi + 0xE1) >> 1;
    else                hi = (hi + 0x161) >> 1;
    return (hi * 256 + lo);
}
*/
//---- シフトJISー>JIS変換
uint16_t SJis2Jis(uint16_t sCd){
    uint8_t hi,lo;
    hi = sCd >> 8;
    lo = (uint8_t)sCd;
    if(hi <= 0x9F){
        if(lo < 0x9F)   hi = hi * 2 - 0xE1;
        else            hi = hi * 2 - 0xE0;
    }else{
        if(lo < 0x9F)   hi = (hi - 0xB0) * 2 - 1;
        else            hi = (hi - 0xB0) * 2;
    }
    if(lo < 0x7F)       lo = lo - 0x1F;
    else{
        if(lo < 0x9F)   lo = lo - 0x20;
        else            lo = lo - 0x7E;
    }
    return (hi * 256 + lo);
}
//--- 全角(漢字)フォントアドレス取得)
uint32_t KfntAdr(uint16_t kCode){
    uint8_t msb, lsb;
    uint32_t lmsb, llsb;
    msb = kCode >> 8;
    lsb = (uint8_t)kCode & 0x000FF;
    lmsb = (uint32_t)msb;
    llsb = (uint32_t)lsb;
    if(msb>=0x21 & msb<0x30){
        if(msb==0x21){                      // 記号1
            if(lsb>=0x21 & lsb<=0x7E) return F_SYM + (lsb-0x21)*32;
            else                      return get_UFntAdr(kCode);
        }else if(msb==0x22){                // 記号2
            if(lsb>=0x21 & lsb<=0x2E) return F_SYM2 + (lsb-0x21)*32;
            else                      return get_UFntAdr(kCode);
        }else if(msb==0x23){                // ASCII
            if(lsb>=0x30 & lsb<=0x39) return F_NUM + (lsb-0x30)*32;
            if(lsb>=0x41 & lsb<=0x5A) return F_ASC + (lsb-0x41)*32;
            if(lsb>=0x61 & lsb<=0x7A) return F_ASC2 + (lsb-0x61)*32;
            else                      return get_UFntAdr(kCode);
        }else if(msb==0x24){                // ひらかな
            if(lsb>=0x21 & lsb<=0x73) return F_HIRA + (lsb-0x21)*32;
            else                      return get_UFntAdr(kCode);
        }else if(msb==0x25){                // カタカナ
            if(lsb>=0x21 & lsb<=0x76) return F_KATA + (lsb-0x21)*32;
            else                      return get_UFntAdr(kCode);
        }
    }else if(msb<0x50){                     // 漢字(第1水準)
        if(lsb>=0x21 & lsb<=0x7E) return F_KAN1 + (lmsb-0x30)*3008+(llsb-0x21)*32;
        else                      return get_UFntAdr(kCode);
    }else if(msb<0x75){                     // 漢字(第2水準)GT20L16J1Y使用時のみ
        if(lsb>=0x21 & lsb<=0x7E) return F_KAN2 + (lmsb-0x50)*3008+(llsb-0x21)*32;
        else                      return get_UFntAdr(kCode);
    }
	return get_UFntAdr(kCode);
}
//---- バイト一単位で全角(漢字)文字表示
uint8_t gLCD_ZchrX(uint8_t xpos, uint8_t ypos, uint16_t kCd,uint8_t ed){
    uint32_t adr;
    uint16_t kk;
    uint8_t h,l;
    if(ed & 0x01){
        h = (uint8_t)(kCd>>8);
        l = (uint8_t)kCd;
        kCd = l*256+h;
    }
//    if(kCd == 0x828F) return gLCD_nk16X(xpos,ypos,(char *)Z_Small_o,16);
    if(ed < 2)  kk = SJis2Jis(kCd);
    else        kk = kCd;
    if(kk == 0x236F) return gLCD_nk16X(xpos,ypos,(char *)Z_Small_o,16);
    adr = KfntAdr(kk);
//    printf(" %X %lX\r",kk,adr);
    SPI_Mem_NRead(adr,(uint8_t *)vBf,32);
    if(adr)	return gLCD_nk16X(xpos,ypos,(char *)vBf,16);
    return xpos;
}
//---- バイト単位位置で全角(漢字)文字列表示
uint8_t LCD_ZstrX(uint8_t xpos, uint8_t ypos, char *str,uint8_t ed){
    uint16_t cd, *kjP;
    kjP = (uint16_t *)str;
    while(*kjP & 0xFF){
        xpos = gLCD_ZchrX(xpos,ypos,*kjP,ed);
        kjP++;
    }
    return xpos;
}		
/****** ドット単位位置で描画 ******/
//----------ドット単位で点を描く----------------------
void gLCD_PSet(uint8_t xpos, uint8_t ypos, uint8_t col){
    uint8_t yAdr, yBit;             // yアドレス、ビット位置
    uint8_t ptn = 0x01;             // ビットパターン
    uint8_t dat;
    if((xpos > 127) || (ypos > 47))  return;
    dat = vRam_read(xpos, ypos);
    yAdr = ypos >> 3; yBit = ypos & 0x07;
    ptn <<= yBit;
    switch(col){
        case 0:	dat &= (~ptn);	break;
        case 1: dat |= ptn;		break;
        case 8: dat ^= ptn;		break;
    }
    gLCD_posXY(xpos,ypos);  
    gCS_SetLow();                   // チップセレクト有効
    gRS_SetHigh();                  // 表示データ指定
    SPI1_ExchangeByte(dat);
    gCS_SetHigh();                  // チップセレクト無効
    vRam_write(xpos, ypos, dat);
}
//-------ドット単位で文字を描く(次xpos位置を返す)-------
uint8_t gLCD_PutChr(uint8_t xpos, uint8_t ypos, char ch, uint8_t col){
    uint8_t i, j, ptn, msk;         //ビットマスクデータ
                                    //有効フォントデータでないなら何もしない
    if((ch < 0x20)||(ch > 0x7f)) return xpos;
    ch -= 0x20;                     //配列アドレスを計算
    for(i = 0; i < 5; i++){
        msk = 0x01;
        ptn = (uint8_t)Font[ch][i];
        if(ptn == 0xFF) break;      //幅狭文字なら抜ける
        for(j = 0; j < 8; j++){
            if(ptn & msk)    gLCD_PSet(xpos + i,ypos + j,col);
            msk <<= 1;
        }
    } 
    return xpos + i + 1;
}
//-------ドット単位で文字列を描く(次xpos位置を返す)---
uint8_t gLCD_PutStr(uint8_t xpos, uint8_t ypos, char * str, uint8_t col){
    while(*str)                     //文字列終端まで継続
        xpos = gLCD_PutChr(xpos,ypos,*str++,col);
    return xpos;                    //次表示位置を返す
}
//-------ドット単位でパターンを描く(次xpos位置を返す)-------
uint8_t gLCD_PutPtn(uint8_t xpos, uint8_t ypos, char * ptn, uint8_t n, uint8_t col){
    uint8_t i, j, msk;             //ビットマスクデータ
    for(i = 0; i < n; i++){
        msk = 0x01;
        for(j = 0; j < 8; j++){
            if(*ptn & msk)    gLCD_PSet(xpos+i,ypos+j,col);
            msk <<= 1;
        }
        ptn++;
    }
    return xpos + i;
}
// --- ABS、SWAP関数定義
void swap_uint8_t(uint8_t *a, uint8_t *b){
    uint8_t tmp; tmp = *a; *a = *b; *b = tmp;
}
#define ABS(a)    (((a)>0) ? (a) : -(a))
//----------ドット単位で直線を描く-------------------
void gLCD_Line(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t col){
    uint8_t steep, x, y, tmp;
    int   ystep, deltax, deltay, error;
    steep = (ABS(y1 - y0) > ABS(x1 - x0));
    if(steep){    swap_uint8_t(&x0,&y0); swap_uint8_t(&x1,&y1); }
    if(x0 > x1){  swap_uint8_t(&x0,&x1); swap_uint8_t(&y0,&y1); }
    deltax = x1 - x0;                       //  傾き計算
    deltay = abs(y1 - y0);
    error = 0;
    y = y0;
    if(y0 < y1) ystep = 1; else ystep = -1;
    for(x = x0; x < x1 + 1; x++){
        if(steep) gLCD_PSet(y,x,col); 
        else      gLCD_PSet(x,y,col);
        error += deltay;
        if((error << 1) >= deltax){
            y += ystep;
            error -= deltax;
        }
    }
}
//---- ドット単位で(縦)16ドットパターン(漢字など)の表示(次xpos位置を返す)
/*  xpos: X位置、   ypos: Y位置,        col: 表示モード
 *  *pKj: 漢字パターンデータポインタ、  cdt: 漢字横ドット数
 *---------------------------------------------------- */
uint8_t Put_nK16(uint8_t xpos, uint8_t ypos, char *pKj, uint8_t cdt, uint8_t col){
    gLCD_PutPtn(xpos, ypos, (char *)pKj, cdt, col); 
    xpos = gLCD_PutPtn(xpos, ypos+8, (char *)(pKj + cdt),cdt, col);
    return xpos;
}
//---- ドット単位で半角文字表示(次xpos位置を返す)
uint8_t Put_HchrX(uint8_t xpos, uint8_t ypos, uint8_t chCode,uint8_t col){
    uint32_t adr;
    if((chCode >= 0x20) & (chCode < 0x7F)){
        adr = (chCode - 0x20) * 16 + F_HALF;
    }else{
        adr = H_BLANK;                  // 半角ブランク
    }
    SPI_Mem_NRead(adr,(uint8_t *)vBf,16);
    xpos = Put_nK16(xpos, ypos, (char *)vBf, 8, col);
    return xpos;
}
//---- ドット単位で半角文字列を表示(次xpos位置を返す)
uint8_t Put_HstrX(uint8_t xpos, uint8_t ypos, char *str, uint8_t col){
    while(*str)  xpos = Put_HchrX(xpos, ypos, *str++, col);
    return xpos;                        //次表示位置を返す
}
//---- ドット単位で全角(漢字)文字表示
uint8_t Put_ZchrX(uint8_t xpos, uint8_t ypos, uint16_t kCd, uint8_t ed, uint8_t col){
    uint32_t adr;
    uint16_t kk;
    uint8_t h,l;
    if(ed & 0x01){
        h = (uint8_t)(kCd>>8);
        l = (uint8_t)kCd;
        kCd = l*256+h;
    }
    if(ed < 2)  kk = SJis2Jis(kCd);
    else        kk = kCd;
    if(kk == 0x236F)
		return Put_nK16(xpos,ypos,(char *)Z_Small_o,16, col);
    adr = KfntAdr(kk);
    SPI_Mem_NRead(adr,(uint8_t *)vBf,32);
    if(adr)	return Put_nK16(xpos,ypos,(char *)vBf,16, col);
    return xpos;
}
//---- ドット単位で全角(漢字)文字列表示
uint8_t Put_ZstrX(uint8_t xpos, uint8_t ypos, char *str, uint8_t ed, uint8_t col){
    uint16_t cd, *kjP;
    kjP = (uint16_t *)str;
    while(*kjP & 0xFF){
        xpos = Put_ZchrX(xpos,ypos,*kjP,ed,col);
        kjP++;
    }
    return xpos;
}
/*****  End of File   *****/
 |