/ MCUME_teensy41 / teensydoom / emuapi.cpp
emuapi.cpp
   1  #define KEYMAP_PRESENT 1
   2  
   3  extern "C" {
   4    #include "emuapi.h"
   5    #include "iopins.h"
   6  }
   7  
   8  #ifdef HAS_T4_VGA
   9  #include "vga_t_dma.h"
  10  #else
  11  #include "tft_t_dma.h"
  12  #endif
  13  
  14  #ifdef HAS_USBKEY
  15  #include "USBHost_t36.h"  // Read this header first for key info
  16  USBHost myusb;
  17  USBHub hub1(myusb);
  18  KeyboardController keyboard1(myusb);
  19  USBHIDParser hid1(myusb);
  20  MouseController mouse1(myusb);
  21  MIDIDevice midi1(myusb);
  22  #endif
  23  
  24  static bool emu_writeConfig(void);
  25  static bool emu_readConfig(void);
  26  static bool emu_eraseConfig(void);
  27  
  28  static bool mouseDetected = false;
  29  static bool keyboardDetected = false;
  30  static uint8_t usbnavpad=0;
  31  
  32  #include <SD.h>
  33  static File file;
  34  
  35  #define MAX_FILES           64
  36  #define AUTORUN_FILENAME    "autorun.txt"
  37  
  38  #define MAX_FILENAME_SIZE   24
  39  #define MAX_MENULINES       9
  40  #define TEXT_HEIGHT         16
  41  #define TEXT_WIDTH          8
  42  #define MENU_FILE_XOFFSET   (6*TEXT_WIDTH)
  43  #define MENU_FILE_YOFFSET   (2*TEXT_HEIGHT)
  44  #define MENU_FILE_W         (MAX_FILENAME_SIZE*TEXT_WIDTH)
  45  #define MENU_FILE_H         (MAX_MENULINES*TEXT_HEIGHT)
  46  #define MENU_FILE_BGCOLOR   RGBVAL16(0x00,0x00,0x40)
  47  #define MENU_JOYS_YOFFSET   (12*TEXT_HEIGHT)
  48  #define MENU_VBAR_XOFFSET   (0*TEXT_WIDTH)
  49  #define MENU_VBAR_YOFFSET   (MENU_FILE_YOFFSET)
  50  
  51  #define MENU_TFT_XOFFSET    (MENU_FILE_XOFFSET+MENU_FILE_W+8)
  52  #define MENU_TFT_YOFFSET    (MENU_VBAR_YOFFSET+32)
  53  #define MENU_VGA_XOFFSET    (MENU_FILE_XOFFSET+MENU_FILE_W+8)
  54  #define MENU_VGA_YOFFSET    (MENU_VBAR_YOFFSET+MENU_FILE_H-32-37)
  55  
  56  extern TFT_T_DMA tft;
  57  
  58  static int nbFiles=0;
  59  static int curFile=0;
  60  static int topFile=0;
  61  static char selection[MAX_FILENAME_PATH]="";
  62  static char second_selection[MAX_FILENAME_PATH]="";
  63  static char files[MAX_FILES][MAX_FILENAME_SIZE];
  64  static char selected_filename[MAX_FILENAME_SIZE]=""; 
  65  static char second_selected_filename[MAX_FILENAME_SIZE]="";
  66  static bool menuRedraw=true;
  67  static bool autorun=false;
  68  
  69  static const unsigned short * keys;
  70  #ifdef TEECOMPUTER
  71  static unsigned char keymatrix[6];
  72  static int keymatrix_hitrow=-1;
  73  static uint32_t keypress_t_ms=0;
  74  static uint32_t last_t_ms=0;
  75  static uint32_t hundred_ms_cnt=0;
  76  static bool ledflash_toggle=false;
  77  #endif
  78  static bool key_extmode=false;
  79  static bool key_sh=false;
  80  static bool key_fn=false;
  81  
  82  static boolean joySwapped = false;
  83  static uint16_t bLastState;
  84  #ifdef PIN_JOY2_A1X
  85  static int xRef;
  86  static int yRef;
  87  #endif
  88  static bool menuOn=true;
  89  
  90  
  91  /********************************
  92   * Generic output and malloc
  93  ********************************/ 
  94  void emu_printf(const char * text)
  95  {
  96    Serial.println(text);
  97  }
  98  
  99  void emu_printf(int val)
 100  {
 101    Serial.println(val);
 102  }
 103  
 104  void emu_printi(int val)
 105  {
 106    Serial.println(val,HEX);
 107  }
 108  
 109  void emu_printh(int val)
 110  {
 111    Serial.println(val,HEX);
 112  }
 113  
 114  static int malbufpt = 0;
 115  static char malbuf[EXTRA_HEAP];
 116  
 117  void * emu_Malloc(unsigned int size)
 118  {
 119    void * retval =  malloc(size);
 120    if (!retval) {
 121      emu_printf("failled to allocate");
 122      emu_printf(size);
 123      emu_printf("fallback");
 124      if ( (malbufpt+size) < sizeof(malbuf) ) {
 125        retval = (void *)&malbuf[malbufpt];
 126        malbufpt += size;      
 127      }
 128      else {
 129        emu_printf("failure to allocate");
 130      }
 131    }
 132    else {
 133      emu_printf("could allocate dynamic ");
 134      emu_printf(size);    
 135    }
 136    
 137    return retval;
 138  }
 139  
 140  void * emu_MallocI(unsigned int size)
 141  {
 142    void * retval =  NULL; 
 143  
 144    if ( (malbufpt+size) < sizeof(malbuf) ) {
 145      retval = (void *)&malbuf[malbufpt];
 146      malbufpt += size;
 147      emu_printf("could allocate static ");
 148      emu_printf(size);          
 149    }
 150    else {
 151      emu_printf("failure to allocate");
 152    }
 153  
 154    return retval;
 155  }
 156  void emu_Free(void * pt)
 157  {
 158    free(pt);
 159  }
 160  
 161  /********************************
 162   * Input and keyboard
 163  ********************************/ 
 164  #ifdef PIN_JOY2_A1X
 165  int emu_ReadAnalogJoyX(int min, int max) 
 166  {
 167    int val = analogRead(PIN_JOY2_A1X);
 168  #if INVX
 169    val = 4095 - val;
 170  #endif
 171    val = val-xRef;
 172    val = ((val*140)/100);
 173    if ( (val > -512) && (val < 512) ) val = 0;
 174    val = val+2048;
 175    return (val*(max-min))/4096;
 176  }
 177  #endif
 178  
 179  #ifdef PIN_JOY2_A2Y
 180  int emu_ReadAnalogJoyY(int min, int max) 
 181  {
 182    int val = analogRead(PIN_JOY2_A2Y);
 183  #if INVY
 184    val = 4095 - val;
 185  #endif
 186    val = val-yRef;
 187    val = ((val*120)/100);
 188    if ( (val > -512) && (val < 512) ) val = 0;
 189    //val = (val*(max-min))/4096;
 190    val = val+2048;
 191    //return val+(max-min)/2;
 192    return (val*(max-min))/4096;
 193  }
 194  #endif
 195  
 196  static uint16_t readAnalogJoystick(void)
 197  {
 198    uint16_t joysval = 0;
 199  
 200  #ifdef PIN_JOY2_A1X
 201    int xReading = emu_ReadAnalogJoyX(0,256);
 202    if (xReading > 128) joysval |= MASK_JOY2_LEFT;
 203    else if (xReading < 128) joysval |= MASK_JOY2_RIGHT;
 204    
 205    int yReading = emu_ReadAnalogJoyY(0,256);
 206    if (yReading < 128) joysval |= MASK_JOY2_UP;
 207    else if (yReading > 128) joysval |= MASK_JOY2_DOWN;
 208  #endif
 209    
 210  #ifdef PIN_JOY2_BTN  
 211    joysval |= (digitalRead(PIN_JOY2_BTN) == HIGH ? 0 : MASK_JOY2_BTN);
 212  #endif
 213    return (joysval);     
 214  }
 215  
 216  
 217  int emu_SwapJoysticks(int statusOnly) {
 218    if (!statusOnly) {
 219      if (joySwapped) {
 220        joySwapped = false;
 221      }
 222      else {
 223        joySwapped = true;
 224      }
 225    }
 226    return(joySwapped?1:0);
 227  }
 228  
 229  int emu_GetPad(void) 
 230  {
 231    return(bLastState/*|((joySwapped?1:0)<<7)*/);
 232  }
 233  
 234  int emu_ReadKeys(void) 
 235  {
 236    uint16_t retval;
 237    uint16_t j1 = readAnalogJoystick();
 238    uint16_t j2 = 0;
 239    
 240    // Second joystick
 241  #ifdef PIN_JOY1_1
 242    if ( digitalRead(PIN_JOY1_1) == LOW ) j2 |= MASK_JOY2_UP;
 243  #endif
 244  #ifdef PIN_JOY1_2
 245    if ( digitalRead(PIN_JOY1_2) == LOW ) j2 |= MASK_JOY2_DOWN;
 246  #endif
 247  #ifdef PIN_JOY1_3
 248    if ( digitalRead(PIN_JOY1_3) == LOW ) j2 |= MASK_JOY2_RIGHT;
 249  #endif
 250  #ifdef PIN_JOY1_4
 251    if ( digitalRead(PIN_JOY1_4) == LOW ) j2 |= MASK_JOY2_LEFT;
 252  #endif
 253  #ifdef PIN_JOY1_BTN
 254    if ( digitalRead(PIN_JOY1_BTN) == LOW ) j2 |= MASK_JOY2_BTN;
 255  #endif
 256    if (joySwapped) {
 257      retval = ((j1 << 8) | j2);
 258    }
 259    else {
 260      retval = ((j2 << 8) | j1);
 261    }
 262  
 263    if (usbnavpad & MASK_JOY2_UP) retval |= MASK_JOY2_UP;
 264    if (usbnavpad & MASK_JOY2_DOWN) retval |= MASK_JOY2_DOWN;
 265    if (usbnavpad & MASK_JOY2_LEFT) retval |= MASK_JOY2_LEFT;
 266    if (usbnavpad & MASK_JOY2_RIGHT) retval |= MASK_JOY2_RIGHT;
 267    if (usbnavpad & MASK_JOY2_BTN) retval |= MASK_JOY2_BTN;
 268    if (usbnavpad & MASK_KEY_USER1) retval |= MASK_KEY_USER1;
 269    if (usbnavpad & MASK_KEY_USER2) retval |= MASK_KEY_USER2;
 270  
 271  #ifdef PIN_KEY_USER1 
 272    if ( digitalRead(PIN_KEY_USER1) == LOW ) retval |= MASK_KEY_USER1;
 273  #endif
 274  #ifdef PIN_KEY_USER2 
 275    if ( digitalRead(PIN_KEY_USER2) == LOW ) retval |= MASK_KEY_USER2;
 276  #endif
 277  #ifdef PIN_KEY_USER3 
 278    if ( digitalRead(PIN_KEY_USER3) == LOW ) retval |= MASK_KEY_USER3;
 279  #endif
 280  #ifdef PIN_KEY_USER4 
 281    if ( digitalRead(PIN_KEY_USER4) == LOW ) retval |= MASK_KEY_USER4;
 282  #endif
 283  
 284  #ifdef TEECOMPUTER
 285    keymatrix_hitrow = -1;
 286    unsigned char row;
 287    unsigned short cols[6]={KCOLOUT1,KCOLOUT2,KCOLOUT3,KCOLOUT4,KCOLOUT5,KCOLOUT6};
 288    for (int i=0;i<6;i++){
 289      pinMode(cols[i],OUTPUT);
 290      digitalWrite(cols[i], 0);
 291      row=0; 
 292      row |= (digitalRead(KROWIN1) ? 0 : 0x01);
 293      row |= (digitalRead(KROWIN2) ? 0 : 0x02);
 294      row |= (digitalRead(KROWIN3) ? 0 : 0x04);
 295      row |= (digitalRead(KROWIN4) ? 0 : 0x08);
 296      row |= (digitalRead(KROWIN5) ? 0 : 0x10);
 297      row |= (digitalRead(KROWIN6) ? 0 : 0x20);
 298      row |= (digitalRead(KROWIN7) ? 0 : 0x40);
 299      digitalWrite(cols[i], 1);
 300      pinMode(cols[i],INPUT_DISABLE);
 301      keymatrix[i]=row;
 302    }
 303  
 304    bool fn_pressed=false;
 305    if ( keymatrix[5] & 0x08 ) {fn_pressed=true; keymatrix[5] &= ~0x08;};
 306    
 307    bool sh_pressed=false;
 308    if ( keymatrix[5] & 0x10 ) {sh_pressed=true; keymatrix[5] &= ~0x10;};
 309  
 310    for (int i=0;i<6;i++){
 311      row = keymatrix[i];
 312      if (row) keymatrix_hitrow=i;
 313    }
 314  
 315    //6,9,15,8,7,22
 316  #if INVX
 317    if ( row & 0x40  ) retval |= MASK_JOY2_LEFT;
 318    if ( row & 0x20  ) retval |= MASK_JOY2_RIGHT;
 319  #else
 320    if ( row & 0x20  ) retval |= MASK_JOY2_LEFT;
 321    if ( row & 0x40  ) retval |= MASK_JOY2_RIGHT;
 322  #endif
 323  #if INVY
 324    if ( row & 0x4  ) retval |= MASK_JOY2_DOWN;
 325    if ( row & 0x1  ) retval |= MASK_JOY2_UP;  
 326  #else
 327    if ( row & 0x1  ) retval |= MASK_JOY2_DOWN;
 328    if ( row & 0x4  ) retval |= MASK_JOY2_UP;  
 329  #endif
 330    if ( row & 0x02 ) retval |= MASK_JOY2_BTN;
 331  
 332    // Handle LED flash
 333    uint32_t time_ms=millis();
 334    if ((time_ms-last_t_ms) > 100) {
 335      last_t_ms = time_ms;
 336      if (ledflash_toggle == false) {
 337        ledflash_toggle = true;
 338      }
 339      else {
 340        ledflash_toggle = false;
 341      }  
 342    }  
 343  
 344    if ( sh_pressed ) {
 345        key_sh = true;      
 346    }
 347    else {
 348      key_sh = false;
 349      if ( fn_pressed ) {
 350        if (key_fn == false) 
 351        {
 352          // Release to Press transition
 353          if (hundred_ms_cnt == 0) {
 354            keypress_t_ms=time_ms;
 355            hundred_ms_cnt += 1; // 1
 356          }  
 357          else {
 358            hundred_ms_cnt += 1; // 2
 359            if (hundred_ms_cnt >= 2) 
 360            { 
 361              hundred_ms_cnt = 0; 
 362              if ( (time_ms-keypress_t_ms) < 500) 
 363              {
 364                if (key_extmode == false) 
 365                {
 366                  key_extmode = true;
 367                }
 368                else 
 369                {
 370                  key_extmode = false;
 371                } 
 372              }
 373            }        
 374          }
 375        }
 376        else {
 377          // Keep press
 378          if (hundred_ms_cnt == 1) {
 379            if ((millis()-keypress_t_ms) > 1000) 
 380            {
 381              if (key_extmode == false) 
 382              {
 383                key_extmode = true;
 384              }
 385              else 
 386              {
 387                key_extmode = false;
 388              } 
 389              hundred_ms_cnt = 0; 
 390            }
 391          } 
 392        } 
 393        key_fn = true;
 394      }
 395      else  {
 396        key_fn = false;    
 397      }    
 398    }
 399    
 400    // Handle LED
 401    if (key_extmode == true) {
 402      digitalWrite(KLED, (ledflash_toggle?1:0));
 403    }
 404    else {
 405      if ( (key_fn == true) || (key_sh == true) ) {
 406        digitalWrite(KLED, 1);
 407      }
 408      else {
 409        digitalWrite(KLED, 0);
 410      }     
 411    } 
 412   
 413    if ( key_fn ) retval |= MASK_KEY_USER2;
 414    if ( ( key_fn ) && (keymatrix[4] == 0x10 )) retval |= MASK_KEY_USER1;
 415  
 416    if ( (key_fn) && (key_sh) )
 417  #else
 418    if ( ((retval & (MASK_KEY_USER1+MASK_KEY_USER2)) == (MASK_KEY_USER1+MASK_KEY_USER2))
 419       || (retval & MASK_KEY_USER4 ) )
 420  #endif
 421    {
 422  // Reset procedure T3.X and T4.0 by Frank Boesing !!   
 423  #if defined(__IMXRT1052__) || defined(__IMXRT1062__)    
 424      uint32_t tmp = SNVS_LPCR; // save control register
 425      
 426      SNVS_LPSR |= 1;
 427      
 428      // disable alarm
 429      SNVS_LPCR &= ~0x02;
 430      while (SNVS_LPCR & 0x02);
 431      
 432      __disable_irq();
 433      //get Time:
 434      uint32_t lsb, msb;
 435      do {
 436        msb = SNVS_LPSRTCMR;
 437        lsb = SNVS_LPSRTCLR;
 438      } while ( (SNVS_LPSRTCLR != lsb) | (SNVS_LPSRTCMR != msb) );
 439      uint32_t secs = (msb << 17) | (lsb >> 15);
 440      
 441      //set alarm
 442      secs += 2;
 443      SNVS_LPTAR = secs;
 444      while (SNVS_LPTAR != secs);
 445      
 446      SNVS_LPCR = tmp | 0x02; // restore control register and set alarm
 447      while (!(SNVS_LPCR & 0x02));
 448      
 449      SNVS_LPCR |= (1 << 6); // turn off power
 450      while (1) asm("wfi");  
 451  #else
 452      *(volatile uint32_t *)0xE000ED0C = 0x5FA0004;
 453      while (true) {
 454        ;
 455      } 
 456  #endif 
 457    }
 458    
 459    return (retval);
 460  }
 461  
 462  unsigned short emu_DebounceLocalKeys(void)
 463  {
 464    uint16_t bCurState = emu_ReadKeys();
 465    uint16_t bClick = bCurState & ~bLastState;
 466    bLastState = bCurState;
 467  
 468    return (bClick);
 469  }
 470  
 471  int emu_ReadI2CKeyboard(void) {
 472    int retval=0;
 473  #ifdef TEECOMPUTER
 474    if (key_extmode) {
 475      if (key_fn) {
 476        keys = (const unsigned short *)key_map5; // fn-extra
 477      }
 478      else if (key_sh) {
 479        keys = (const unsigned short *)key_map4; // shift-functionkeys
 480      }
 481      else {
 482        keys = (const unsigned short *)key_map3; // def-digitkeys
 483      }
 484    }
 485    else {
 486      if (key_fn) {
 487        keys = (const unsigned short *)key_map2; // fn-shiftothers 
 488      }
 489      else if (key_sh) {
 490        keys = (const unsigned short *)key_map1; // shift-uppercase
 491      }
 492      else {
 493        keys = (const unsigned short *)key_map0; // def-lowercase
 494      }
 495    }
 496  
 497    
 498    if (keymatrix_hitrow >=0 ) {
 499      unsigned short match = ((unsigned short)keymatrix_hitrow<<8) | keymatrix[keymatrix_hitrow];  
 500      for (unsigned int i=0; i<sizeof(matkeys)/sizeof(unsigned short); i++) {
 501        if (match == matkeys[i]) {
 502          hundred_ms_cnt = 0;    
 503          return (keys[i]);
 504        }
 505      }
 506    }
 507  #endif
 508    return(retval);
 509  }
 510  
 511  unsigned char emu_ReadI2CKeyboard2(int row) {
 512    int retval=0;
 513  #ifdef TEECOMPUTER
 514    retval = keymatrix[row];
 515  #endif
 516    return retval;
 517  }
 518  
 519  void emu_InitJoysticks(void) { 
 520  
 521    // Second Joystick   
 522  #ifdef PIN_JOY1_1
 523    pinMode(PIN_JOY1_1, INPUT_PULLUP);
 524  #endif  
 525  #ifdef PIN_JOY1_2
 526    pinMode(PIN_JOY1_2, INPUT_PULLUP);
 527  #endif  
 528  #ifdef PIN_JOY1_3
 529    pinMode(PIN_JOY1_3, INPUT_PULLUP);
 530  #endif  
 531  #ifdef PIN_JOY1_4
 532    pinMode(PIN_JOY1_4, INPUT_PULLUP);
 533  #endif  
 534  #ifdef PIN_JOY1_BTN
 535    pinMode(PIN_JOY1_BTN, INPUT_PULLUP);
 536  #endif  
 537  
 538  #ifdef PIN_KEY_USER1
 539    pinMode(PIN_KEY_USER1, INPUT_PULLUP);
 540  #endif  
 541  #ifdef PIN_KEY_USER2
 542    pinMode(PIN_KEY_USER2, INPUT_PULLUP);
 543  #endif  
 544  #ifdef PIN_KEY_USER3
 545    pinMode(PIN_KEY_USER3, INPUT_PULLUP);
 546  #endif  
 547  #ifdef PIN_KEY_USER4
 548    pinMode(PIN_KEY_USER4, INPUT_PULLUP);
 549  #endif  
 550  #ifdef PIN_JOY2_BTN
 551    pinMode(PIN_JOY2_BTN, INPUT_PULLUP);
 552  #endif  
 553  
 554  #ifdef PIN_JOY2_A1X
 555    analogReadResolution(12);
 556    xRef=0; yRef=0;
 557    for (int i=0; i<10; i++) {
 558      xRef += analogRead(PIN_JOY2_A1X);
 559      yRef += analogRead(PIN_JOY2_A2Y);  
 560      delay(20);
 561    }
 562  #if INVX
 563    xRef = 4095 -xRef/10;
 564  #else
 565    xRef /= 10;
 566  #endif
 567  #if INVY
 568    yRef = 4095 -yRef/10;
 569  #else
 570    yRef /= 10;
 571  #endif   
 572  #endif
 573  
 574  #ifdef TEECOMPUTER
 575    // keyboard LED
 576    pinMode(KLED,OUTPUT);
 577    digitalWrite(KLED,1);
 578  
 579    // Output (cols)
 580    pinMode(KCOLOUT1,OUTPUT);
 581    pinMode(KCOLOUT2,OUTPUT);
 582    pinMode(KCOLOUT3,OUTPUT);
 583    pinMode(KCOLOUT4,OUTPUT);
 584    pinMode(KCOLOUT5,OUTPUT);
 585    pinMode(KCOLOUT6,OUTPUT);
 586    digitalWrite(KCOLOUT1,1);
 587    digitalWrite(KCOLOUT2,1);
 588    digitalWrite(KCOLOUT3,1);
 589    digitalWrite(KCOLOUT4,1);
 590    digitalWrite(KCOLOUT5,1);
 591    digitalWrite(KCOLOUT6,1);
 592  
 593    // Input pins (rows)
 594    pinMode(KROWIN1, INPUT_PULLUP);
 595    pinMode(KROWIN2, INPUT_PULLUP);
 596    pinMode(KROWIN3, INPUT_PULLUP);
 597    pinMode(KROWIN4, INPUT_PULLUP);
 598    pinMode(KROWIN5, INPUT_PULLUP);
 599    pinMode(KROWIN6, INPUT_PULLUP); 
 600    pinMode(KROWIN7, INPUT_PULLUP); 
 601  #endif
 602  }
 603  
 604  
 605  int emu_setKeymap(int index) {
 606    return 0;
 607  }
 608  
 609  int emu_GetMouse(int *x, int *y, int *buts) {
 610  #ifdef HAS_USBKEY
 611    if (mouse1.available()) {
 612      *buts = mouse1.getButtons();
 613      *x = mouse1.getMouseX();
 614      *y = mouse1.getMouseY();
 615      mouse1.mouseDataClear();
 616      mouseDetected = true;
 617      return 1;
 618    }   
 619  #endif
 620    return 0;
 621  }
 622  
 623  #ifdef HAS_USBKEY
 624  void OnPress(auto key)
 625  {
 626    keyboardDetected = true;
 627    uint8_t keymodifier = keyboard1.getModifiers();
 628  
 629    if(keymodifier == 0x40){
 630      // ALTGR Key modifier FR Keyboard
 631      switch (key) {
 632  #ifdef LAYOUT_FRENCH
 633        case 233 : key = '~' ; break;
 634        case  34 : key = '#' ; break;
 635        case  39 : key = '{' ; break;
 636        case  40 : key = '[' ; break;
 637        case  45 : key = '|' ; break;
 638        case 232 : key = '`' ; break;
 639        case  95 : key = 92  ; break;
 640        case 231 : key = '^' ; break;
 641        case 224 : key = '@' ; break;
 642        case  41 : key = ']' ; break;
 643        case  61 : key = '}' ; break;
 644  #endif  
 645  #ifdef LAYOUT_FRENCH_BELGIAN
 646        case  38 : key = '|' ; break; //1
 647        case 233 : key = '@' ; break; //2
 648        case  34 : key = '#' ; break; //3
 649        case 167 : key = '^' ; break; //6
 650        case 231 : key = '{' ; break; //9
 651        case 224 : key = '}' ; break; //0
 652        case  36 : key = ']' ; break; //$
 653        case  61 : key = '~' ; break; //=
 654  #endif  
 655      }
 656    }  
 657  
 658    if (menuActive())
 659    {
 660      switch (key)  
 661      {
 662        case 217:
 663          usbnavpad |= MASK_JOY2_DOWN;
 664          break;
 665        case 218:
 666          usbnavpad |= MASK_JOY2_UP;
 667          break;
 668        case 216:
 669          usbnavpad |= MASK_JOY2_LEFT;
 670          break;
 671        case 215:
 672          usbnavpad |= MASK_JOY2_RIGHT;
 673          break;
 674        case 10:
 675          usbnavpad |= MASK_JOY2_BTN;
 676          break;
 677        case 32:
 678          usbnavpad |= MASK_KEY_USER1;
 679          break;
 680        case 9:
 681          usbnavpad |= MASK_KEY_USER2;
 682          break;
 683      }     
 684    }
 685    else
 686    {
 687      emu_KeyboardOnDown(keymodifier, key);
 688    }
 689  }
 690  
 691  void OnRelease(int key)
 692  {
 693    keyboardDetected = true;
 694    uint8_t keymodifier = keyboard1.getModifiers();
 695  
 696    if(keymodifier == 0x40){
 697      // ALTGR Key modifier FR Keyboard
 698      switch (key) {
 699  #ifdef LAYOUT_FRENCH
 700        case 233 : key = '~' ; break;
 701        case  34 : key = '#' ; break;
 702        case  39 : key = '{' ; break;
 703        case  40 : key = '[' ; break;
 704        case  45 : key = '|' ; break;
 705        case 232 : key = '`' ; break;
 706        case  95 : key = 92  ; break;
 707        case 231 : key = '^' ; break;
 708        case 224 : key = '@' ; break;
 709        case  41 : key = ']' ; break;
 710        case  61 : key = '}' ; break;
 711  #endif  
 712  #ifdef LAYOUT_FRENCH_BELGIAN
 713        case  38 : key = '|' ; break; //1
 714        case 233 : key = '@' ; break; //2
 715        case  34 : key = '#' ; break; //3
 716        case 167 : key = '^' ; break; //6
 717        case 231 : key = '{' ; break; //9
 718        case 224 : key = '}' ; break; //0
 719        case  36 : key = ']' ; break; //$
 720        case  61 : key = '~' ; break; //=
 721  #endif  
 722      }
 723    }
 724  
 725    if (menuActive())
 726    {
 727      switch (key)  
 728      {
 729        case 217:
 730          usbnavpad &= ~MASK_JOY2_DOWN;
 731          break;
 732        case 218:
 733          usbnavpad &= ~MASK_JOY2_UP;
 734          break;
 735        case 216:
 736          usbnavpad &= ~MASK_JOY2_LEFT;
 737          break;
 738        case 215:
 739          usbnavpad &= ~MASK_JOY2_RIGHT;
 740          break;
 741        case 10:
 742          usbnavpad &= ~MASK_JOY2_BTN;
 743          break;
 744        case 32:
 745          usbnavpad &= ~MASK_KEY_USER1;
 746          break;
 747        case 9:
 748          usbnavpad &= ~MASK_KEY_USER2;
 749          break;
 750      }     
 751    }
 752    else
 753    {
 754      emu_KeyboardOnUp(keymodifier, key);  
 755    }
 756  }
 757  #endif
 758  
 759  int emu_MouseDetected(void) {
 760    return (mouseDetected?1:0);
 761  }
 762  
 763  int emu_KeyboardDetected(void) {
 764    return (keyboardDetected?1:0); 
 765  }
 766  
 767  #ifdef HAS_USBKEY
 768  static unsigned char midiBuffer[16];
 769  static unsigned char midiLastCmd=0;
 770  static int midiDataCnt=0;
 771  static int midiCmdNbParam=0;
 772  #endif
 773  
 774  void emu_MidiOnDataReceived(unsigned char value) {
 775  
 776  #ifdef HAS_USBKEY
 777  //Serial.println(value, HEX);    
 778  //10000000 = 128 = note off
 779  //10010000 = 144 = note on
 780  //10100000 = 160 = aftertouch
 781  //10110000 = 176 = continuous controller
 782  //11000000 = 192 = patch change
 783  //11010000 = 208 = channel pressure
 784  //11100000 = 224 = pitch bend
 785  //11110000 = 240 = non-musical commands
 786    if (value >= 128) {
 787      midiDataCnt = 0;
 788      midiLastCmd = value;
 789      switch (value & 0xF0) {
 790        case 128: // 0x80
 791          midiCmdNbParam = 2;
 792          //Serial.print("note off: ");      
 793          //Serial.println(value&0xf);            
 794          break;
 795        case 144: //0x90
 796          midiCmdNbParam = 2;
 797          //Serial.print("note on: ");      
 798          //Serial.println(value&0xf);            
 799          break;
 800        case 160: //0xA0
 801          midiCmdNbParam = 2;
 802          //Serial.print("aftertouch: "); // rare     
 803          //Serial.println(value&0xf);            
 804          break;
 805        case 176: //0xB0
 806          midiCmdNbParam = 2;
 807          //Serial.print("continuous controller: ");      
 808          //Serial.println(value&0xf);            
 809          break;
 810        case 192: //0xC0
 811          midiCmdNbParam = 1;
 812          //Serial.print("patch change: "); //some      
 813          //Serial.println(value&0xf);            
 814          break;
 815        case 208: //0xD0
 816          midiCmdNbParam = 1;
 817          Serial.print("channel pressure: ");      
 818          Serial.println(value&0xf);            
 819          break;
 820        case 224: //0xE0
 821          midiCmdNbParam = 2;
 822          //Serial.print("pitch bend: ");      
 823          //Serial.println(value&0xf);            
 824          break;
 825        case 240: //0xF0
 826          // non-musical commands     
 827          switch (value) {
 828            case 0xF0:
 829              //Serial.println("NI: System Exclusive"); 
 830              break;
 831            case 0xF1:
 832              //Serial.println("NI: System Common - MIDI Time Code Quarter Frame"); 
 833              break;
 834            case 0xF2:
 835               midiCmdNbParam = 2;
 836               break;
 837            case 0xF3:
 838              //Serial.println("NI: System Common - Song Select"); 
 839              break;
 840            case 0xF6:
 841              //Serial.println("NI: System Common - Tune Request"); 
 842              break;
 843            case 0xF8:
 844              //Serial.println("System Real Time - Timing Clock");
 845              midi1.sendRealTime(value, 0); 
 846              break;
 847            case 0xFA:
 848              //Serial.println("System Real Time - Start"); 
 849              midi1.sendRealTime(value, 0); 
 850              break;
 851            case 0xFB:
 852              //Serial.println("System Real Time - Continue"); 
 853              midi1.sendRealTime(value, 0); 
 854              break;
 855            case 0xFC:
 856              //Serial.println("System Real Time - Stop");
 857              midi1.sendRealTime(value, 0); 
 858              break;
 859            case 0xFE:
 860              //Serial.println("System Real Time - Active Sensing"); 
 861              midi1.sendRealTime(value, 0); 
 862              break;
 863            case 0xFF:
 864              //Serial.println("System Real Time - System Reset"); 
 865              midi1.sendRealTime(value, 0); 
 866              break;
 867          }
 868          //SystemExclusive       = 0xF0, // System Exclusive
 869          //TimeCodeQuarterFrame  = 0xF1, // System Common - MIDI Time Code Quarter Frame
 870          //SongPosition          = 0xF2, // System Common - Song Position Pointer
 871          //SongSelect            = 0xF3, // System Common - Song Select
 872          //TuneRequest           = 0xF6, // System Common - Tune Request
 873          //Clock                 = 0xF8, // System Real Time - Timing Clock
 874          //Start                 = 0xFA, // System Real Time - Start
 875          //Continue              = 0xFB, // System Real Time - Continue
 876          //Stop                  = 0xFC, // System Real Time - Stop
 877          //ActiveSensing         = 0xFE, // System Real Time - Active Sensing
 878          //SystemReset           = 0xFF, // System Real Time - System Reset                   
 879          break;
 880        default:
 881          Serial.print("??: ");      
 882          Serial.println(value&0xf);            
 883          break;      
 884      }          
 885    }
 886    else {
 887      if (midiDataCnt<16) midiBuffer[midiDataCnt++] = value ;
 888      if ( (midiLastCmd & 0xF0) == 240) {
 889        if (midiLastCmd == 0xF2) {
 890          if (midiDataCnt == midiCmdNbParam) {
 891            //Serial.println("System Common - Song Position Pointer"); 
 892            midi1.sendSongPosition(((int)midiBuffer[1]<<7)+(int)midiBuffer[0], 0);          
 893          }
 894        }
 895        else {
 896          Serial.println(value);
 897        }
 898      }
 899      else if (midiDataCnt == midiCmdNbParam) {
 900        unsigned char chan = (midiLastCmd&0xf)+1;
 901        //Serial.print("ch ");    
 902        //Serial.println(chan);    
 903        switch (midiLastCmd & 0xF0) {
 904          case 128: //0x80
 905            //Serial.print("note off: ");      
 906            midi1.sendNoteOff(midiBuffer[0], midiBuffer[1], chan);
 907            break;
 908          case 144: //0x90
 909            //Serial.print("note on: ");      
 910            midi1.sendNoteOn(midiBuffer[0], midiBuffer[1], chan);
 911            break;
 912          case 160: //0xA0
 913            //Serial.print("aftertouch: ");      
 914            midi1.sendPolyPressure(midiBuffer[0], midiBuffer[1], chan);
 915            break;
 916          case 176: //0xB0
 917            //Serial.print("continuous controller: ");      
 918            midi1.sendControlChange(midiBuffer[0], midiBuffer[1], chan);           
 919            break;
 920          case 192: //0xC0
 921            //Serial.print("patch change: ");      
 922            midi1.sendProgramChange(midiBuffer[0], chan);           
 923            break;
 924          case 208: //0xD0
 925            //Serial.print("channel pressure: ");      
 926            midi1.sendAfterTouch(midiBuffer[0], chan);                 
 927            break;
 928          case 224: //0xE0
 929            //Serial.print("pitch bend: ");          
 930            midi1.sendPitchBend((((int)midiBuffer[1]<<7)+(int)midiBuffer[0])-8192, chan);                  
 931            break;
 932          default:
 933            Serial.print("??: ");               
 934            break;      
 935        }         
 936      }
 937    }
 938  #endif  
 939  }
 940  
 941  /********************************
 942   * Menu file loader UI
 943  ********************************/ 
 944  static int readNbFiles(void) {
 945    int totalFiles = 0;
 946  
 947    File entry;    
 948    file = SD.open(selection);
 949    while ( (true) && (totalFiles<MAX_FILES) ) {
 950      entry = file.openNextFile();
 951      if (! entry) {
 952        // no more files
 953        break;
 954      }
 955    const char * filename = entry.name();
 956      Serial.println(filename); 
 957      if (!entry.isDirectory())  {
 958        strncpy(&files[totalFiles][0], filename, MAX_FILENAME_SIZE-1);
 959        totalFiles++;
 960      }
 961      else {
 962        if ( (strcmp(filename,".")) && (strcmp(filename,"..")) ) {
 963          strncpy(&files[totalFiles][0], filename, MAX_FILENAME_SIZE-1);
 964          totalFiles++;
 965        }
 966      }  
 967      entry.close();
 968    }
 969    file.close();
 970    return totalFiles;  
 971  }  
 972  
 973  
 974  
 975  void backgroundMenu(void) {
 976      menuRedraw=true;  
 977      tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00));
 978      tft.drawTextNoDma(0,0, TITLE, RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), true);         
 979  }
 980  
 981  int handleMenu(uint16_t bClick)
 982  {
 983    if (autorun) {
 984        return (ACTION_RUN1);                    
 985    }  
 986    
 987    int action = ACTION_NONE;
 988    if ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_JOY1_BTN) ) {     
 989        char newpath[MAX_FILENAME_PATH];
 990        strcpy(newpath, selection);
 991        strcat(newpath, "/");
 992        strcat(newpath, selected_filename);
 993        strcpy(selection,newpath);
 994        emu_printf("new filepath is");
 995        emu_printf(selection);
 996        File file = SD.open(selection);
 997        if (file.isDirectory())  {
 998          curFile = 0;
 999          nbFiles = readNbFiles();             
1000        }
1001        else {
1002          action = ACTION_RUN1;
1003  #ifdef TEECOMPUTER
1004          if (key_extmode) {
1005            emu_writeConfig();
1006          }
1007  #endif                       
1008        }
1009        menuRedraw=true;
1010    }
1011    else if ( bClick & MASK_KEY_USER1 ) {
1012        menuRedraw=true;
1013        strcpy(second_selected_filename,selected_filename); 
1014        strcpy(second_selection, selection);
1015        strcat(second_selection, "/");
1016        strcat(second_selection, second_selected_filename);      
1017        action = ACTION_RUN2;    
1018    }
1019    else if ( bClick & MASK_KEY_USER2  ) {
1020        menuRedraw=true;  
1021        //action = ACTION_RUN3;    
1022        emu_SwapJoysticks(0);
1023    }  
1024    else if ( (bClick & MASK_JOY2_UP) || (bClick & MASK_JOY1_UP) ) {
1025      if (curFile!=0) {
1026        menuRedraw=true;
1027        curFile--;
1028      }
1029    }
1030    else if ( (bClick & MASK_JOY2_RIGHT) || (bClick & MASK_JOY1_RIGHT) ) {
1031      if ((curFile-9)>=0) {
1032        menuRedraw=true;
1033        curFile -= 9;
1034      } else if (curFile!=0) {
1035        menuRedraw=true;
1036        curFile--;
1037      }
1038    }  
1039    else if ( (bClick & MASK_JOY2_DOWN) || (bClick & MASK_JOY1_DOWN) )  {
1040      if ((curFile<(nbFiles-1)) && (nbFiles)) {
1041        curFile++;
1042        menuRedraw=true;
1043      }
1044    }
1045    else if ( (bClick & MASK_JOY2_LEFT) || (bClick & MASK_JOY1_LEFT) ) {
1046      if ((curFile<(nbFiles-9)) && (nbFiles)) {
1047        curFile += 9;
1048        menuRedraw=true;
1049      }
1050      else if ((curFile<(nbFiles-1)) && (nbFiles)) {
1051        curFile++;
1052        menuRedraw=true;
1053      }
1054    } 
1055      
1056    if (menuRedraw && nbFiles) {
1057      int fileIndex = 0;
1058      tft.drawRectNoDma(MENU_FILE_XOFFSET,MENU_FILE_YOFFSET, MENU_FILE_W, MENU_FILE_H, MENU_FILE_BGCOLOR);
1059  //    if (curFile <= (MAX_MENULINES/2-1)) topFile=0;
1060  //    else topFile=curFile-(MAX_MENULINES/2);
1061      if (curFile <= (MAX_MENULINES-1)) topFile=0;
1062      else topFile=curFile-(MAX_MENULINES/2);
1063  
1064      //Serial.print("curfile: ");
1065      //Serial.println(curFile);
1066      //Serial.print("topFile: ");
1067      //Serial.println(topFile);
1068      
1069      int i=0;
1070      while (i<MAX_MENULINES) {
1071        if (fileIndex>=nbFiles) {
1072            // no more files
1073            break;
1074        }
1075        char * filename = &files[fileIndex][0];    
1076        if (fileIndex >= topFile) {              
1077          if ((i+topFile) < nbFiles ) {
1078            if ((i+topFile)==curFile) {
1079              tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, filename, RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true);
1080              strcpy(selected_filename,filename);            
1081            }
1082            else {
1083              tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, filename, RGBVAL16(0xff,0xff,0xff), MENU_FILE_BGCOLOR, true);      
1084            }
1085          }
1086          i++; 
1087        }
1088        fileIndex++;    
1089      }
1090  
1091      
1092  //    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);
1093      tft.drawTextNoDma(48,MENU_JOYS_YOFFSET+8, "FLOPPY2:", RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), false);
1094      tft.drawRectNoDma(120,MENU_JOYS_YOFFSET+8, MENU_FILE_W, 8, RGBVAL16(0x00,0x00,0x00));
1095      tft.drawTextNoDma(120,MENU_JOYS_YOFFSET+8, second_selected_filename, RGBVAL16(0xff,0xff,0xff), RGBVAL16(0x00,0x00,0x00), false);
1096      menuRedraw=false;     
1097    }
1098  
1099    return (action);  
1100  }
1101  
1102  bool menuActive(void) 
1103  {
1104    return (menuOn);
1105  }
1106  
1107  void toggleMenu(bool on) {
1108    if (on) {
1109      menuOn=true;
1110      backgroundMenu();
1111    } else {
1112      menuOn = false;    
1113    }
1114  }
1115  
1116  char * menuSelection(void)
1117  {
1118    return (selection);  
1119  }
1120  
1121  char * menuSecondSelection(void)
1122  {
1123    return (second_selection);  
1124  }
1125  
1126  
1127  /********************************
1128   * OSKB handling
1129  ********************************/   
1130  static bool oskbOn = false;
1131  static int cxpos = 0;
1132  static int cypos = 0;
1133  static uint16_t oskbBLastState = 0;
1134  #define OSKBHEIGHT 4
1135  #define OSKBXOFF   16
1136  #define OSKBYOFF   0
1137  
1138  static void lineOSKB(int xoff, bool bottom, char * str, int row)
1139  {
1140    char c[4] = {' ',0,' ',0};
1141    const char * cpt = str;
1142    int i=0;
1143    int fb_width,fb_height;
1144    tft.get_frame_buffer_size(&fb_width, &fb_height);
1145    int ypos = (bottom?(fb_height-2*8):0);
1146    int line = row + (bottom?2:0);
1147    while ((c[1] = *cpt++))
1148    {
1149      uint16_t bg;
1150      if (row&1) bg = (i&1)?RGBVAL16(0xff,0xff,0xff):RGBVAL16(0xe0,0xe0,0xe0);
1151      else bg = (i&1)?RGBVAL16(0xe0,0xe0,0xe0):RGBVAL16(0xff,0xff,0xff);
1152      if ( (cxpos == i) && (cypos == line) ) bg = RGBVAL16(0x00,0xff,0xff);
1153      tft.drawTextNoDma(OSKBXOFF+xoff+24*i,OSKBYOFF+ypos+8*row , &c[0], RGBVAL16(0x00,0x00,0x00), bg, false);
1154      i++;
1155    } 
1156  }
1157  
1158  static int linelenOSKB() {
1159    if (cypos == 0) return strlen(keylables_map0_0);
1160    else if (cypos == 1) return strlen(keylables_map0_1);
1161    else if (cypos == 2) return strlen(keylables_map0_2);
1162    else return strlen(keylables_map0_3);
1163  }
1164  
1165  static void drawOSKB() {
1166    if (key_extmode) {
1167      if (key_fn) {
1168        lineOSKB(16,false, keylables_map5_0,  0);
1169        lineOSKB(8, false, keylables_map5_1,  1);
1170        lineOSKB(0, true, keylables_map5_2,  0);
1171        lineOSKB(96,true, keylables_map5_3,  1);
1172      }
1173      else if (key_sh) {
1174        lineOSKB(16,false, keylables_map4_0,  0);
1175        lineOSKB(8, false, keylables_map4_1,  1);
1176        lineOSKB(0, true, keylables_map4_2,  0);
1177        lineOSKB(96,true, keylables_map4_3,  1);
1178      }
1179      else {
1180        lineOSKB(16,false, keylables_map3_0,  0);
1181        lineOSKB(8, false, keylables_map3_1,  1);
1182        lineOSKB(0, true, keylables_map3_2,  0);
1183        lineOSKB(96,true, keylables_map3_3,  1);
1184      }
1185    }
1186    else {
1187      if (key_fn) {
1188        lineOSKB(16,false, keylables_map2_0,  0);
1189        lineOSKB(8, false, keylables_map2_1,  1);
1190        lineOSKB(0, true, keylables_map2_2,  0);
1191        lineOSKB(96,true, keylables_map2_3,  1);
1192      }
1193      else if (key_sh) {
1194        lineOSKB(16,false, keylables_map1_0,  0);
1195        lineOSKB(8, false, keylables_map1_1,  1);
1196        lineOSKB(0, true, keylables_map1_2,  0);
1197        lineOSKB(96,true, keylables_map1_3,  1);
1198      }
1199      else {
1200        lineOSKB(16,false, keylables_map0_0,  0);
1201        lineOSKB(8, false, keylables_map0_1,  1);
1202        lineOSKB(0, true, keylables_map0_2,  0);
1203        lineOSKB(96,true, keylables_map0_3,  1);
1204      }
1205    }  
1206  }
1207  
1208  int handleOSKB(void) { 
1209    int retval = 0;
1210    if (oskbOn) {
1211      uint16_t bClick = bLastState & ~oskbBLastState;
1212      oskbBLastState = bLastState;
1213      bool updated = true;
1214      if (bClick & MASK_KEY_USER1)
1215      { 
1216      }    
1217      else if (bClick & MASK_JOY2_RIGHT)
1218      {  
1219        cxpos++;
1220        if (cxpos >= linelenOSKB()) cxpos = 0;
1221      }
1222      else if (bClick & MASK_JOY2_LEFT)
1223      {  
1224        cxpos--;
1225        if (cxpos < 0) cxpos = linelenOSKB()-1;
1226      }
1227      else if (bClick & MASK_JOY2_DOWN)
1228      {  
1229        cypos++;
1230        if (cypos >= OSKBHEIGHT) cypos = 0;
1231        if (cxpos >= linelenOSKB()) cxpos = linelenOSKB()-1;
1232      }
1233      else if (bClick & MASK_JOY2_UP)
1234      {  
1235        cypos--;
1236        if (cypos < 0) cypos = OSKBHEIGHT-1;
1237        if (cxpos >= linelenOSKB()) cxpos = linelenOSKB()-1;
1238      }
1239      else if (oskbBLastState & MASK_JOY2_BTN)
1240      {  
1241        //if (retval) { toggleOSKB(false); updated=false; };
1242      }
1243      else {
1244        updated=false;
1245      }    
1246      /*if (updated)*/ drawOSKB();
1247    }
1248    return retval; 
1249  }
1250  
1251  void toggleOSKB(bool forceon) {
1252    if (forceon) {
1253      oskbOn = true;
1254      drawOSKB();
1255    }
1256    else {
1257      if (oskbOn) {
1258        oskbOn = false;
1259      }
1260      else {
1261        oskbOn = true;
1262        drawOSKB();
1263      }
1264    }
1265  }
1266  
1267  
1268  
1269  /********************************
1270   * File IO
1271  ********************************/ 
1272  static File file_handlers[NB_FILE_HANDLER];
1273  
1274  static void FileHandlersInit(void) {
1275    for (int i=0; i<NB_FILE_HANDLER;i++) {
1276      file_handlers[i]=file;
1277    }
1278  }
1279  
1280  static int getFreeFileHandler(void) {
1281    for (int i=0; i<NB_FILE_HANDLER; i++) {
1282      if (!file_handlers[i] != file) return i;
1283    }
1284    emu_printf("No free file handler");
1285    return -1;
1286  }
1287  
1288  static File getFileHandler(int handler) {
1289    return (file_handlers[handler-1]);
1290  }
1291  
1292  //#define HCFH 1
1293  
1294  int emu_FileOpen(const char * filepath, const char * mode)
1295  {
1296  //  emu_printf("FileOpen...");
1297  //  emu_printf(filepath);
1298  #ifdef HCFH  
1299    int retval = 0;
1300    if ((file = SD.open(filepath, O_READ))) {
1301      retval = 1;  
1302    }
1303    else {
1304      emu_printf("FileOpen failed");
1305    }
1306    return (retval);
1307  #else
1308    int retval = 0;
1309    int handler = getFreeFileHandler();
1310    if (handler >= 0) {
1311      if ((file_handlers[handler] = SD.open(filepath, O_READ))) {
1312   //     emu_printi(handler+1);
1313        retval = handler+1;  
1314      }
1315      else {
1316        file_handlers[handler] = file;
1317        emu_printf("FileOpen failed");
1318      }
1319    }
1320    return (retval);
1321  #endif
1322  }
1323  
1324  int emu_FileRead(void * buf, int size, int handler)
1325  {
1326  //  emu_printf("FileRead");
1327  //  emu_printi(handler);
1328  #ifdef HCFH  
1329    return (file.read(buf, size));
1330  #else
1331    return (getFileHandler(handler).read(buf, size));
1332  #endif
1333  }
1334  
1335  int emu_FileGetc(int handler) {
1336  //  emu_printf("FileGetc");
1337  //  emu_printi(handler);
1338  #ifdef HCFH  
1339    unsigned char c;
1340    int retval = file.read(&c, 1);
1341    if (retval != 1) {
1342      emu_printf("emu_FileGetc failed");
1343    }  
1344    return (int)c; 
1345  #else
1346    unsigned char c;
1347    int retval = getFileHandler(handler).read(&c, 1);
1348    if (retval != 1) {
1349      emu_printf("emu_FileGetc failed");
1350    }  
1351    return (int)c; 
1352  #endif
1353  }
1354  
1355  int emu_FileSeek(int handler, int seek, int origin)
1356  {
1357  //  emu_printf("FileSeek");
1358  //  emu_printi(handler);
1359  //  emu_printi(seek);
1360  #ifdef HCFH  
1361    file.seek(seek);
1362    return (seek);
1363  #else
1364    getFileHandler(handler).seek(seek);
1365    return (seek);
1366  #endif
1367  }
1368  
1369  int emu_FileTell(int handler) {
1370  //  emu_printf("FileTell");
1371  //  emu_printi(handler);
1372  #ifdef HCFH  
1373    return (50);
1374  #else
1375    File file = getFileHandler(handler);
1376    return (emu_FileSize((char*)file.name()));
1377  #endif
1378  }
1379  
1380  
1381  void emu_FileClose(int handler)
1382  {
1383  //  emu_printf("FileClose");
1384  //  emu_printi(handler);
1385  #ifdef HCFH  
1386    file.close();  
1387  #else
1388    getFileHandler(handler).close();  
1389    file_handlers[handler-1] = file;
1390  #endif
1391  }
1392  
1393  
1394  static File lofile;
1395  
1396  unsigned int emu_FileSize(const char * filepath) 
1397  {
1398    unsigned int filesize=0;
1399    emu_printf(filepath);
1400    if ((lofile = SD.open(filepath, O_READ))) 
1401    {
1402      emu_printf("filesize is...");
1403      filesize = lofile.size(); 
1404      emu_printf(filesize);
1405      lofile.close();    
1406    }
1407    return(filesize);
1408  }
1409  
1410  unsigned int emu_LoadFile(const char * filepath, void * buf, int size)
1411  { 
1412    unsigned int filesize = 0;
1413    emu_printf("LoadFile...");
1414    emu_printf(filepath);
1415    if ((lofile = SD.open(filepath, O_READ))) 
1416    {
1417      filesize = lofile.size(); 
1418      emu_printf(filesize);
1419      if ((unsigned int)size >= filesize)
1420      {
1421        if (lofile.read(buf, filesize) != filesize) 
1422        {
1423          emu_printf("File read failed");
1424        }        
1425      }
1426      lofile.close();
1427    }
1428    return(filesize);
1429  }
1430  
1431  unsigned int emu_LoadFileSeek(const char * filepath, void * buf, int size, int seek)
1432  {  
1433    unsigned int filesize = 0;
1434    emu_printf("LoadFileSeek...");
1435    emu_printf(filepath);
1436    if ((lofile = SD.open(filepath, O_READ))) 
1437    {
1438      lofile.seek(seek);
1439      emu_printf(size);
1440      if (lofile.read(buf, size) != (unsigned int)size) {
1441        emu_printf("File read failed");
1442      }        
1443      lofile.close();
1444    }
1445    return(filesize);
1446  }
1447  
1448  static bool emu_writeConfig(void)
1449  {
1450    bool retval = false;
1451    if ((lofile = SD.open(ROMSDIR "/" AUTORUN_FILENAME, O_CREAT | O_WRITE)))
1452    {
1453      if (lofile.write(selection, strlen(selection)) != strlen(selection)) {
1454        emu_printf("Config write failed");
1455      }
1456      else {
1457        retval = true;
1458      }
1459      lofile.close();
1460    }
1461    return retval;
1462  }
1463  
1464  static bool emu_readConfig(void)
1465  {
1466    bool retval = false;
1467  
1468    if ((lofile = SD.open(ROMSDIR "/" AUTORUN_FILENAME, O_READ)))
1469    {
1470      unsigned int filesize = lofile.size();
1471      unsigned int sizeread = lofile.read(selection, filesize);
1472      if (sizeread != filesize) {
1473        emu_printf("Config read failed");
1474      }
1475      else {
1476        if (sizeread == filesize)
1477        {
1478          selection[filesize]=0;
1479          retval = true;
1480        }
1481      }
1482      lofile.close();
1483    }
1484    return retval;
1485  }
1486  
1487  static bool emu_eraseConfig(void)
1488  {
1489    SD.remove (ROMSDIR "/" AUTORUN_FILENAME);
1490  }
1491  
1492  /********************************
1493   * File IO compatibility
1494  ********************************/ 
1495  #ifdef HAS_EXTFF
1496  
1497  #include "ff.h"
1498  
1499  typedef struct {
1500    File f;
1501    int offset;
1502    int size;
1503    int used;
1504  } FileDesc;
1505  
1506  typedef int * FIL;
1507  
1508  
1509  
1510  #define NO_MMAP_HANDLES 32
1511  
1512  static FileDesc fds[NO_MMAP_HANDLES];
1513  static int nextHandle=0;
1514  
1515  static void freeHandle(int h) {
1516    fds[h].used = 0;
1517  }
1518  
1519  
1520  static int getFreeHandle() {
1521    int n=NO_MMAP_HANDLES;
1522    while (fds[nextHandle].used!=0 && n!=0) {
1523      nextHandle++;
1524      if (nextHandle==NO_MMAP_HANDLES) nextHandle=0;
1525      n-1;
1526    }
1527    if (n==0) {
1528      emu_printf("getFreeHandle error"); 
1529      return;
1530    }
1531    
1532    int r=nextHandle;
1533      fds[r].used = 1;  
1534    nextHandle++;
1535    if (nextHandle==NO_MMAP_HANDLES) nextHandle=0;
1536  
1537    return r;
1538  }
1539  
1540  FRESULT f_open (FIL* fp, const char * path, unsigned char mode)
1541  {
1542    emu_printf("fopen");
1543    emu_printf((char*)path);
1544    int i=getFreeHandle();
1545    emu_printf(i);
1546    fds[i].f = SD.open(path, O_READ);
1547    *fp = i;
1548    if  (fds[i].f) {
1549      fds[i].size = fds[i].f.size();
1550      emu_printi(fds[i].size);
1551      return(FR_OK);
1552    } 
1553    emu_printf("error");
1554    freeHandle(fds[i].f);
1555    return(FR_NO_FILE);
1556  }
1557  
1558  FRESULT f_close (FIL* fp)
1559  {
1560    int i = *fp;
1561    emu_printf("fclose");
1562    emu_printi(i);
1563    fds[i].f.close();  
1564    freeHandle(i);  
1565    return(FR_OK);
1566  }
1567  
1568  FRESULT f_read (FIL* fp, void* buff, unsigned int  btr, unsigned int * br)
1569  {
1570    int i = *fp;
1571  
1572    if (btr < 64738) {
1573      int nr = fds[i].f.read(buff, btr);
1574      //emu_printf("fread");
1575      //emu_printi(btr);  
1576      //emu_printi(nr);    
1577      *br = nr;
1578      if (nr <= 0) 
1579        return(FR_DISK_ERR);
1580      else
1581        return(FR_OK);
1582    }
1583  
1584    unsigned char buffer[256];
1585    
1586    int remaining = btr;
1587    int byteread = 0;
1588    int retval=0; 
1589  
1590      while (remaining>0) {
1591        if (remaining < 256)
1592          retval = fds[i].f.read(buffer, remaining);      
1593        else
1594          retval = fds[i].f.read(buffer, 256);
1595        if (retval>0) {
1596          memcpy(buff,buffer,retval);
1597          buff += retval;
1598          byteread += retval;     
1599          remaining -= retval;
1600        }
1601        else {
1602          break;
1603        }
1604      }    
1605      *br = byteread;
1606      //emu_printi(byteread);         
1607      if (byteread <= 0) 
1608        return(FR_DISK_ERR);
1609      else
1610        return(FR_OK);
1611  }
1612  
1613  FRESULT f_readn (FIL* fp, void* buff, unsigned int btr, unsigned int * br)
1614  {
1615    return(f_read (fp, buff, btr, br));
1616  }
1617  
1618  FRESULT f_write (FIL* fp, const void* buff, unsigned int  btw, unsigned int * bw)
1619  {
1620    return(FR_OK);
1621  }
1622  FRESULT f_writen (FIL* fp, const void* buff, unsigned int btw, unsigned int * bw)
1623  {
1624    return(FR_OK);
1625  }
1626  FRESULT f_lseek (FIL* fp, unsigned long ofs)
1627  {
1628    int i = *fp;
1629    //emu_printf("fseek");
1630    //emu_printi(ofs);  
1631    fds[i].f.seek(ofs);
1632    return(FR_OK);
1633  }
1634  
1635  
1636  FRESULT f_unlink (const char * path)
1637  {
1638    return(FR_OK);
1639  }
1640  FRESULT f_rename (const char * path_old, const  char * path_new)
1641  {
1642    return(FR_OK);
1643  }
1644  FRESULT f_stat (const char * path, FILINFO* fno)
1645  {
1646    return(FR_OK);
1647  }
1648  
1649  unsigned long f_tell (FIL * fp)
1650  {
1651    int i = *fp;
1652    emu_printf("ftell");
1653    return(fds[i].size);  
1654    //return(fds[i].f.ftell());
1655  }
1656  
1657  unsigned long f_size (FIL * fp)
1658  {
1659    int i = *fp;
1660    emu_printf("fsize");
1661    emu_printi(fds[i].size); 
1662    return(fds[i].size);
1663  }
1664  
1665  FRESULT f_mkdir (const char* path)
1666  {
1667    return(FR_OK);
1668  }  
1669  #endif
1670  
1671  
1672  /********************************
1673   * Initialization
1674  ********************************/ 
1675  void emu_init(void)
1676  {
1677    Serial.begin(115200);
1678  
1679  #ifdef HAS_USBKEY
1680    myusb.begin();
1681    keyboard1.attachPress(OnPress);
1682    keyboard1.attachRelease(OnRelease);
1683  #endif
1684  
1685    while (!SD.begin(SD_CS))
1686    {
1687      Serial.println("SD begin failed, retrying...");
1688      delay(1000);    
1689    }
1690    strcpy(selection,ROMSDIR);
1691    
1692    FileHandlersInit();
1693    
1694    nbFiles = readNbFiles(); 
1695  
1696    Serial.print("SD initialized, files found: ");
1697    Serial.println(nbFiles);
1698  
1699    emu_InitJoysticks();
1700  #ifdef SWAP_JOYSTICK
1701    joySwapped = true;   
1702  #else
1703    joySwapped = false;   
1704  #endif
1705  
1706  #ifdef TEECOMPUTER
1707  #ifndef HAS_T4_VGA
1708      tft.flipscreen(true);
1709  #endif
1710  #endif
1711    int keypressed = emu_ReadKeys();
1712    if (keypressed & MASK_JOY2_DOWN) {
1713      tft.fillScreenNoDma( RGBVAL16(0xff,0x00,0x00) );
1714      tft.drawTextNoDma(64,48,    (char*)" AUTURUN file erased", RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true);
1715      emu_eraseConfig();
1716      delay(1000);
1717    }
1718    else {
1719      if (emu_readConfig()) {
1720        autorun = true;
1721      }
1722    }  
1723  
1724    toggleMenu(true);
1725  }
1726  
1727  
1728  void emu_start(void)
1729  {
1730    usbnavpad = 0;
1731  }