emuapi.cpp
1 #define KEYMAP_PRESENT 1 2 3 #include <stdint.h> 4 #include <stdbool.h> 5 #include <stddef.h> 6 #include <string.h> 7 8 extern "C" { 9 #include "emuapi.h" 10 #include "iopins.h" 11 } 12 13 #include "ili9341_t3dma.h" 14 //#include "logo.h" 15 #include "bmpjoy.h" 16 #include "bmpvbar.h" 17 18 #include "esp_event.h" 19 #include "esp_vfs_fat.h" 20 #include "driver/sdspi_host.h" 21 #include <dirent.h> 22 #include <sys/stat.h> 23 #include <driver/adc.h> 24 25 #ifdef HAS_I2CKBD 26 #ifdef USE_WIRE 27 #include "Wire.h" 28 #else 29 #include <driver/i2c.h> 30 #define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/ 31 #define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */ 32 #define ACK_VAL 0x0 /*!< I2C ack value */ 33 #define NACK_VAL 0x1 /*!< I2C nack value */ 34 #endif 35 36 #define I2C_FREQ_HZ 400000 /*!< I2C master clock frequency */ 37 static bool i2cKeyboardPresent = false; 38 #endif 39 40 41 extern ILI9341_t3DMA tft; 42 43 static char romspath[64]; 44 static int calMinX=-1,calMinY=-1,calMaxX=-1,calMaxY=-1; 45 static sdmmc_card_t* card; 46 const uint16_t deflogo[] = { 47 0x0000,0x0000 48 }; 49 static const uint16_t * logo = deflogo; 50 51 #define CALIBRATION_FILE "/sdcard/cal.cfg" 52 53 #define MAX_FILENAME_SIZE 28 54 #define MAX_MENULINES (MKEY_L9) 55 #define TEXT_HEIGHT 16 56 #define TEXT_WIDTH 8 57 #define MENU_FILE_XOFFSET (6*TEXT_WIDTH) 58 #define MENU_FILE_YOFFSET (2*TEXT_HEIGHT) 59 #define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH) 60 #define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT) 61 #define MENU_FILE_FGCOLOR RGBVAL16(0xff,0xff,0xff) 62 #define MENU_FILE_BGCOLOR RGBVAL16(0x00,0x00,0x20) 63 #define MENU_JOYS_YOFFSET (12*TEXT_HEIGHT) 64 #define MENU_VBAR_XOFFSET (0*TEXT_WIDTH) 65 #define MENU_VBAR_YOFFSET (MENU_FILE_YOFFSET) 66 67 68 #define MKEY_L1 1 69 #define MKEY_L2 2 70 #define MKEY_L3 3 71 #define MKEY_L4 4 72 #define MKEY_L5 5 73 #define MKEY_L6 6 74 #define MKEY_L7 7 75 #define MKEY_L8 8 76 #define MKEY_L9 9 77 #define MKEY_UP 20 78 #define MKEY_DOWN 21 79 #define MKEY_JOY 22 80 81 82 const unsigned short menutouchareas[] = { 83 TAREA_XY,MENU_FILE_XOFFSET,MENU_FILE_YOFFSET, 84 TAREA_WH,MENU_FILE_W, TEXT_HEIGHT, 85 TAREA_NEW_COL,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT, 86 87 TAREA_XY,MENU_VBAR_XOFFSET,MENU_VBAR_YOFFSET, 88 TAREA_WH,32,48, 89 TAREA_NEW_COL, 72,72,8,40, 90 91 TAREA_END}; 92 93 const unsigned short menutouchactions[] = { 94 MKEY_L1,MKEY_L2,MKEY_L3,MKEY_L4,MKEY_L5,MKEY_L6,MKEY_L7,MKEY_L8,MKEY_L9, 95 MKEY_UP,MKEY_DOWN,ACTION_NONE,MKEY_JOY}; 96 97 98 static bool menuOn=true; 99 static bool callibrationOn=false; 100 static int callibrationStep=0; 101 static bool menuRedraw=true; 102 static int nbFiles=0; 103 static int curFile=0; 104 static int topFile=0; 105 static char selection[MAX_FILENAME_SIZE+1]=""; 106 static uint8_t prev_zt=0; 107 108 static int readNbFiles(void) { 109 int totalFiles = 0; 110 111 DIR* dir = opendir(romspath); 112 while (true) { 113 struct dirent* de = readdir(dir); 114 if (!de) { 115 // no more files 116 break; 117 } 118 if (de->d_type == DT_REG) { 119 totalFiles++; 120 } 121 else if (de->d_type == DT_DIR) { 122 if ( (strcmp(de->d_name,".")) && (strcmp(de->d_name,"..")) ) { 123 totalFiles++; 124 } 125 } 126 } 127 closedir(dir); 128 printf("Directory read: %d files",totalFiles); 129 return totalFiles; 130 } 131 132 static char captureTouchZone(const unsigned short * areas, const unsigned short * actions, int *rx, int *ry, int *rw, int * rh) { 133 uint16_t xt=0; 134 uint16_t yt=0; 135 uint16_t zt=0; 136 bool hDir=true; 137 138 if (tft.isTouching()) 139 { 140 if (prev_zt == 0) { 141 prev_zt =1; 142 tft.readCal(&xt,&yt,&zt); 143 if (zt<1000) { 144 prev_zt=0; 145 return ACTION_NONE; 146 } 147 int i=0; 148 int k=0; 149 int y2=0, y1=0; 150 int x2=0, x1=0; 151 int x=KEYBOARD_X,y=KEYBOARD_Y; 152 int w=TAREA_W_DEF,h=TAREA_H_DEF; 153 uint8_t s; 154 while ( (s=areas[i++]) != TAREA_END ) { 155 if (s == TAREA_XY) { 156 x = areas[i++]; 157 y = areas[i++]; 158 x2 = x; 159 y2 = y; 160 } 161 else if (s == TAREA_WH) { 162 w = areas[i++]; 163 h = areas[i++]; 164 } 165 else if (s == TAREA_NEW_ROW) { 166 hDir = true; 167 y1 = y2; 168 y2 = y1 + h; 169 x2 = x; 170 } 171 else if (s == TAREA_NEW_COL) { 172 hDir = false; 173 x1 = x2; 174 x2 = x1 + w; 175 y2 = y; 176 } 177 else { 178 if (hDir) { 179 x1 = x2; 180 x2 = x1+s; 181 } else { 182 y1 = y2; 183 y2 = y1+s; 184 } 185 if ( (yt >= y1) && (yt < y2) && (xt >= x1) && (xt < x2) ) { 186 *rx = x1; 187 *ry = y1; 188 *rw = x2-x1; 189 *rh = y2-y1; 190 return (actions[k]); 191 } 192 k++; 193 } 194 } 195 } 196 prev_zt =1; 197 } else { 198 prev_zt=0; 199 } 200 201 return ACTION_NONE; 202 } 203 204 void toggleMenu(bool on) { 205 if (on) { 206 callibrationOn=false; 207 menuOn=true; 208 menuRedraw=true; 209 tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00)); 210 tft.drawTextNoDma(0,0, TITLE, RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), true); 211 tft.drawSpriteNoDma(MENU_VBAR_XOFFSET,MENU_VBAR_YOFFSET,(uint16_t*)bmpvbar); 212 } else { 213 menuOn = false; 214 } 215 } 216 217 218 static void callibrationInit(void) 219 { 220 callibrationOn=true; 221 menuOn=false; 222 callibrationStep = 0; 223 calMinX=0,calMinY=0,calMaxX=0,calMaxY=0; 224 tft.fillScreenNoDma(RGBVAL16(0xff,0xff,0xff)); 225 tft.drawTextNoDma(0,100, " Callibration process:", RGBVAL16(0x00,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true); 226 tft.drawTextNoDma(0,116, " Hit the red cross at each corner", RGBVAL16(0x00,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true); 227 tft.drawTextNoDma(0,0, "+", RGBVAL16(0xff,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true); 228 prev_zt = 1; 229 } 230 231 static void readCallibration(void) 232 { 233 FILE * file = fopen(CALIBRATION_FILE, "rb"); 234 if (file) { 235 fscanf(file,"%d %d %d %d\n",&calMinX,&calMinY,&calMaxX,&calMaxY); 236 fclose(file); 237 printf("Current callibration params: %d %d %d %d\n",calMinX,calMinY,calMaxX,calMaxY); 238 } 239 else { 240 printf("Callibration read error\n"); 241 } 242 tft.callibrateTouch(calMinX,calMinY,calMaxX,calMaxY); 243 } 244 245 static void writeCallibration(void) 246 { 247 tft.callibrateTouch(calMinX,calMinY,calMaxX,calMaxY); 248 FILE * file = fopen(CALIBRATION_FILE, "wb"); 249 if (file) { 250 fprintf(file,"%d %d %d %d\n",calMinX,calMinY,calMaxX,calMaxY); 251 fclose(file); 252 } 253 else { 254 printf("Callibration write error\n"); 255 } 256 } 257 258 259 bool callibrationActive(void) 260 { 261 return (callibrationOn); 262 } 263 264 265 266 int handleCallibration(uint16_t bClick) { 267 uint16_t xt=0; 268 uint16_t yt=0; 269 uint16_t zt=0; 270 if (tft.isTouching()) { 271 if (prev_zt == 0) { 272 prev_zt = 1; 273 tft.readRaw(&xt,&yt,&zt); 274 if (zt < 1000) { 275 return 0; 276 } 277 switch (callibrationStep) 278 { 279 case 0: 280 callibrationStep++; 281 tft.drawTextNoDma(0,0, " ", RGBVAL16(0xff,0xff,0xff), RGBVAL16(0xff,0xff,0xff), true); 282 tft.drawTextNoDma(ILI9341_TFTREALWIDTH-8,0, "+", RGBVAL16(0xff,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true); 283 calMinX += xt; 284 calMinY += yt; 285 break; 286 case 1: 287 callibrationStep++; 288 tft.drawTextNoDma(ILI9341_TFTREALWIDTH-8,0, " ", RGBVAL16(0xff,0xff,0xff), RGBVAL16(0xff,0xff,0xff), true); 289 tft.drawTextNoDma(ILI9341_TFTREALWIDTH-8,ILI9341_TFTREALHEIGHT-16, "+", RGBVAL16(0xff,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true); 290 calMaxX += xt; 291 calMinY += yt; 292 break; 293 case 2: 294 callibrationStep++; 295 tft.drawTextNoDma(ILI9341_TFTREALWIDTH-8,ILI9341_TFTREALHEIGHT-16, " ", RGBVAL16(0xff,0xff,0xff), RGBVAL16(0xff,0xff,0xff), true); 296 tft.drawTextNoDma(0,ILI9341_TFTREALHEIGHT-16, "+", RGBVAL16(0xff,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true); 297 calMaxX += xt; 298 calMaxY += yt; 299 break; 300 case 3: 301 tft.fillScreenNoDma(RGBVAL16(0xff,0xff,0xff)); 302 tft.drawTextNoDma(0,100, " Callibration done!", RGBVAL16(0x00,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true); 303 tft.drawTextNoDma(0,116, " (Click center to exit)", RGBVAL16(0xff,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true); 304 callibrationStep++; 305 calMinX += xt; 306 calMaxY += yt; 307 break; 308 case 4: 309 if ( (xt > (ILI9341_TFTREALWIDTH/4)) && (xt < (ILI9341_TFTREALWIDTH*3)/4) 310 && (yt > (ILI9341_TFTREALHEIGHT/4)) && (yt < (ILI9341_TFTREALHEIGHT*3)/4) ) { 311 calMinX /= 2; 312 calMinY /= 2; 313 calMaxX /= 2; 314 calMaxY /= 2; 315 writeCallibration(); 316 toggleMenu(true); 317 } 318 else { 319 callibrationInit(); 320 } 321 break; 322 323 } 324 vTaskDelay(100 / portTICK_PERIOD_MS); 325 } 326 } 327 else { 328 prev_zt = 0; 329 } 330 return 1; 331 } 332 333 334 335 bool menuActive(void) 336 { 337 return (menuOn); 338 } 339 340 int handleMenu(uint16_t bClick) 341 { 342 int action = ACTION_NONE; 343 344 char newpath[80]; 345 strcpy(newpath, romspath); 346 strcat(newpath, "/"); 347 strcat(newpath, selection); 348 349 struct stat st; 350 bool newPathIsDir = false; 351 if(stat(newpath,&st) == 0) 352 if((st.st_mode & S_IFDIR) != 0) 353 newPathIsDir = true; 354 355 int rx=0,ry=0,rw=0,rh=0; 356 char c = captureTouchZone(menutouchareas, menutouchactions, &rx,&ry,&rw,&rh); 357 if ( ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_KEY_USER1) ) && (newPathIsDir) ) { 358 menuRedraw=true; 359 strcpy(romspath,newpath); 360 curFile = 0; 361 nbFiles = readNbFiles(); 362 } 363 else if ( (c >= MKEY_L1) && (c <= MKEY_L9) ) { 364 if ( (topFile+(int)c-1) <= (nbFiles-1) ) 365 { 366 curFile = topFile + (int)c -1; 367 menuRedraw=true; 368 //tft.drawRectNoDma( rx,ry,rw,rh, KEYBOARD_HIT_COLOR ); 369 } 370 } 371 else if ( (bClick & MASK_JOY2_BTN) ) { 372 menuRedraw=true; 373 action = ACTION_RUNTFT; 374 } 375 else if (bClick & MASK_JOY2_UP) { 376 if (curFile!=0) { 377 menuRedraw=true; 378 curFile--; 379 } 380 } 381 else if ( (bClick & MASK_JOY2_RIGHT) || (c == MKEY_UP) ) { 382 if ((curFile-9)>=0) { 383 menuRedraw=true; 384 curFile -= 9; 385 } else if (curFile!=0) { 386 menuRedraw=true; 387 curFile--; 388 } 389 } 390 else if (bClick & MASK_JOY2_DOWN) { 391 if ((curFile<(nbFiles-1)) && (nbFiles)) { 392 curFile++; 393 menuRedraw=true; 394 } 395 } 396 else if ( (bClick & MASK_JOY2_LEFT) || (c == MKEY_DOWN) ) { 397 if ((curFile<(nbFiles-9)) && (nbFiles)) { 398 curFile += 9; 399 menuRedraw=true; 400 } 401 else if ((curFile<(nbFiles-1)) && (nbFiles)) { 402 curFile++; 403 menuRedraw=true; 404 } 405 } 406 else if ( (bClick & MASK_KEY_USER1) || (c == MKEY_JOY) ) { 407 emu_SwapJoysticks(0); 408 menuRedraw=true; 409 } 410 411 412 if (menuRedraw && nbFiles) { 413 414 int fileIndex = 0; 415 DIR* dir = opendir(romspath); 416 tft.drawRectNoDma(MENU_FILE_XOFFSET,MENU_FILE_YOFFSET, MENU_FILE_W, MENU_FILE_H, MENU_FILE_BGCOLOR); 417 // if (curFile <= (MAX_MENULINES/2-1)) topFile=0; 418 // else topFile=curFile-(MAX_MENULINES/2); 419 if (curFile <= (MAX_MENULINES-1)) topFile=0; 420 else topFile=curFile-(MAX_MENULINES/2); 421 422 int i=0; 423 while (i<MAX_MENULINES) { 424 struct dirent* de = readdir(dir); 425 if (!de) { 426 break; 427 } 428 if ( (de->d_type == DT_REG) || ((de->d_type == DT_DIR) && (strcmp(de->d_name,".")) && (strcmp(de->d_name,"..")) ) ) { 429 if (fileIndex >= topFile) { 430 if ((i+topFile) < nbFiles ) { 431 if ((i+topFile)==curFile) { 432 tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, de->d_name, RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true); 433 strcpy(selection,de->d_name); 434 } 435 else { 436 tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, de->d_name, MENU_FILE_FGCOLOR, MENU_FILE_BGCOLOR, true); 437 } 438 } 439 i++; 440 } 441 fileIndex++; 442 } 443 } 444 closedir(dir); 445 446 tft.drawSpriteNoDma(0,MENU_JOYS_YOFFSET,(uint16_t*)bmpjoy); 447 tft.drawTextNoDma(48,MENU_JOYS_YOFFSET+8, (emu_SwapJoysticks(1)?(char*)"SWAP=1":(char*)"SWAP=0"), RGBVAL16(0x00,0xff,0xff), RGBVAL16(0xff,0x00,0x00), false); 448 449 menuRedraw=false; 450 } 451 452 453 return (action); 454 } 455 456 char * menuSelection(void) 457 { 458 return (selection); 459 } 460 461 #ifdef HAS_I2CKBD 462 #ifdef USE_WIRE 463 #else 464 static esp_err_t i2c_master_read_slave_reg(i2c_port_t i2c_num, uint8_t i2c_addr, uint8_t* data_rd, size_t size) 465 { 466 if (size == 0) { 467 return ESP_OK; 468 } 469 i2c_cmd_handle_t cmd = i2c_cmd_link_create(); 470 i2c_master_start(cmd); 471 i2c_master_write_byte(cmd, ( i2c_addr << 1 ) | I2C_MASTER_READ, ACK_CHECK_EN); 472 if (size > 1) { 473 i2c_master_read(cmd, data_rd, size - 1, (i2c_ack_type_t)ACK_VAL); 474 } 475 i2c_master_read_byte(cmd, data_rd + size - 1, (i2c_ack_type_t)NACK_VAL); 476 i2c_master_stop(cmd); 477 esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS); 478 i2c_cmd_link_delete(cmd); 479 return ret; 480 } 481 #endif 482 #endif 483 484 485 void emu_init(void) 486 { 487 488 esp_err_t ret = 0; 489 490 printf("mounting sd...\n"); 491 492 sdmmc_host_t host = SDSPI_HOST_DEFAULT(); 493 host.max_freq_khz = 10000; 494 //host.slot = HSPI_HOST; 495 496 sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT(); 497 slot_config.gpio_miso = SPIN_NUM_MISO; 498 slot_config.gpio_mosi = SPIN_NUM_MOSI; 499 slot_config.gpio_sck = SPIN_NUM_CLK; 500 slot_config.gpio_cs = SPIN_NUM_CS; 501 slot_config.dma_channel = 2; 502 503 504 esp_vfs_fat_sdmmc_mount_config_t mount_config = { 505 .format_if_mount_failed = false, 506 .max_files = 5, 507 .allocation_unit_size = 16 * 1024 508 }; 509 510 511 while((ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card)) != ESP_OK) { 512 printf("retrying\n"); 513 vTaskDelay(500 / portTICK_PERIOD_MS); 514 } 515 516 strcpy(romspath,"/sdcard/"); 517 strcat(romspath,ROMSDIR); 518 printf("dir is : %s\n",romspath); 519 520 nbFiles = readNbFiles(); 521 printf("SD initialized, files found: %d\n",nbFiles); 522 523 524 tft.touchBegin(); 525 //uint16_t xt=0; 526 //uint16_t yt=0; 527 //uint16_t zt=0; 528 //tft.readRo(&xt,&yt,&zt); 529 530 531 emu_InitJoysticks(); 532 readCallibration(); 533 534 if ((tft.isTouching()) || (emu_ReadKeys() & MASK_JOY2_BTN) ) { 535 callibrationInit(); 536 } else { 537 toggleMenu(true); 538 } 539 540 #ifdef HAS_I2CKBD 541 uint8_t msg[7]={0,0,0,0,0,0,0}; 542 543 #ifdef USE_WIRE 544 Wire.begin(I2C_SDA_IO, I2C_SCL_IO); 545 Wire.requestFrom(8, 7, I2C_FREQ_HZ); // request 5 bytes from slave device #8 546 int i = 0; 547 int hitindex=-1; 548 while (Wire.available() && (i<7) ) { // slave may send less than requested 549 uint8_t b = Wire.read(); // receive a byte 550 if (b != 0xff) hitindex=i; 551 msg[i++] = b; 552 } 553 #else 554 int i2c_master_port = I2C_NUM_1; 555 i2c_config_t conf; 556 conf.mode = I2C_MODE_MASTER; 557 conf.sda_io_num = I2C_SDA_IO; 558 conf.sda_pullup_en = GPIO_PULLUP_ENABLE; 559 conf.scl_io_num = I2C_SCL_IO; 560 conf.scl_pullup_en = GPIO_PULLUP_ENABLE; 561 conf.master.clk_speed = I2C_FREQ_HZ; 562 i2c_param_config((i2c_port_t)i2c_master_port, &conf); 563 if (i2c_driver_install((i2c_port_t)i2c_master_port, conf.mode,0, 0, 0) != ESP_OK) 564 printf("I2C Failed initialized\n"); 565 566 if (i2c_master_read_slave_reg( I2C_NUM_1, 8, &msg[0], 7 ) != ESP_OK) 567 printf("I2C Failed \n"); 568 #endif 569 570 571 572 573 if ( (msg[0] == 0xff) && (msg[1] == 0xff) && 574 (msg[2] == 0xff) && (msg[3] == 0xff) && 575 (msg[4] == 0xff) && (msg[5] == 0xff) && (msg[6] == 0xff)) { 576 i2cKeyboardPresent = true; 577 printf("i2C keyboard found\n"); 578 } 579 #endif 580 } 581 582 583 void emu_printf(char * text) 584 { 585 printf("%s\n",text); 586 } 587 588 589 void emu_printi(int val) 590 { 591 printf("%d\n",val); 592 } 593 594 void * emu_Malloc(int size) 595 { 596 void * retval = malloc(size); 597 if (!retval) { 598 printf("failled to allocate %d\n",size); 599 } 600 else { 601 printf("could allocate %d\n",size); 602 } 603 604 return retval; 605 } 606 607 void emu_Free(void * pt) 608 { 609 free(pt); 610 } 611 612 613 static FILE * lastfileOpened; 614 615 616 int emu_FileOpen(char * filename) 617 { 618 int retval = 0; 619 620 char filepath[80]; 621 strcpy(filepath, romspath); 622 strcat(filepath, "/"); 623 strcat(filepath, filename); 624 //printf("FileOpen...%s\n",filepath); 625 626 lastfileOpened = fopen(filepath, "rb"); 627 if (lastfileOpened) { 628 retval = 1; 629 } 630 else { 631 //printf("FileOpen failed\n"); 632 } 633 return (retval); 634 } 635 636 int emu_FileRead(char * buf, int size) 637 { 638 int retval = fread(buf, 1, size, lastfileOpened); 639 if (retval != size) { 640 printf("FileRead failed\n"); 641 } 642 return (retval); 643 } 644 645 unsigned char emu_FileGetc(void) { 646 unsigned char c; 647 int retval = fread(&c, 1, 1, lastfileOpened); 648 if (retval != 1) { 649 printf("emu_FileGetc failed\n"); 650 } 651 return c; 652 } 653 654 655 void emu_FileClose(void) 656 { 657 fclose(lastfileOpened); 658 } 659 660 int emu_FileSize(char * filename) 661 { 662 int filesize=0; 663 char filepath[80]; 664 strcpy(filepath, romspath); 665 strcat(filepath, "/"); 666 strcat(filepath, filename); 667 printf("FileSize...%s\n",filepath); 668 669 FILE * file = fopen(filepath, "rb"); 670 if (file) { 671 fseek(file, 0L, SEEK_END); 672 filesize = ftell(file); 673 //fseek(file, 0L, SEEK_SET); 674 printf("filesize is...%d\n",filesize); 675 fclose(file); 676 } 677 678 return(filesize); 679 } 680 681 int emu_FileSeek(int seek) 682 { 683 fseek(lastfileOpened, seek, SEEK_SET); 684 return (seek); 685 } 686 687 int emu_LoadFile(char * filename, char * buf, int size) 688 { 689 int filesize = 0; 690 691 char filepath[80]; 692 strcpy(filepath, romspath); 693 strcat(filepath, "/"); 694 strcat(filepath, filename); 695 printf("LoadFile...%s\n",filepath); 696 697 filesize = emu_FileSize(filename); 698 FILE * file = fopen(filepath, "rb"); 699 if (file) { 700 if (size >= filesize) 701 { 702 if (fread(buf, 1, filesize, file) != filesize) { 703 printf("File read failed\n"); 704 } 705 } 706 fclose(file); 707 } 708 709 return(filesize); 710 } 711 712 int emu_LoadFileSeek(char * filename, char * buf, int size, int seek) 713 { 714 int filesize = 0; 715 716 char filepath[80]; 717 strcpy(filepath, romspath); 718 strcat(filepath, "/"); 719 strcat(filepath, filename); 720 printf("LoadFileSeek...%d bytes at %d from %s\n",size,seek,filepath); 721 722 FILE * file = fopen(filepath, "rb"); 723 if (file) { 724 fseek(file, seek, SEEK_SET); 725 if (fread(buf, size, 1, file) != size) { 726 printf("File read failed\n"); 727 } 728 fclose(file); 729 } 730 731 return(filesize); 732 } 733 734 static int keypadval=0; 735 static bool joySwapped = false; 736 static uint16_t bLastState; 737 static int xRef; 738 static int yRef; 739 740 int emu_ReadAnalogJoyX(int min, int max) 741 { 742 int val; //adc1_get_raw((adc1_channel_t)PIN_JOY2_A1X); 743 adc2_get_raw((adc2_channel_t)PIN_JOY2_A1X, ADC_WIDTH_BIT_12,&val); 744 //printf("refX:%d X:%d\n",xRef,val); 745 val = val-xRef; 746 //val = ((val*140)/100); 747 if ( (val > -xRef/4) && (val < xRef/4) ) val = 0; 748 #if INVX 749 val = xRef-val; 750 #else 751 val = val+xRef; 752 #endif 753 754 return (val*(max-min))/(xRef*2); 755 } 756 757 int emu_ReadAnalogJoyY(int min, int max) 758 { 759 int val; //= adc1_get_raw((adc1_channel_t)PIN_JOY2_A2Y); 760 adc2_get_raw((adc2_channel_t)PIN_JOY2_A2Y, ADC_WIDTH_BIT_12,&val); 761 //printf("refY:%d Y:%d\n",yRef,val); 762 val = val-yRef; 763 //val = ((val*120)/100); 764 if ( (val > -yRef/4) && (val < yRef/4) ) val = 0; 765 #if INVY 766 val = yRef-val; 767 #else 768 val = val+yRef; 769 #endif 770 return (val*(max-min))/(yRef*2); 771 } 772 773 774 static uint16_t readAnalogJoystick(void) 775 { 776 uint16_t joysval = 0; 777 778 int xReading = emu_ReadAnalogJoyX(0,256); 779 if (xReading > 128) joysval |= MASK_JOY2_LEFT; 780 else if (xReading < 128) joysval |= MASK_JOY2_RIGHT; 781 782 int yReading = emu_ReadAnalogJoyY(0,256); 783 if (yReading < 128) joysval |= MASK_JOY2_UP; 784 else if (yReading > 128) joysval |= MASK_JOY2_DOWN; 785 786 joysval |= ((gpio_get_level((gpio_num_t)PIN_JOY2_BTN) == 1) ? 0 : MASK_JOY2_BTN); 787 788 return (joysval); 789 } 790 791 792 int emu_SwapJoysticks(int statusOnly) { 793 if (!statusOnly) { 794 if (joySwapped) { 795 joySwapped = false; 796 } 797 else { 798 joySwapped = true; 799 } 800 } 801 return(joySwapped?1:0); 802 } 803 804 int emu_GetPad(void) 805 { 806 return(keypadval|((joySwapped?1:0)<<7)); 807 } 808 809 int emu_ReadKeys(void) 810 { 811 uint16_t retval; 812 uint16_t j1 = readAnalogJoystick(); 813 814 uint16_t j2 = 0; 815 816 if (joySwapped) { 817 retval = ((j1 << 8) | j2); 818 } 819 else { 820 retval = ((j2 << 8) | j1); 821 } 822 823 if (gpio_get_level((gpio_num_t)PIN_KEY_USER1) == 0 ) retval |= MASK_KEY_USER1; 824 if (gpio_get_level((gpio_num_t)PIN_KEY_USER2) == 0 ) retval |= MASK_KEY_USER2; 825 826 //printf("%d\n",retval); 827 return (retval); 828 } 829 830 unsigned short emu_DebounceLocalKeys(void) 831 { 832 uint16_t bCurState = emu_ReadKeys(); 833 uint16_t bClick = bCurState & ~bLastState; 834 bLastState = bCurState; 835 836 return (bClick); 837 } 838 839 840 int emu_ReadI2CKeyboard(void) { 841 int retval=0; 842 #ifdef HAS_I2CKBD 843 if (i2cKeyboardPresent) { 844 uint8_t msg[7]; 845 #ifdef USE_WIRE 846 Wire.requestFrom(8, 7, I2C_FREQ_HZ); // request 5 bytes from slave device #8 847 int i = 0; 848 int hitindex=-1; 849 while (Wire.available() && (i<7) ) { // slave may send less than requested 850 uint8_t b = Wire.read(); // receive a byte 851 if (b != 0xff) hitindex=i; 852 msg[i++] = b; 853 } 854 #else 855 if (i2c_master_read_slave_reg( I2C_NUM_1, 8, &msg[0], 7 ) != ESP_OK) 856 printf("I2C Failed \n"); 857 int hitindex=-1; 858 int i = 0; 859 while (i<7) { 860 if (msg[i] != 0xff) hitindex=i; 861 i++; 862 } 863 #endif 864 //printf("I2C 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n", 865 // msg[0],msg[1],msg[2],msg[3],msg[4],msg[5],msg[6]); 866 if ((hitindex >=0 ) && (hitindex <=6 )) { 867 unsigned short match = ((~msg[hitindex])&0x00FF) | (hitindex<<8); 868 for (i=0; i<sizeof(i2ckeys); i++) { 869 if (match == i2ckeys[i]) { 870 //printf("I2C %d\n",keys[i]); 871 return (keys[i]); 872 } 873 } 874 } 875 } 876 #endif 877 return(retval); 878 } 879 880 void emu_InitJoysticks(void) { 881 gpio_set_direction((gpio_num_t)PIN_JOY2_BTN, GPIO_MODE_INPUT); 882 gpio_set_pull_mode((gpio_num_t)PIN_JOY2_BTN, GPIO_PULLUP_ONLY); 883 gpio_set_direction((gpio_num_t)PIN_KEY_USER1, GPIO_MODE_INPUT); 884 gpio_set_pull_mode((gpio_num_t)PIN_KEY_USER1, GPIO_PULLUP_ONLY); 885 gpio_set_direction((gpio_num_t)PIN_KEY_USER2, GPIO_MODE_INPUT); 886 gpio_set_pull_mode((gpio_num_t)PIN_KEY_USER2, GPIO_PULLUP_ONLY); 887 888 //adc1_config_channel_atten((adc1_channel_t)PIN_JOY2_A1X,ADC_ATTEN_DB_11); 889 //adc1_config_channel_atten((adc1_channel_t)PIN_JOY2_A2Y,ADC_ATTEN_DB_11); 890 adc2_config_channel_atten((adc2_channel_t)PIN_JOY2_A1X,ADC_ATTEN_DB_11); 891 adc2_config_channel_atten((adc2_channel_t)PIN_JOY2_A2Y,ADC_ATTEN_DB_11); 892 xRef=0; yRef=0; 893 for (int i=0; i<10; i++) { 894 int val; 895 adc2_get_raw((adc2_channel_t)PIN_JOY2_A1X, ADC_WIDTH_BIT_12, &val); 896 //val = adc1_get_raw((adc1_channel_t)PIN_JOY2_A1X); 897 xRef += val; 898 adc2_get_raw((adc2_channel_t)PIN_JOY2_A2Y,ADC_WIDTH_BIT_12, &val); 899 //val = adc1_get_raw((adc1_channel_t)PIN_JOY2_A2Y); 900 yRef += val; 901 vTaskDelay(20 / portTICK_PERIOD_MS); 902 } 903 xRef /= 10; 904 yRef /= 10; 905 906 printf("refs: %d %d\n",xRef,yRef); 907 } 908 909 910 911 static bool vkbKeepOn = false; 912 static bool vkbActive = false; 913 static bool vkeyRefresh=false; 914 static bool exitVkbd = false; 915 static uint8_t keyPressCount=0; 916 917 918 bool virtualkeyboardIsActive(void) { 919 return (vkbActive); 920 } 921 922 void toggleVirtualkeyboard(bool keepOn) { 923 if (keepOn) { 924 tft.drawSpriteNoDma(0,0,(uint16_t*)logo); 925 //prev_zt = 0; 926 vkbKeepOn = true; 927 vkbActive = true; 928 exitVkbd = false; 929 } 930 else { 931 vkbKeepOn = false; 932 if ( (vkbActive) /*|| (exitVkbd)*/ ) { 933 tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) ); 934 #ifdef DMA_FULLgpio_get_level 935 tft.begin(); 936 tft.refresh(); 937 #endif 938 //prev_zt = 0; 939 vkbActive = false; 940 exitVkbd = false; 941 } 942 else { 943 #ifdef DMA_FULL 944 tft.stop(); 945 tft.begin(); 946 tft.start(); 947 #endif 948 tft.drawSpriteNoDma(0,0,(uint16_t*)logo); 949 //prev_zt = 0; 950 vkbActive = true; 951 exitVkbd = false; 952 } 953 } 954 } 955 956 957 void handleVirtualkeyboard() { 958 int rx=0,ry=0,rw=0,rh=0; 959 960 if (keyPressCount == 0) { 961 keypadval = 0; 962 } else { 963 keyPressCount--; 964 } 965 966 if ( (!virtualkeyboardIsActive()) && (tft.isTouching()) && (!keyPressCount) ) { 967 toggleVirtualkeyboard(false); 968 return; 969 } 970 971 if ( ( (vkbKeepOn) || (virtualkeyboardIsActive()) ) ) { 972 char c = captureTouchZone(keysw, keys, &rx,&ry,&rw,&rh); 973 if (c) { 974 tft.drawRectNoDma( rx,ry,rw,rh, KEYBOARD_HIT_COLOR ); 975 if ( (c >=1) && (c <= ACTION_MAXKBDVAL) ) { 976 keypadval = c; 977 keyPressCount = 10; 978 vTaskDelay(50 / portTICK_PERIOD_MS); 979 vkeyRefresh = true; 980 exitVkbd = true; 981 } 982 else if (c == ACTION_EXITKBD) { 983 vkeyRefresh = true; 984 exitVkbd = true; 985 } 986 } 987 } 988 989 if (vkeyRefresh) { 990 vkeyRefresh = false; 991 tft.drawSpriteNoDma(0,0,(uint16_t*)logo, rx, ry, rw, rh); 992 } 993 994 if ( (exitVkbd) && (vkbActive) ) { 995 if (!vkbKeepOn) { 996 toggleVirtualkeyboard(false); 997 } 998 else { 999 toggleVirtualkeyboard(true); 1000 } 1001 } 1002 } 1003 1004 int emu_setKeymap(int index) { 1005 if (index) { 1006 //logo = ; 1007 //keysw = ; 1008 } 1009 else { 1010 //logo = ; 1011 //keysw = ; 1012 } 1013 return 0; 1014 } 1015 1016 1017 1018 static unsigned short palette16[PALETTE_SIZE]; 1019 static int fskip=0; 1020 1021 void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index) 1022 { 1023 if (index<PALETTE_SIZE) { 1024 //printf("%d: %d %d %d\n", index, r,g,b); 1025 palette16[index] = RGBVAL16(r,g,b); 1026 } 1027 } 1028 1029 void emu_DrawVsync(void) 1030 { 1031 //printf("sync %d\n",skip); 1032 fskip += 1; 1033 fskip &= VID_FRAME_SKIP; 1034 } 1035 1036 void emu_DrawLine(unsigned char * VBuf, int width, int height, int line) 1037 { 1038 if (fskip==0) { 1039 tft.writeLine(width,height,line, VBuf, palette16); 1040 } 1041 } 1042 1043 void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride) 1044 { 1045 if (fskip==0) { 1046 tft.writeScreen(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16); 1047 } 1048 } 1049 1050 int emu_FrameSkip(void) 1051 { 1052 return fskip; 1053 } 1054 1055 void * emu_LineBuffer(int line) 1056 { 1057 return (void*)tft.getLineBuffer(line); 1058 } 1059 1060 #ifdef HAS_SND 1061 #include "AudioPlaySystem.h" 1062 extern AudioPlaySystem audio; 1063 1064 void emu_sndInit() { 1065 } 1066 1067 void emu_sndPlaySound(int chan, int volume, int freq) 1068 { 1069 if (chan < 6) { 1070 audio.sound(chan, freq, volume); 1071 } 1072 } 1073 1074 void emu_sndPlayBuzz(int size, int val) { 1075 //mymixer.buzz(size,val); 1076 } 1077 #endif 1078