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_640x240); 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_640x240); 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 }