/ MCUME_pico / display / emuapi.cpp
emuapi.cpp
   1  #define KEYMAP_PRESENT 1
   2  
   3  #define PROGMEM
   4  
   5  #include "pico.h"
   6  #include "pico/stdlib.h"
   7  #include "hardware/adc.h"
   8  #include <stdio.h>
   9  #include <string.h>
  10  
  11  extern "C" {
  12    #include "emuapi.h"
  13    #include "iopins.h"
  14  }
  15  
  16  static bool emu_writeConfig(void);
  17  static bool emu_readConfig(void);
  18  static bool emu_eraseConfig(void);
  19  static bool emu_writeGfxConfig(void);
  20  static bool emu_readGfxConfig(void);
  21  static bool emu_eraseGfxConfig(void);
  22  
  23  #include "pico_dsp.h"
  24  extern PICO_DSP tft;
  25  
  26  #define MAX_FILENAME_PATH   64
  27  #define NB_FILE_HANDLER     4
  28  #define AUTORUN_FILENAME    "autorun.txt"
  29  #define GFX_CFG_FILENAME    "gfxmode.txt"
  30  
  31  #define MAX_FILES           64
  32  #define MAX_FILENAME_SIZE   24
  33  #define MAX_MENULINES       9
  34  #define TEXT_HEIGHT         16
  35  #define TEXT_WIDTH          8
  36  #define MENU_FILE_XOFFSET   (6*TEXT_WIDTH)
  37  #define MENU_FILE_YOFFSET   (2*TEXT_HEIGHT)
  38  #define MENU_FILE_W         (MAX_FILENAME_SIZE*TEXT_WIDTH)
  39  #define MENU_FILE_H         (MAX_MENULINES*TEXT_HEIGHT)
  40  #define MENU_FILE_BGCOLOR   RGBVAL16(0x00,0x00,0x40)
  41  #define MENU_JOYS_YOFFSET   (12*TEXT_HEIGHT)
  42  #define MENU_VBAR_XOFFSET   (0*TEXT_WIDTH)
  43  #define MENU_VBAR_YOFFSET   (MENU_FILE_YOFFSET)
  44  
  45  #define MENU_TFT_XOFFSET    (MENU_FILE_XOFFSET+MENU_FILE_W+8)
  46  #define MENU_TFT_YOFFSET    (MENU_VBAR_YOFFSET+32)
  47  #define MENU_VGA_XOFFSET    (MENU_FILE_XOFFSET+MENU_FILE_W+8)
  48  #define MENU_VGA_YOFFSET    (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37)
  49  
  50  
  51  
  52  static int nbFiles=0;
  53  static int curFile=0;
  54  static int topFile=0;
  55  static char selection[MAX_FILENAME_PATH]="";
  56  static char selected_filename[MAX_FILENAME_SIZE]="";
  57  static char files[MAX_FILES][MAX_FILENAME_SIZE];
  58  static bool menuRedraw=true;
  59  
  60  #if (defined(PICOMPUTER) || defined(PICOZX) )
  61  static const unsigned short * keys;
  62  static unsigned char keymatrix[7];
  63  static int keymatrix_hitrow=-1;
  64  static bool key_fn=false;
  65  static bool key_alt=false;
  66  static uint32_t keypress_t_ms=0;
  67  static uint32_t last_t_ms=0;
  68  static uint32_t hundred_ms_cnt=0;
  69  static bool ledflash_toggle=false;
  70  #endif
  71  static int keyMap;
  72  
  73  static bool joySwapped = false;
  74  static uint16_t bLastState;
  75  static int xRef;
  76  static int yRef;
  77  static uint8_t usbnavpad=0;
  78  
  79  static bool menuOn=true;
  80  static bool autorun=false;
  81  
  82  
  83  /********************************
  84   * Generic output and malloc
  85  ********************************/ 
  86  void emu_printf(const char * text)
  87  {
  88    printf("%s\n",text);
  89  }
  90  
  91  void emu_printf(int val)
  92  {
  93    printf("%d\n",val);
  94  }
  95  
  96  void emu_printi(int val)
  97  {
  98    printf("%d\n",val);
  99  }
 100  
 101  void emu_printh(int val)
 102  {
 103    printf("0x%.8\n",val);
 104  }
 105  
 106  static int malbufpt = 0;
 107  static char malbuf[EXTRA_HEAP];
 108  
 109  void * emu_Malloc(int size)
 110  {
 111    void * retval =  malloc(size);
 112    if (!retval) {
 113      emu_printf("failled to allocate");
 114      emu_printf(size);
 115      emu_printf("fallback");
 116      if ( (malbufpt+size) < sizeof(malbuf) ) {
 117        retval = (void *)&malbuf[malbufpt];
 118        malbufpt += size;      
 119      }
 120      else {
 121        emu_printf("failure to allocate");
 122      }
 123    }
 124    else {
 125      emu_printf("could allocate dynamic ");
 126      emu_printf(size);    
 127    }
 128    
 129    return retval;
 130  }
 131  
 132  void * emu_MallocI(int size)
 133  {
 134    void * retval =  NULL; 
 135  
 136    if ( (malbufpt+size) < sizeof(malbuf) ) {
 137      retval = (void *)&malbuf[malbufpt];
 138      malbufpt += size;
 139      emu_printf("could allocate static ");
 140      emu_printf(size);          
 141    }
 142    else {
 143      emu_printf("failure to allocate");
 144    }
 145  
 146    return retval;
 147  }
 148  void emu_Free(void * pt)
 149  {
 150    free(pt);
 151  }
 152  
 153  void emu_drawText(unsigned short x, unsigned short y, const char * text, unsigned short fgcolor, unsigned short bgcolor, int doublesize)
 154  {
 155    tft.drawText(x, y, text, fgcolor, bgcolor, doublesize?true:false);
 156  }
 157  
 158  
 159  /********************************
 160   * OSKB handling
 161  ********************************/ 
 162  #if (defined(ILI9341) || defined(ST7789)) && defined(USE_VGA)
 163  // On screen keyboard position
 164  #define KXOFF      28 //64
 165  #define KYOFF      96
 166  #define KWIDTH     11 //22
 167  #define KHEIGHT    3
 168  
 169  static bool oskbOn = false;
 170  static int cxpos = 0;
 171  static int cypos = 0;
 172  static int oskbMap = 0;
 173  static uint16_t oskbBLastState = 0;
 174  
 175  static void lineOSKB2(int kxoff, int kyoff, char * str, int row)
 176  {
 177    char c[2] = {'A',0};
 178    const char * cpt = str;
 179    for (int i=0; i<KWIDTH; i++)
 180    {
 181      c[0] = *cpt++;
 182      c[1] = 0;
 183      uint16_t bg = RGBVAL16(0x00,0x00,0xff);
 184      if ( (cxpos == i) && (cypos == row) ) bg = RGBVAL16(0xff,0x00,0x00);
 185      tft.drawTextNoDma(kxoff+8*i,kyoff, &c[0], RGBVAL16(0x00,0xff,0xff), bg, ((i&1)?false:true));
 186    } 
 187  }
 188  
 189  static void lineOSKB(int kxoff, int kyoff, char * str, int row)
 190  {
 191    char c[4] = {' ',0,' ',0};
 192    const char * cpt = str;
 193    for (int i=0; i<KWIDTH; i++)
 194    {
 195      c[1] = *cpt++;
 196      uint16_t bg;
 197      if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0);
 198      else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff);
 199      if ( (cxpos == i) && (cypos == row) ) bg = RGBVAL16(0x00,0xff,0xff);
 200      tft.drawTextNoDma(kxoff+24*i,kyoff+32*row+0 , "   ", RGBVAL16(0x00,0x00,0x00), bg, false);
 201      tft.drawTextNoDma(kxoff+24*i,kyoff+32*row+8 , &c[0], RGBVAL16(0x00,0x00,0x00), bg, true);
 202      tft.drawTextNoDma(kxoff+24*i,kyoff+32*row+24, "   ", RGBVAL16(0x00,0x00,0x00), bg, false);
 203    } 
 204  }
 205  
 206  
 207  static void drawOskb(void)
 208  {
 209  //  lineOSKB2(KXOFF,KYOFF+0,  (char *)"Q1W2E3R4T5Y6U7I8O9P0<=",  0);
 210  //  lineOSKB2(KXOFF,KYOFF+16, (char *)"  A!S@D#F$G%H+J&K*L-EN",  1);
 211  //  lineOSKB2(KXOFF,KYOFF+32, (char *)"  Z(X)C?V/B\"N<M>.,SP  ", 2);
 212  /*  
 213    if (oskbMap == 0) {
 214      lineOSKB(KXOFF,KYOFF, keylables_map1_0,  0);
 215      lineOSKB(KXOFF,KYOFF, keylables_map1_1,  1);
 216      lineOSKB(KXOFF,KYOFF, keylables_map1_2,  2);
 217    }
 218    else if (oskbMap == 1) {
 219      lineOSKB(KXOFF,KYOFF, keylables_map2_0,  0);
 220      lineOSKB(KXOFF,KYOFF, keylables_map2_1,  1);
 221      lineOSKB(KXOFF,KYOFF, keylables_map2_2,  2);
 222    }
 223    else {
 224      lineOSKB(KXOFF,KYOFF, keylables_map3_0,  0);
 225      lineOSKB(KXOFF,KYOFF, keylables_map3_1,  1);
 226      lineOSKB(KXOFF,KYOFF, keylables_map3_2,  2);
 227    }
 228  */  
 229  }
 230  
 231  void toggleOskb(bool forceoff) {
 232    if (forceoff) oskbOn=true; 
 233    if (oskbOn) {
 234      oskbOn = false;
 235      tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00));
 236      tft.drawTextNoDma(0,32, "Press USER2 to toggle onscreen keyboard.", RGBVAL16(0xff,0xff,0xff), RGBVAL16(0x00,0x00,0x00), true);
 237    } else {
 238      oskbOn = true;
 239      tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00));
 240      tft.drawTextNoDma(0,32, " Press USER2 to exit onscreen keyboard. ", RGBVAL16(0xff,0xff,0xff), RGBVAL16(0x00,0x00,0x00), true);
 241      tft.drawTextNoDma(0,64, "    (USER1 to toggle between keymaps)   ", RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), true);
 242      tft.drawRectNoDma(KXOFF,KYOFF, 22*8, 3*16, RGBVAL16(0x00,0x00,0xFF));
 243      drawOskb();        
 244    }
 245  }
 246  
 247  static int handleOskb(void)
 248  {  
 249    int retval = 0;
 250  
 251    uint16_t bClick = bLastState & ~oskbBLastState;
 252    oskbBLastState = bLastState;
 253    /*
 254    static const char * digits = "0123456789ABCDEF";
 255    char buf[5] = {0,0,0,0,0};
 256    int val = bClick;
 257    buf[0] = digits[(val>>12)&0xf];
 258    buf[1] = digits[(val>>8)&0xf];
 259    buf[2] = digits[(val>>4)&0xf];
 260    buf[3] = digits[val&0xf];
 261    tft.drawTextNoDma(0,KYOFF+ 64,buf,RGBVAL16(0x00,0x00,0x00),RGBVAL16(0xFF,0xFF,0xFF),1);
 262    */
 263    if (bClick & MASK_KEY_USER2)
 264    { 
 265      toggleOskb(false);
 266    }
 267    if (oskbOn)
 268    {
 269      bool updated = true;
 270      if (bClick & MASK_KEY_USER1)
 271      { 
 272        oskbMap += 1;
 273        if (oskbMap == 3) oskbMap = 0;
 274      }    
 275      else if (bClick & MASK_JOY2_LEFT)
 276      {  
 277        cxpos++;
 278        if (cxpos >= KWIDTH) cxpos = 0;
 279      }
 280      else if (bClick & MASK_JOY2_RIGHT)
 281      {  
 282        cxpos--;
 283        if (cxpos < 0) cxpos = KWIDTH-1;
 284      }
 285      else if (bClick & MASK_JOY2_DOWN)
 286      {  
 287        cypos++;
 288        if (cypos >= KHEIGHT) cypos = 0;
 289      }
 290      else if (bClick & MASK_JOY2_UP)
 291      {  
 292        cypos--;
 293        if (cypos < 0) cypos = KHEIGHT-1;
 294      }
 295      else if (oskbBLastState & MASK_JOY2_BTN)
 296      {  
 297        retval = cypos*KWIDTH+cxpos+1;
 298        if (retval) {
 299          retval--;
 300          //if (retval & 1) retval = key_map2[retval>>1];
 301          //else retval = key_map1[retval>>1];
 302          if (oskbMap == 0) {
 303            retval = key_map1[retval];
 304          }
 305          else if (oskbMap == 1) {
 306            retval = key_map2[retval];
 307          }
 308          else {
 309            retval = key_map3[retval];
 310          }
 311          //if (retval) { toggleOskb(true); updated=false; };
 312        }
 313      }
 314      else {
 315        updated=false;
 316      }    
 317      if (updated) drawOskb();
 318    }
 319  
 320    return retval;    
 321  }
 322  #endif
 323  
 324  /********************************
 325   * Input and keyboard
 326  ********************************/ 
 327  int emu_ReadAnalogJoyX(int min, int max) 
 328  {
 329    adc_select_input(0);
 330    int val = adc_read();
 331  #if INVX
 332    val = 4095 - val;
 333  #endif
 334    val = val-xRef;
 335    val = ((val*140)/100);
 336    if ( (val > -512) && (val < 512) ) val = 0;
 337    val = val+2048;
 338    return (val*(max-min))/4096;
 339  }
 340  
 341  int emu_ReadAnalogJoyY(int min, int max) 
 342  {
 343    adc_select_input(1);  
 344    int val = adc_read();
 345  #if INVY
 346    val = 4095 - val;
 347  #endif
 348    val = val-yRef;
 349    val = ((val*120)/100);
 350    if ( (val > -512) && (val < 512) ) val = 0;
 351    //val = (val*(max-min))/4096;
 352    val = val+2048;
 353    //return val+(max-min)/2;
 354    return (val*(max-min))/4096;
 355  }
 356  
 357  
 358  static uint16_t readAnalogJoystick(void)
 359  {
 360    uint16_t joysval = 0;
 361  #ifdef PIN_JOY2_A1X
 362    int xReading = emu_ReadAnalogJoyX(0,256);
 363    if (xReading > 128) joysval |= MASK_JOY2_LEFT;
 364    else if (xReading < 128) joysval |= MASK_JOY2_RIGHT;
 365    
 366    int yReading = emu_ReadAnalogJoyY(0,256);
 367    if (yReading < 128) joysval |= MASK_JOY2_UP;
 368    else if (yReading > 128) joysval |= MASK_JOY2_DOWN;
 369  #endif 
 370    // First joystick
 371  #if INVY
 372  #ifdef PIN_JOY2_1
 373    if ( !gpio_get(PIN_JOY2_1) ) joysval |= MASK_JOY2_DOWN;
 374  #endif
 375  #ifdef PIN_JOY2_2
 376    if ( !gpio_get(PIN_JOY2_2) ) joysval |= MASK_JOY2_UP;
 377  #endif
 378  #else
 379  #ifdef PIN_JOY2_1
 380    if ( !gpio_get(PIN_JOY2_1) ) joysval |= MASK_JOY2_UP;
 381  #endif
 382  #ifdef PIN_JOY2_2
 383    if ( !gpio_get(PIN_JOY2_2) ) joysval |= MASK_JOY2_DOWN;
 384  #endif
 385  #endif
 386  #if INVX
 387  #ifdef PIN_JOY2_3
 388    if ( !gpio_get(PIN_JOY2_3) ) joysval |= MASK_JOY2_LEFT;
 389  #endif
 390  #ifdef PIN_JOY2_4
 391    if ( !gpio_get(PIN_JOY2_4) ) joysval |= MASK_JOY2_RIGHT;
 392  #endif
 393  #else
 394  #ifdef PIN_JOY2_3
 395    if ( !gpio_get(PIN_JOY2_3) ) joysval |= MASK_JOY2_RIGHT;
 396  #endif
 397  #ifdef PIN_JOY2_4
 398    if ( !gpio_get(PIN_JOY2_4) ) joysval |= MASK_JOY2_LEFT;
 399  #endif
 400  #endif
 401  #ifdef PIN_JOY2_BTN
 402    joysval |= (gpio_get(PIN_JOY2_BTN) ? 0 : MASK_JOY2_BTN);
 403  #endif
 404  
 405    return (joysval);     
 406  }
 407  
 408  
 409  int emu_SwapJoysticks(int statusOnly) {
 410    if (!statusOnly) {
 411      if (joySwapped) {
 412        joySwapped = false;
 413      }
 414      else {
 415        joySwapped = true;
 416      }
 417    }
 418    return(joySwapped?1:0);
 419  }
 420  
 421  int emu_GetPad(void) 
 422  {
 423    return(bLastState/*|((joySwapped?1:0)<<7)*/);
 424  }
 425  
 426  int emu_ReadKeys(void) 
 427  {
 428    uint16_t retval;
 429    uint16_t j1 = readAnalogJoystick();
 430    uint16_t j2 = 0;
 431    
 432    // Second joystick
 433  #if INVY
 434  #ifdef PIN_JOY1_1
 435    if ( !gpio_get(PIN_JOY1_1) ) j2 |= MASK_JOY2_DOWN;
 436  #endif
 437  #ifdef PIN_JOY1_2
 438    if ( !gpio_get(PIN_JOY1_2) ) j2 |= MASK_JOY2_UP;
 439  #endif
 440  #else
 441  #ifdef PIN_JOY1_1
 442    if ( !gpio_get(PIN_JOY1_1) ) j2 |= MASK_JOY2_UP;
 443  #endif
 444  #ifdef PIN_JOY1_2
 445    if ( !gpio_get(PIN_JOY1_2) ) j2 |= MASK_JOY2_DOWN;
 446  #endif
 447  #endif
 448  #if INVX
 449  #ifdef PIN_JOY1_3
 450    if ( !gpio_get(PIN_JOY1_3) ) j2 |= MASK_JOY2_LEFT;
 451  #endif
 452  #ifdef PIN_JOY1_4
 453    if ( !gpio_get(PIN_JOY1_4) ) j2 |= MASK_JOY2_RIGHT;
 454  #endif
 455  #else
 456  #ifdef PIN_JOY1_3
 457    if ( !gpio_get(PIN_JOY1_3) ) j2 |= MASK_JOY2_RIGHT;
 458  #endif
 459  #ifdef PIN_JOY1_4
 460    if ( !gpio_get(PIN_JOY1_4) ) j2 |= MASK_JOY2_LEFT;
 461  #endif
 462  #endif
 463  #ifdef PIN_JOY1_BTN
 464    if ( !gpio_get(PIN_JOY1_BTN) ) j2 |= MASK_JOY2_BTN;
 465  #endif
 466  
 467  
 468    if (joySwapped) {
 469      retval = ((j1 << 8) | j2);
 470    }
 471    else {
 472      retval = ((j2 << 8) | j1);
 473    }
 474  
 475    if (usbnavpad & MASK_JOY2_UP) retval |= MASK_JOY2_UP;
 476    if (usbnavpad & MASK_JOY2_DOWN) retval |= MASK_JOY2_DOWN;
 477    if (usbnavpad & MASK_JOY2_LEFT) retval |= MASK_JOY2_LEFT;
 478    if (usbnavpad & MASK_JOY2_RIGHT) retval |= MASK_JOY2_RIGHT;
 479    if (usbnavpad & MASK_JOY2_BTN) retval |= MASK_JOY2_BTN;
 480  
 481  #ifdef PIN_KEY_USER1 
 482    if ( !gpio_get(PIN_KEY_USER1) ) retval |= MASK_KEY_USER1;
 483  #endif
 484  #ifdef PIN_KEY_USER2 
 485    if ( !gpio_get(PIN_KEY_USER2) ) retval |= MASK_KEY_USER2;
 486  #endif
 487  #ifdef PIN_KEY_USER3 
 488    if ( !gpio_get(PIN_KEY_USER3) ) retval |= MASK_KEY_USER3;
 489  #endif
 490  #ifdef PIN_KEY_USER4 
 491    if ( !gpio_get(PIN_KEY_USER4) ) retval |= MASK_KEY_USER4;
 492  #endif
 493  
 494  
 495  #if (defined(PICOMPUTER) || defined(PICOZX) )
 496    keymatrix_hitrow = -1;
 497    unsigned char row;
 498  #ifdef PICOZX  
 499    unsigned short cols[7]={KCOLOUT1,KCOLOUT2,KCOLOUT3,KCOLOUT4,KCOLOUT5,KCOLOUT6,KCOLOUT7};
 500    unsigned char keymatrixtmp[7];
 501    for (int i=0;i<7;i++){
 502  #else  
 503    unsigned short cols[6]={KCOLOUT1,KCOLOUT2,KCOLOUT3,KCOLOUT4,KCOLOUT5,KCOLOUT6};
 504    unsigned char keymatrixtmp[6];
 505    for (int i=0;i<6;i++){
 506  #endif
 507      gpio_set_dir(cols[i], GPIO_OUT);
 508      gpio_put(cols[i], 0);
 509  #ifdef SWAP_ALT_DEL
 510      sleep_us(1);
 511      //__asm volatile ("nop\n"); // 4-8ns
 512  #endif
 513      row=0; 
 514  #ifdef PICOZX  
 515      row |= (gpio_get(KROWIN1) ? 0 : 0x04);
 516      row |= (gpio_get(KROWIN1) ? 0 : 0x04);
 517      row |= (gpio_get(KROWIN1) ? 0 : 0x04);
 518      row |= (gpio_get(KROWIN1) ? 0 : 0x04);
 519      row |= (gpio_get(KROWIN2) ? 0 : 0x01);
 520      row |= (gpio_get(KROWIN3) ? 0 : 0x08);
 521      row |= (gpio_get(KROWIN4) ? 0 : 0x02);
 522      row |= (gpio_get(KROWIN5) ? 0 : 0x10);
 523      row |= (gpio_get(KROWIN6) ? 0 : 0x20);
 524      row |= (gpio_get(KROWIN7) ? 0 : 0x40);
 525  #else
 526      row |= (gpio_get(KROWIN2) ? 0 : 0x01);
 527      row |= (gpio_get(KROWIN2) ? 0 : 0x01);
 528      row |= (gpio_get(KROWIN2) ? 0 : 0x01);
 529      row |= (gpio_get(KROWIN2) ? 0 : 0x01);
 530      row |= (gpio_get(KROWIN4) ? 0 : 0x02);
 531      row |= (gpio_get(KROWIN1) ? 0 : 0x04);
 532      row |= (gpio_get(KROWIN3) ? 0 : 0x08);
 533      row |= (gpio_get(KROWIN5) ? 0 : 0x10);
 534      row |= (gpio_get(KROWIN6) ? 0 : 0x20);
 535  #endif    
 536      //gpio_set_dir(cols[i], GPIO_OUT);
 537      gpio_put(cols[i], 1);
 538      gpio_set_dir(cols[i], GPIO_IN);
 539      gpio_disable_pulls(cols[i]); 
 540      keymatrixtmp[i] = row;
 541    }
 542  
 543  #ifdef SWAP_ALT_DEL
 544    // Swap ALT and DEL  
 545    unsigned char alt = keymatrixtmp[0] & 0x02;
 546    unsigned char del = keymatrixtmp[5] & 0x20;
 547    keymatrixtmp[0] &= ~0x02;
 548    keymatrixtmp[5] &= ~0x20;
 549    if (alt) keymatrixtmp[5] |= 0x20;
 550    if (del) keymatrixtmp[0] |= 0x02;
 551  #endif
 552  
 553  
 554  #ifdef PICOZX  
 555    for (int i=0;i<7;i++){
 556  #else  
 557    bool alt_pressed=false;
 558    if ( keymatrixtmp[5] & 0x20 ) {alt_pressed=true; keymatrixtmp[5] &= ~0x20;};
 559    for (int i=0;i<6;i++){
 560  #endif
 561      row = keymatrixtmp[i];
 562      if (row) keymatrix_hitrow=i;
 563      keymatrix[i] = row;
 564    }
 565  
 566  #ifdef PICOZX
 567    //row = keymatrix[6];
 568    if ( row & 0x02 ) retval |= MASK_KEY_USER1;
 569    if ( row & 0x10 ) retval |= MASK_KEY_USER2;
 570    if ( row & 0x20 ) retval |= MASK_KEY_USER3;
 571    if ( row & 0x40 ) retval |= MASK_KEY_USER4;
 572    row = keymatrix[0];
 573    key_fn = false;
 574    key_alt = false;
 575    if ( row & 0x20 ) {key_fn = true; keymatrix[0] &= ~0x20;}
 576    if ( row & 0x40 ) {key_alt = true;keymatrix[0] &= ~0x40; }
 577    //19,20,21,22,26,27,28  
 578  #if INVX
 579    if ( row & 0x2  ) retval |= MASK_JOY2_LEFT;
 580    if ( row & 0x1  ) retval |= MASK_JOY2_RIGHT;
 581  #else
 582    if ( row & 0x1  ) retval |= MASK_JOY2_LEFT;
 583    if ( row & 0x2  ) retval |= MASK_JOY2_RIGHT;
 584  #endif
 585  #if INVY
 586    if ( row & 0x8  ) retval |= MASK_JOY2_DOWN;
 587    if ( row & 0x10  ) retval |= MASK_JOY2_UP;  
 588  #else
 589    if ( row & 0x10  ) retval |= MASK_JOY2_DOWN;
 590    if ( row & 0x8  ) retval |= MASK_JOY2_UP;  
 591  #endif
 592    if ( row & 0x04 ) retval |= MASK_JOY2_BTN;
 593  
 594  #else // end PICOZX 
 595    //6,9,15,8,7,22
 596  #if INVX
 597    if ( row & 0x2  ) retval |= MASK_JOY2_LEFT;
 598    if ( row & 0x1  ) retval |= MASK_JOY2_RIGHT;
 599  #else
 600    if ( row & 0x1  ) retval |= MASK_JOY2_LEFT;
 601    if ( row & 0x2  ) retval |= MASK_JOY2_RIGHT;
 602  #endif
 603  #if INVY
 604    if ( row & 0x8  ) retval |= MASK_JOY2_DOWN;
 605    if ( row & 0x4  ) retval |= MASK_JOY2_UP;  
 606  #else
 607    if ( row & 0x4  ) retval |= MASK_JOY2_DOWN;
 608    if ( row & 0x8  ) retval |= MASK_JOY2_UP;  
 609  #endif
 610    if ( row & 0x10 ) retval |= MASK_JOY2_BTN;
 611  
 612    if ( key_fn ) retval |= MASK_KEY_USER2;
 613    if ( ( key_fn ) && (keymatrix[0] == 0x02 )) retval |= MASK_KEY_USER1;
 614  
 615    // Handle LED flash
 616    uint32_t time_ms=to_ms_since_boot (get_absolute_time());
 617    if ((time_ms-last_t_ms) > 100) {
 618      last_t_ms = time_ms;
 619      if (ledflash_toggle == false) {
 620        ledflash_toggle = true;
 621      }
 622      else {
 623        ledflash_toggle = false;
 624      }  
 625    }  
 626   
 627    if ( alt_pressed ) {
 628      if (key_fn == false) 
 629      {
 630        // Release to Press transition
 631        if (hundred_ms_cnt == 0) {
 632          keypress_t_ms=time_ms;
 633          hundred_ms_cnt += 1; // 1
 634        }  
 635        else {
 636          hundred_ms_cnt += 1; // 2
 637          if (hundred_ms_cnt >= 2) 
 638          { 
 639            hundred_ms_cnt = 0;
 640            /* 
 641            if ( (time_ms-keypress_t_ms) < 500) 
 642            {
 643              if (key_alt == false) 
 644              {
 645                key_alt = true;
 646              }
 647              else 
 648              {
 649                key_alt = false;
 650              } 
 651            }
 652            */
 653          }        
 654        }
 655      }
 656      else {
 657        // Keep press
 658        if (hundred_ms_cnt == 1) {
 659          if ((to_ms_since_boot (get_absolute_time())-keypress_t_ms) > 2000) 
 660          {
 661            if (key_alt == false) 
 662            {
 663              key_alt = true;
 664            }
 665            else 
 666            {
 667              key_alt = false;
 668            } 
 669            hundred_ms_cnt = 0; 
 670          }
 671        } 
 672      } 
 673      key_fn = true;
 674    }
 675    else  {
 676      key_fn = false;    
 677    }
 678  
 679  #ifdef KLED
 680    // Handle LED
 681    if (key_alt == true) {
 682      gpio_put(KLED, (ledflash_toggle?1:0));
 683    }
 684    else {
 685      if (key_fn == true) {
 686        gpio_put(KLED, 1);
 687      }
 688      else {
 689        gpio_put(KLED, 0);
 690      }     
 691    } 
 692  #endif
 693  
 694  #endif
 695  
 696  
 697  #endif
 698  
 699    //Serial.println(retval,HEX);
 700  
 701    if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2))
 702       || (retval & MASK_KEY_USER4 ) )
 703    {  
 704    }
 705  
 706  #if (defined(ILI9341) || defined(ST7789)) && defined(USE_VGA)
 707    if (oskbOn) {
 708      retval |= MASK_OSKB; 
 709    }  
 710  #endif  
 711    
 712    return (retval);
 713  }
 714  
 715  unsigned short emu_DebounceLocalKeys(void)
 716  {
 717    uint16_t bCurState = emu_ReadKeys();
 718    uint16_t bClick = bCurState & ~bLastState;
 719    bLastState = bCurState;
 720  
 721    return (bClick);
 722  }
 723  
 724  int emu_ReadI2CKeyboard(void) {
 725    int retval=0;
 726  #if (defined(PICOMPUTER) || defined(PICOZX) )
 727    if (key_alt) {
 728      keys = (const unsigned short *)key_map3;
 729    }
 730    else if (key_fn) {
 731      keys = (const unsigned short *)key_map2;
 732    }
 733    else {
 734      keys = (const unsigned short *)key_map1;
 735    }
 736    if (keymatrix_hitrow >=0 ) {
 737      unsigned short match = ((unsigned short)keymatrix_hitrow<<8) | keymatrix[keymatrix_hitrow];  
 738      for (int i=0; i<sizeof(matkeys)/sizeof(unsigned short); i++) {
 739        if (match == matkeys[i]) {
 740          hundred_ms_cnt = 0;
 741          return (keys[i]);
 742        }
 743      }
 744    }
 745  #endif
 746  #if (defined(ILI9341) || defined(ST7789)) && defined(USE_VGA)
 747    if (!menuOn) {
 748      retval = handleOskb(); 
 749    }  
 750  #endif  
 751    return(retval);
 752  }
 753  
 754  unsigned char emu_ReadI2CKeyboard2(int row) {
 755    int retval=0;
 756  #if (defined(PICOMPUTER) || defined(PICOZX) )
 757    retval = keymatrix[row];
 758  #endif
 759    return retval;
 760  }
 761  
 762  
 763  void emu_InitJoysticks(void) { 
 764  
 765    // Second Joystick   
 766  #ifdef PIN_JOY1_1
 767    gpio_set_pulls(PIN_JOY1_1,true,false);
 768    gpio_set_dir(PIN_JOY1_1,GPIO_IN);  
 769  #endif  
 770  #ifdef PIN_JOY1_2
 771    gpio_set_pulls(PIN_JOY1_2,true,false);
 772    gpio_set_dir(PIN_JOY1_2,GPIO_IN);  
 773  #endif  
 774  #ifdef PIN_JOY1_3
 775    gpio_set_pulls(PIN_JOY1_3,true,false);
 776    gpio_set_dir(PIN_JOY1_3,GPIO_IN);  
 777  #endif  
 778  #ifdef PIN_JOY1_4
 779    gpio_set_pulls(PIN_JOY1_4,true,false);
 780    gpio_set_dir(PIN_JOY1_4,GPIO_IN);  
 781  #endif  
 782  #ifdef PIN_JOY1_BTN
 783    gpio_set_pulls(PIN_JOY1_BTN,true,false);
 784    gpio_set_dir(PIN_JOY1_BTN,GPIO_IN);  
 785  #endif  
 786  
 787    // User keys   
 788  #ifdef PIN_KEY_USER1
 789    gpio_set_pulls(PIN_KEY_USER1,true,false);
 790    gpio_set_dir(PIN_KEY_USER1,GPIO_IN);  
 791  #endif  
 792  #ifdef PIN_KEY_USER2
 793    gpio_set_dir(PIN_KEY_USER2,GPIO_IN);
 794    gpio_set_pulls(PIN_KEY_USER2,true,false);
 795  #endif  
 796  #ifdef PIN_KEY_USER3
 797    gpio_set_pulls(PIN_KEY_USER3,true,false);
 798    gpio_set_dir(PIN_KEY_USER3,GPIO_IN);  
 799  #endif  
 800  #ifdef PIN_KEY_USER4
 801    gpio_set_pulls(PIN_KEY_USER4,true,false);
 802    gpio_set_dir(PIN_KEY_USER4,GPIO_IN);  
 803  #endif  
 804  
 805    // First Joystick   
 806  #ifdef PIN_JOY2_1
 807    gpio_set_pulls(PIN_JOY2_1,true,false);
 808    gpio_set_dir(PIN_JOY2_1,GPIO_IN);
 809    gpio_set_input_enabled(PIN_JOY2_1, true); // Force ADC as digital input        
 810  #endif  
 811  #ifdef PIN_JOY2_2
 812    gpio_set_pulls(PIN_JOY2_2,true,false);
 813    gpio_set_dir(PIN_JOY2_2,GPIO_IN);  
 814    gpio_set_input_enabled(PIN_JOY2_2, true);  // Force ADC as digital input       
 815  #endif  
 816  #ifdef PIN_JOY2_3
 817    gpio_set_pulls(PIN_JOY2_3,true,false);
 818    gpio_set_dir(PIN_JOY2_3,GPIO_IN);  
 819    gpio_set_input_enabled(PIN_JOY2_3, true);  // Force ADC as digital input        
 820  #endif  
 821  #ifdef PIN_JOY2_4
 822    gpio_set_pulls(PIN_JOY2_4,true,false);
 823    gpio_set_dir(PIN_JOY2_4,GPIO_IN);  
 824  #endif  
 825  #ifdef PIN_JOY2_BTN
 826    gpio_set_pulls(PIN_JOY2_BTN,true,false);
 827    gpio_set_dir(PIN_JOY2_BTN,GPIO_IN);  
 828  #endif  
 829   
 830  #ifdef PIN_JOY2_A1X
 831    adc_init(); 
 832    adc_gpio_init(PIN_JOY2_A1X);
 833    adc_gpio_init(PIN_JOY2_A2Y);
 834    xRef=0; yRef=0;
 835    for (int i=0; i<10; i++) {
 836      adc_select_input(0);  
 837      xRef += adc_read();
 838      adc_select_input(1);  
 839      yRef += adc_read();
 840      sleep_ms(20);
 841    }
 842  #if INVX
 843    xRef = 4095 -xRef/10;
 844  #else
 845    xRef /= 10;
 846  #endif
 847  #if INVY
 848    yRef = 4095 -yRef/10;
 849  #else
 850    yRef /= 10;
 851  #endif
 852  #endif
 853  
 854  #if (defined(PICOMPUTER) || defined(PICOZX) ) 
 855    // keyboard LED
 856  #ifdef KLED  
 857    gpio_init(KLED);
 858    gpio_set_dir(KLED, GPIO_OUT);
 859    gpio_put(KLED, 1);
 860  #endif
 861    // Output (rows)
 862    gpio_init(KCOLOUT1);
 863    gpio_init(KCOLOUT2);
 864    gpio_init(KCOLOUT3);
 865    gpio_init(KCOLOUT4);
 866    gpio_init(KCOLOUT5);
 867    gpio_init(KCOLOUT6);
 868  #ifdef PICOZX
 869    gpio_init(KCOLOUT7);
 870  #endif  
 871    gpio_set_dir(KCOLOUT1, GPIO_OUT); 
 872    gpio_set_dir(KCOLOUT2, GPIO_OUT); 
 873    gpio_set_dir(KCOLOUT3, GPIO_OUT); 
 874    gpio_set_dir(KCOLOUT4, GPIO_OUT); 
 875    gpio_set_dir(KCOLOUT5, GPIO_OUT); 
 876    gpio_set_dir(KCOLOUT6, GPIO_OUT);
 877  #ifdef PICOZX
 878    gpio_set_dir(KCOLOUT7, GPIO_OUT);
 879  #endif   
 880    gpio_put(KCOLOUT1, 1);
 881    gpio_put(KCOLOUT2, 1);
 882    gpio_put(KCOLOUT3, 1);
 883    gpio_put(KCOLOUT4, 1);
 884    gpio_put(KCOLOUT5, 1);
 885    gpio_put(KCOLOUT6, 1);
 886  #ifdef PICOZX
 887    gpio_put(KCOLOUT7, 1);
 888  #endif   
 889    // but set as input floating when not used!
 890    gpio_set_dir(KCOLOUT1, GPIO_IN); 
 891    gpio_set_dir(KCOLOUT2, GPIO_IN); 
 892    gpio_set_dir(KCOLOUT3, GPIO_IN); 
 893    gpio_set_dir(KCOLOUT4, GPIO_IN); 
 894    gpio_set_dir(KCOLOUT5, GPIO_IN); 
 895    gpio_set_dir(KCOLOUT6, GPIO_IN);
 896  #ifdef PICOZX
 897    gpio_set_dir(KCOLOUT7, GPIO_IN);
 898  #endif   
 899    gpio_disable_pulls(KCOLOUT1); 
 900    gpio_disable_pulls(KCOLOUT2); 
 901    gpio_disable_pulls(KCOLOUT3); 
 902    gpio_disable_pulls(KCOLOUT4); 
 903    gpio_disable_pulls(KCOLOUT5); 
 904    gpio_disable_pulls(KCOLOUT6);
 905  #ifdef PICOZX
 906    gpio_disable_pulls(KCOLOUT7);
 907  #endif   
 908    // Input pins (cols)
 909    gpio_init(KROWIN1);
 910    gpio_init(KROWIN2);
 911    gpio_init(KROWIN3);
 912    gpio_init(KROWIN4);
 913    gpio_init(KROWIN5);
 914    gpio_init(KROWIN6);
 915  #ifdef PICOZX
 916    gpio_init(KROWIN7);
 917  #endif   
 918    gpio_set_dir(KROWIN1,GPIO_IN);  
 919    gpio_set_dir(KROWIN2,GPIO_IN);  
 920    gpio_set_dir(KROWIN3,GPIO_IN);  
 921    gpio_set_dir(KROWIN4,GPIO_IN);  
 922    gpio_set_dir(KROWIN5,GPIO_IN);  
 923    gpio_set_dir(KROWIN6,GPIO_IN);  
 924  #ifdef PICOZX
 925    gpio_set_dir(KROWIN7,GPIO_IN);  
 926  #endif 
 927    gpio_pull_up(KROWIN1);
 928    gpio_pull_up(KROWIN2);
 929    gpio_pull_up(KROWIN3);
 930    gpio_pull_up(KROWIN4);
 931    gpio_pull_up(KROWIN5);
 932    gpio_pull_up(KROWIN6);
 933  #ifdef PICOZX
 934    gpio_pull_up(KROWIN7);
 935  #endif 
 936  #endif
 937  }
 938  
 939  int emu_setKeymap(int index) {
 940    return 0;
 941  }
 942  
 943  
 944  
 945  /********************************
 946   * Menu file loader UI
 947  ********************************/ 
 948  #include "ff.h"
 949  static FATFS fatfs;
 950  static FIL file; 
 951  extern "C" int sd_init_driver(void);
 952  
 953  #ifdef FILEBROWSER
 954  static int readNbFiles(char * rootdir) {
 955    int totalFiles = 0;
 956  
 957    DIR dir;
 958    FILINFO entry;
 959    FRESULT fr = f_findfirst(&dir, &entry, rootdir, "*");
 960    while ( (fr == FR_OK) && (entry.fname[0]) && (totalFiles<MAX_FILES) ) {  
 961      if (!entry.fname[0]) {
 962        // no more files
 963        break;
 964      }
 965      char * filename = entry.fname;   
 966      if ( !(entry.fattrib & AM_DIR) ) {
 967        if (strcmp(filename,AUTORUN_FILENAME)) {
 968          strncpy(&files[totalFiles][0], filename, MAX_FILENAME_SIZE-1);
 969          totalFiles++;
 970        }  
 971      }
 972      else {
 973        if ( (strcmp(filename,".")) && (strcmp(filename,"..")) ) {
 974          strncpy(&files[totalFiles][0], filename, MAX_FILENAME_SIZE-1);
 975          totalFiles++;
 976        }
 977      }
 978      fr = f_findnext(&dir, &entry);  
 979    } 
 980    f_closedir(&dir);
 981  
 982    return totalFiles;  
 983  }  
 984  
 985  
 986  
 987  void backgroundMenu(void) {
 988      menuRedraw=true;  
 989      tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00));
 990      tft.drawTextNoDma(0,0, TITLE, RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), true);           
 991  }
 992  
 993  
 994  static void menuLeft(void)
 995  {
 996  #if (defined(ILI9341) || defined(ST7789)) && defined(USE_VGA)
 997    toggleOskb(true);  
 998  #endif
 999  }
1000  
1001  
1002  bool menuActive(void) 
1003  {
1004    return (menuOn);
1005  }
1006  
1007  void toggleMenu(bool on) {
1008    if (on) {
1009      menuOn = true;
1010      backgroundMenu();
1011    } else {
1012      tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00));    
1013      menuOn = false;    
1014    }
1015  }
1016  
1017  int handleMenu(uint16_t bClick)
1018  {
1019    if (autorun) {
1020        menuLeft();
1021        toggleMenu(false);
1022        menuRedraw=false;
1023        return (ACTION_RUN);
1024    }  
1025  
1026    if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_KEY_USER1) || (bClick & MASK_KEY_USER4) ) {
1027      char newpath[MAX_FILENAME_PATH];
1028      strcpy(newpath, selection);
1029      strcat(newpath, "/");
1030      strcat(newpath, selected_filename);
1031      strcpy(selection,newpath);
1032      emu_printf("new filepath is");
1033      emu_printf(selection);
1034      FILINFO entry;
1035      FRESULT fr;
1036      fr = f_stat(selection, &entry);
1037      if ( (fr == FR_OK) && (entry.fattrib & AM_DIR) ) {
1038          curFile = 0;
1039          nbFiles = readNbFiles(selection);
1040          menuRedraw=true;
1041      }
1042      else
1043      {
1044  #ifdef PICOMPUTER
1045        if (key_alt) {
1046          emu_writeConfig();
1047        }
1048  #endif
1049  #ifdef PICOZX
1050        if (bClick & MASK_KEY_USER4) {
1051          emu_writeConfig();
1052        }
1053  #endif
1054        menuLeft();
1055        toggleMenu(false);
1056        menuRedraw=false;
1057  #ifdef PICOZX
1058        if ( tft.getMode() != MODE_VGA_320x240) {   
1059          if ( (bClick & MASK_KEY_USER1) ) {
1060            tft.begin(MODE_VGA_320x240);
1061          }
1062        }
1063  #endif
1064        return (ACTION_RUN);
1065      }
1066    }
1067    else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) {
1068      if (curFile!=0) {
1069        menuRedraw=true;
1070        curFile--;
1071      }
1072    }
1073    else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) {
1074      if ((curFile-9)>=0) {
1075        menuRedraw=true;
1076        curFile -= 9;
1077      } else if (curFile!=0) {
1078        menuRedraw=true;
1079        curFile--;
1080      }
1081    }  
1082    else if ( (bClick & MASK_JOY2_DOWN) || (bClick & MASK_JOY1_DOWN) )  {
1083      if ((curFile<(nbFiles-1)) && (nbFiles)) {
1084        curFile++;
1085        menuRedraw=true;
1086      }
1087    }
1088    else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) {
1089      if ((curFile<(nbFiles-9)) && (nbFiles)) {
1090        curFile += 9;
1091        menuRedraw=true;
1092      }
1093      else if ((curFile<(nbFiles-1)) && (nbFiles)) {
1094        curFile++;
1095        menuRedraw=true;
1096      }
1097    }
1098    else if ( (bClick & MASK_KEY_USER2) ) {
1099      emu_SwapJoysticks(0);
1100      menuRedraw=true;  
1101    } 
1102  
1103    if (menuRedraw && nbFiles) {
1104      int fileIndex = 0;
1105      tft.drawRectNoDma(MENU_FILE_XOFFSET,MENU_FILE_YOFFSET, MENU_FILE_W, MENU_FILE_H, MENU_FILE_BGCOLOR);
1106  //    if (curFile <= (MAX_MENULINES/2-1)) topFile=0;
1107  //    else topFile=curFile-(MAX_MENULINES/2);
1108      if (curFile <= (MAX_MENULINES-1)) topFile=0;
1109      else topFile=curFile-(MAX_MENULINES/2);
1110  
1111      int i=0;
1112      while (i<MAX_MENULINES) {
1113        if (fileIndex>=nbFiles) {
1114            // no more files
1115            break;
1116        }
1117        char * filename = &files[fileIndex][0];    
1118        if (fileIndex >= topFile) {              
1119          if ((i+topFile) < nbFiles ) {
1120            if ((i+topFile)==curFile) {
1121              tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, filename, RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true);
1122              strcpy(selected_filename,filename);            
1123            }
1124            else {
1125              tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, filename, RGBVAL16(0xff,0xff,0xff), MENU_FILE_BGCOLOR, true);      
1126            }
1127          }
1128          i++; 
1129        }
1130        fileIndex++;    
1131      }
1132  
1133       
1134      tft.drawTextNoDma(48,MENU_JOYS_YOFFSET+8, (emu_SwapJoysticks(1)?(char*)"SWAP=1":(char*)"SWAP=0"), RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false);
1135      menuRedraw=false;     
1136    }
1137  
1138    return (ACTION_NONE);  
1139  }
1140  
1141  char * menuSelection(void)
1142  {
1143    return (selection);  
1144  }
1145  #endif
1146  
1147  /********************************
1148   * File IO
1149  ********************************/ 
1150  int emu_FileOpen(const char * filepath, const char * mode)
1151  {
1152    int retval = 0;
1153  
1154    emu_printf("FileOpen...");
1155    emu_printf(filepath);
1156    if( !(f_open(&file, filepath, FA_READ)) ) {
1157      retval = 1;  
1158    }
1159    else {
1160      emu_printf("FileOpen failed");
1161    }
1162    return (retval);
1163  }
1164  
1165  int emu_FileRead(void * buf, int size, int handler)
1166  {
1167    unsigned int retval=0; 
1168    f_read (&file, (void*)buf, size, &retval);
1169    return retval; 
1170  }
1171  
1172  int emu_FileGetc(int handler)
1173  {
1174    unsigned char c;
1175    unsigned int retval=0;
1176    if( !(f_read (&file, &c, 1, &retval)) )
1177    if (retval != 1) {
1178      emu_printf("emu_FileGetc failed");
1179    }  
1180    return (int)c; 
1181  }
1182  
1183  void emu_FileClose(int handler)
1184  {
1185    f_close(&file); 
1186  }
1187  
1188  int emu_FileSeek(int handler, int seek, int origin)
1189  {
1190    f_lseek(&file, seek);
1191    return (seek);
1192  }
1193  
1194  int emu_FileTell(int handler)
1195  {
1196    return (f_tell(&file));
1197  }
1198  
1199  
1200  unsigned int emu_FileSize(const char * filepath)
1201  {
1202    int filesize=0;
1203    emu_printf("FileSize...");
1204    emu_printf(filepath);
1205    FILINFO entry;
1206    f_stat(filepath, &entry);
1207    filesize = entry.fsize; 
1208    return(filesize);    
1209  }
1210  
1211  unsigned int emu_LoadFile(const char * filepath, void * buf, int size)
1212  {
1213    int filesize = 0;
1214      
1215    emu_printf("LoadFile...");
1216    emu_printf(filepath);
1217    if( !(f_open(&file, filepath, FA_READ)) ) {
1218      filesize = f_size(&file);
1219      emu_printf(filesize);
1220      if (size >= filesize)
1221      {
1222        unsigned int retval=0;
1223        if( (f_read (&file, buf, filesize, &retval)) ) {
1224          emu_printf("File read failed");        
1225        }
1226      }
1227      f_close(&file);
1228    }
1229   
1230    return(filesize);
1231  }
1232  
1233  static FIL outfile; 
1234  
1235  static bool emu_writeGfxConfig(void)
1236  {
1237    bool retval = false;
1238    if( !(f_open(&outfile, "/" GFX_CFG_FILENAME, FA_CREATE_NEW | FA_WRITE)) ) {
1239      f_close(&outfile);
1240      retval = true;
1241    } 
1242    return retval;   
1243  }
1244  
1245  static bool emu_readGfxConfig(void)
1246  {
1247    bool retval = false;
1248    if( !(f_open(&outfile, "/" GFX_CFG_FILENAME, FA_READ)) ) {
1249      f_close(&outfile);
1250      retval = true;
1251    }  
1252    return retval;   
1253  }
1254  
1255  static bool emu_eraseGfxConfig(void)
1256  {
1257    f_unlink ("/" GFX_CFG_FILENAME);
1258    return true;
1259  }
1260  
1261  static bool emu_writeConfig(void)
1262  {
1263    bool retval = false;
1264    if( !(f_open(&outfile, ROMSDIR "/" AUTORUN_FILENAME, FA_CREATE_NEW | FA_WRITE)) ) {
1265      unsigned int sizeread=0;
1266      if( (f_write (&outfile, selection, strlen(selection), &sizeread)) ) {
1267        emu_printf("Config write failed");        
1268      }
1269      else {
1270        retval = true;
1271      }  
1272      f_close(&outfile);   
1273    } 
1274    return retval; 
1275  }
1276  
1277  static bool emu_readConfig(void)
1278  {
1279    bool retval = false;
1280    if( !(f_open(&outfile, ROMSDIR "/" AUTORUN_FILENAME, FA_READ)) ) {
1281      unsigned int filesize = f_size(&outfile);
1282      unsigned int sizeread=0;
1283      if( (f_read (&outfile, selection, filesize, &sizeread)) ) {
1284        emu_printf("Config read failed");        
1285      }
1286      else {
1287        if (sizeread == filesize) {
1288          selection[filesize]=0;
1289          retval = true;
1290        }
1291      }  
1292      f_close(&outfile);   
1293    }  
1294    return retval; 
1295  }
1296  
1297  static bool emu_eraseConfig(void)
1298  {
1299    f_unlink (ROMSDIR "/" AUTORUN_FILENAME);
1300    return true;
1301  }
1302  
1303  
1304  /********************************
1305   * Initialization
1306  ********************************/ 
1307  void emu_init(void)
1308  {
1309    bool forceVga = false;
1310  #ifdef FILEBROWSER
1311    sd_init_driver(); 
1312    FRESULT fr = f_mount(&fatfs, "0:", 1);    
1313  
1314    forceVga = emu_readGfxConfig();
1315  
1316    strcpy(selection,ROMSDIR);
1317    nbFiles = readNbFiles(selection); 
1318  
1319    emu_printf("SD initialized, files found: ");
1320    emu_printi(nbFiles);
1321  #endif
1322  
1323    emu_InitJoysticks();
1324  #ifdef SWAP_JOYSTICK
1325    joySwapped = true;   
1326  #else
1327    joySwapped = false;   
1328  #endif  
1329  
1330  int keypressed = emu_ReadKeys();
1331  
1332  #ifdef USE_VGA    
1333      tft.begin(MODE_VGA_320x240);
1334  #else
1335  
1336  #ifdef PICOZX    
1337    // Force VGA if LEFT/RIGHT pressed
1338    if (keypressed & MASK_JOY2_UP)
1339    {
1340      tft.begin(MODE_VGA_320x240);
1341  #ifdef FILEBROWSER
1342      emu_writeGfxConfig();
1343  #endif    
1344    }
1345    else
1346    {
1347      if ( (keypressed & MASK_JOY2_LEFT) || (keypressed & MASK_JOY2_RIGHT) )
1348      {
1349  #ifdef FILEBROWSER
1350          emu_eraseGfxConfig();
1351  #endif    
1352          forceVga = false;
1353      }
1354      if (forceVga) {
1355        tft.begin(MODE_VGA_320x240);
1356      }
1357      else
1358      {
1359        tft.begin(MODE_TFT_320x240);    
1360      }     
1361    }
1362  #else /* end PICOZX */
1363    tft.begin(MODE_TFT_320x240);    
1364  #endif 
1365  
1366  #endif
1367  
1368  #ifndef USE_VGA    
1369  #ifdef PICOMPUTER
1370    // Flip screen if UP pressed
1371    if (keypressed & MASK_JOY2_UP)
1372    {
1373      tft.flipscreen(true);
1374    }
1375    else 
1376    {
1377      tft.flipscreen(false);
1378    }
1379  #endif
1380  #endif
1381  
1382    if (keypressed & MASK_JOY2_DOWN) {
1383      tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) );
1384      tft.drawTextNoDma(64,48,    (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true);
1385      tft.drawTextNoDma(64,48+24, (char*)"Please reset the board!", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true);
1386      emu_eraseConfig();
1387    }
1388    else {
1389      if (emu_readConfig()) {
1390        autorun = true;
1391      }
1392    }  
1393  
1394  #ifdef FILEBROWSER
1395    toggleMenu(true);
1396  #endif  
1397  }
1398  
1399  
1400  void emu_start(void)
1401  {
1402    usbnavpad = 0;
1403  
1404    keyMap = 0;
1405  }