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