kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
1085 wiersze
28 KiB
C++
1085 wiersze
28 KiB
C++
![]() |
#define KEYMAP_PRESENT 1
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stddef.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
extern "C" {
|
||
|
#include "emuapi.h"
|
||
|
#include "iopins.h"
|
||
|
}
|
||
|
|
||
|
#include "ili9341_t3dma.h"
|
||
|
//#include "logo.h"
|
||
|
#include "bmpjoy.h"
|
||
|
#include "bmpvbar.h"
|
||
|
|
||
|
#include "esp_event.h"
|
||
|
#include "esp_vfs_fat.h"
|
||
|
#include "driver/sdspi_host.h"
|
||
|
#include <dirent.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <driver/adc.h>
|
||
|
|
||
|
#ifdef HAS_I2CKBD
|
||
|
#ifdef USE_WIRE
|
||
|
#include "Wire.h"
|
||
|
#else
|
||
|
#include <driver/i2c.h>
|
||
|
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
|
||
|
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
|
||
|
#define ACK_VAL 0x0 /*!< I2C ack value */
|
||
|
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||
|
#endif
|
||
|
|
||
|
#define I2C_FREQ_HZ 400000 /*!< I2C master clock frequency */
|
||
|
static bool i2cKeyboardPresent = false;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
extern ILI9341_t3DMA tft;
|
||
|
|
||
|
static char romspath[64];
|
||
|
static int calMinX=-1,calMinY=-1,calMaxX=-1,calMaxY=-1;
|
||
|
static sdmmc_card_t* card;
|
||
|
const uint16_t deflogo[] = {
|
||
|
0x0000,0x0000
|
||
|
};
|
||
|
static const uint16_t * logo = deflogo;
|
||
|
|
||
|
#define CALIBRATION_FILE "/sdcard/cal.cfg"
|
||
|
|
||
|
#define MAX_FILENAME_SIZE 28
|
||
|
#define MAX_MENULINES (MKEY_L9)
|
||
|
#define TEXT_HEIGHT 16
|
||
|
#define TEXT_WIDTH 8
|
||
|
#define MENU_FILE_XOFFSET (6*TEXT_WIDTH)
|
||
|
#define MENU_FILE_YOFFSET (2*TEXT_HEIGHT)
|
||
|
#define MENU_FILE_W (MAX_FILENAME_SIZE*TEXT_WIDTH)
|
||
|
#define MENU_FILE_H (MAX_MENULINES*TEXT_HEIGHT)
|
||
|
#define MENU_FILE_FGCOLOR RGBVAL16(0xff,0xff,0xff)
|
||
|
#define MENU_FILE_BGCOLOR RGBVAL16(0x00,0x00,0x20)
|
||
|
#define MENU_JOYS_YOFFSET (12*TEXT_HEIGHT)
|
||
|
#define MENU_VBAR_XOFFSET (0*TEXT_WIDTH)
|
||
|
#define MENU_VBAR_YOFFSET (MENU_FILE_YOFFSET)
|
||
|
|
||
|
|
||
|
#define MKEY_L1 1
|
||
|
#define MKEY_L2 2
|
||
|
#define MKEY_L3 3
|
||
|
#define MKEY_L4 4
|
||
|
#define MKEY_L5 5
|
||
|
#define MKEY_L6 6
|
||
|
#define MKEY_L7 7
|
||
|
#define MKEY_L8 8
|
||
|
#define MKEY_L9 9
|
||
|
#define MKEY_UP 20
|
||
|
#define MKEY_DOWN 21
|
||
|
#define MKEY_JOY 22
|
||
|
|
||
|
|
||
|
const unsigned short menutouchareas[] = {
|
||
|
TAREA_XY,MENU_FILE_XOFFSET,MENU_FILE_YOFFSET,
|
||
|
TAREA_WH,MENU_FILE_W, TEXT_HEIGHT,
|
||
|
TAREA_NEW_COL,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,TEXT_HEIGHT,
|
||
|
|
||
|
TAREA_XY,MENU_VBAR_XOFFSET,MENU_VBAR_YOFFSET,
|
||
|
TAREA_WH,32,48,
|
||
|
TAREA_NEW_COL, 72,72,8,40,
|
||
|
|
||
|
TAREA_END};
|
||
|
|
||
|
const unsigned short menutouchactions[] = {
|
||
|
MKEY_L1,MKEY_L2,MKEY_L3,MKEY_L4,MKEY_L5,MKEY_L6,MKEY_L7,MKEY_L8,MKEY_L9,
|
||
|
MKEY_UP,MKEY_DOWN,ACTION_NONE,MKEY_JOY};
|
||
|
|
||
|
|
||
|
static bool menuOn=true;
|
||
|
static bool callibrationOn=false;
|
||
|
static int callibrationStep=0;
|
||
|
static bool menuRedraw=true;
|
||
|
static int nbFiles=0;
|
||
|
static int curFile=0;
|
||
|
static int topFile=0;
|
||
|
static char selection[MAX_FILENAME_SIZE+1]="";
|
||
|
static uint8_t prev_zt=0;
|
||
|
|
||
|
static int readNbFiles(void) {
|
||
|
int totalFiles = 0;
|
||
|
|
||
|
DIR* dir = opendir(romspath);
|
||
|
while (true) {
|
||
|
struct dirent* de = readdir(dir);
|
||
|
if (!de) {
|
||
|
// no more files
|
||
|
break;
|
||
|
}
|
||
|
if (de->d_type == DT_REG) {
|
||
|
totalFiles++;
|
||
|
}
|
||
|
else if (de->d_type == DT_DIR) {
|
||
|
if ( (strcmp(de->d_name,".")) && (strcmp(de->d_name,"..")) ) {
|
||
|
totalFiles++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
closedir(dir);
|
||
|
printf("Directory read: %d files",totalFiles);
|
||
|
return totalFiles;
|
||
|
}
|
||
|
|
||
|
static char captureTouchZone(const unsigned short * areas, const unsigned short * actions, int *rx, int *ry, int *rw, int * rh) {
|
||
|
uint16_t xt=0;
|
||
|
uint16_t yt=0;
|
||
|
uint16_t zt=0;
|
||
|
bool hDir=true;
|
||
|
|
||
|
if (tft.isTouching())
|
||
|
{
|
||
|
if (prev_zt == 0) {
|
||
|
prev_zt =1;
|
||
|
tft.readCal(&xt,&yt,&zt);
|
||
|
if (zt<1000) {
|
||
|
prev_zt=0;
|
||
|
return ACTION_NONE;
|
||
|
}
|
||
|
int i=0;
|
||
|
int k=0;
|
||
|
int y2=0, y1=0;
|
||
|
int x2=0, x1=0;
|
||
|
int x=KEYBOARD_X,y=KEYBOARD_Y;
|
||
|
int w=TAREA_W_DEF,h=TAREA_H_DEF;
|
||
|
uint8_t s;
|
||
|
while ( (s=areas[i++]) != TAREA_END ) {
|
||
|
if (s == TAREA_XY) {
|
||
|
x = areas[i++];
|
||
|
y = areas[i++];
|
||
|
x2 = x;
|
||
|
y2 = y;
|
||
|
}
|
||
|
else if (s == TAREA_WH) {
|
||
|
w = areas[i++];
|
||
|
h = areas[i++];
|
||
|
}
|
||
|
else if (s == TAREA_NEW_ROW) {
|
||
|
hDir = true;
|
||
|
y1 = y2;
|
||
|
y2 = y1 + h;
|
||
|
x2 = x;
|
||
|
}
|
||
|
else if (s == TAREA_NEW_COL) {
|
||
|
hDir = false;
|
||
|
x1 = x2;
|
||
|
x2 = x1 + w;
|
||
|
y2 = y;
|
||
|
}
|
||
|
else {
|
||
|
if (hDir) {
|
||
|
x1 = x2;
|
||
|
x2 = x1+s;
|
||
|
} else {
|
||
|
y1 = y2;
|
||
|
y2 = y1+s;
|
||
|
}
|
||
|
if ( (yt >= y1) && (yt < y2) && (xt >= x1) && (xt < x2) ) {
|
||
|
*rx = x1;
|
||
|
*ry = y1;
|
||
|
*rw = x2-x1;
|
||
|
*rh = y2-y1;
|
||
|
return (actions[k]);
|
||
|
}
|
||
|
k++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
prev_zt =1;
|
||
|
} else {
|
||
|
prev_zt=0;
|
||
|
}
|
||
|
|
||
|
return ACTION_NONE;
|
||
|
}
|
||
|
|
||
|
void toggleMenu(bool on) {
|
||
|
if (on) {
|
||
|
callibrationOn=false;
|
||
|
menuOn=true;
|
||
|
menuRedraw=true;
|
||
|
tft.fillScreenNoDma(RGBVAL16(0x00,0x00,0x00));
|
||
|
tft.drawTextNoDma(0,0, TITLE, RGBVAL16(0x00,0xff,0xff), RGBVAL16(0x00,0x00,0xff), true);
|
||
|
tft.drawSpriteNoDma(MENU_VBAR_XOFFSET,MENU_VBAR_YOFFSET,(uint16_t*)bmpvbar);
|
||
|
} else {
|
||
|
menuOn = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
static void callibrationInit(void)
|
||
|
{
|
||
|
callibrationOn=true;
|
||
|
menuOn=false;
|
||
|
callibrationStep = 0;
|
||
|
calMinX=0,calMinY=0,calMaxX=0,calMaxY=0;
|
||
|
tft.fillScreenNoDma(RGBVAL16(0xff,0xff,0xff));
|
||
|
tft.drawTextNoDma(0,100, " Callibration process:", RGBVAL16(0x00,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true);
|
||
|
tft.drawTextNoDma(0,116, " Hit the red cross at each corner", RGBVAL16(0x00,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true);
|
||
|
tft.drawTextNoDma(0,0, "+", RGBVAL16(0xff,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true);
|
||
|
prev_zt = 1;
|
||
|
}
|
||
|
|
||
|
static void readCallibration(void)
|
||
|
{
|
||
|
FILE * file = fopen(CALIBRATION_FILE, "rb");
|
||
|
if (file) {
|
||
|
fscanf(file,"%d %d %d %d\n",&calMinX,&calMinY,&calMaxX,&calMaxY);
|
||
|
fclose(file);
|
||
|
printf("Current callibration params: %d %d %d %d\n",calMinX,calMinY,calMaxX,calMaxY);
|
||
|
}
|
||
|
else {
|
||
|
printf("Callibration read error\n");
|
||
|
}
|
||
|
tft.callibrateTouch(calMinX,calMinY,calMaxX,calMaxY);
|
||
|
}
|
||
|
|
||
|
static void writeCallibration(void)
|
||
|
{
|
||
|
tft.callibrateTouch(calMinX,calMinY,calMaxX,calMaxY);
|
||
|
FILE * file = fopen(CALIBRATION_FILE, "wb");
|
||
|
if (file) {
|
||
|
fprintf(file,"%d %d %d %d\n",calMinX,calMinY,calMaxX,calMaxY);
|
||
|
fclose(file);
|
||
|
}
|
||
|
else {
|
||
|
printf("Callibration write error\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
bool callibrationActive(void)
|
||
|
{
|
||
|
return (callibrationOn);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
int handleCallibration(uint16_t bClick) {
|
||
|
uint16_t xt=0;
|
||
|
uint16_t yt=0;
|
||
|
uint16_t zt=0;
|
||
|
if (tft.isTouching()) {
|
||
|
if (prev_zt == 0) {
|
||
|
prev_zt = 1;
|
||
|
tft.readRaw(&xt,&yt,&zt);
|
||
|
if (zt < 1000) {
|
||
|
return 0;
|
||
|
}
|
||
|
switch (callibrationStep)
|
||
|
{
|
||
|
case 0:
|
||
|
callibrationStep++;
|
||
|
tft.drawTextNoDma(0,0, " ", RGBVAL16(0xff,0xff,0xff), RGBVAL16(0xff,0xff,0xff), true);
|
||
|
tft.drawTextNoDma(ILI9341_TFTREALWIDTH-8,0, "+", RGBVAL16(0xff,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true);
|
||
|
calMinX += xt;
|
||
|
calMinY += yt;
|
||
|
break;
|
||
|
case 1:
|
||
|
callibrationStep++;
|
||
|
tft.drawTextNoDma(ILI9341_TFTREALWIDTH-8,0, " ", RGBVAL16(0xff,0xff,0xff), RGBVAL16(0xff,0xff,0xff), true);
|
||
|
tft.drawTextNoDma(ILI9341_TFTREALWIDTH-8,ILI9341_TFTREALHEIGHT-16, "+", RGBVAL16(0xff,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true);
|
||
|
calMaxX += xt;
|
||
|
calMinY += yt;
|
||
|
break;
|
||
|
case 2:
|
||
|
callibrationStep++;
|
||
|
tft.drawTextNoDma(ILI9341_TFTREALWIDTH-8,ILI9341_TFTREALHEIGHT-16, " ", RGBVAL16(0xff,0xff,0xff), RGBVAL16(0xff,0xff,0xff), true);
|
||
|
tft.drawTextNoDma(0,ILI9341_TFTREALHEIGHT-16, "+", RGBVAL16(0xff,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true);
|
||
|
calMaxX += xt;
|
||
|
calMaxY += yt;
|
||
|
break;
|
||
|
case 3:
|
||
|
tft.fillScreenNoDma(RGBVAL16(0xff,0xff,0xff));
|
||
|
tft.drawTextNoDma(0,100, " Callibration done!", RGBVAL16(0x00,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true);
|
||
|
tft.drawTextNoDma(0,116, " (Click center to exit)", RGBVAL16(0xff,0x00,0x00), RGBVAL16(0xff,0xff,0xff), true);
|
||
|
callibrationStep++;
|
||
|
calMinX += xt;
|
||
|
calMaxY += yt;
|
||
|
break;
|
||
|
case 4:
|
||
|
if ( (xt > (ILI9341_TFTREALWIDTH/4)) && (xt < (ILI9341_TFTREALWIDTH*3)/4)
|
||
|
&& (yt > (ILI9341_TFTREALHEIGHT/4)) && (yt < (ILI9341_TFTREALHEIGHT*3)/4) ) {
|
||
|
calMinX /= 2;
|
||
|
calMinY /= 2;
|
||
|
calMaxX /= 2;
|
||
|
calMaxY /= 2;
|
||
|
writeCallibration();
|
||
|
toggleMenu(true);
|
||
|
}
|
||
|
else {
|
||
|
callibrationInit();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
prev_zt = 0;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
bool menuActive(void)
|
||
|
{
|
||
|
return (menuOn);
|
||
|
}
|
||
|
|
||
|
int handleMenu(uint16_t bClick)
|
||
|
{
|
||
|
int action = ACTION_NONE;
|
||
|
|
||
|
char newpath[80];
|
||
|
strcpy(newpath, romspath);
|
||
|
strcat(newpath, "/");
|
||
|
strcat(newpath, selection);
|
||
|
|
||
|
struct stat st;
|
||
|
bool newPathIsDir = false;
|
||
|
if(stat(newpath,&st) == 0)
|
||
|
if((st.st_mode & S_IFDIR) != 0)
|
||
|
newPathIsDir = true;
|
||
|
|
||
|
int rx=0,ry=0,rw=0,rh=0;
|
||
|
char c = captureTouchZone(menutouchareas, menutouchactions, &rx,&ry,&rw,&rh);
|
||
|
if ( ( (bClick & MASK_JOY2_BTN) || (bClick & MASK_KEY_USER1) ) && (newPathIsDir) ) {
|
||
|
menuRedraw=true;
|
||
|
strcpy(romspath,newpath);
|
||
|
curFile = 0;
|
||
|
nbFiles = readNbFiles();
|
||
|
}
|
||
|
else if ( (c >= MKEY_L1) && (c <= MKEY_L9) ) {
|
||
|
if ( (topFile+(int)c-1) <= (nbFiles-1) )
|
||
|
{
|
||
|
curFile = topFile + (int)c -1;
|
||
|
menuRedraw=true;
|
||
|
//tft.drawRectNoDma( rx,ry,rw,rh, KEYBOARD_HIT_COLOR );
|
||
|
}
|
||
|
}
|
||
|
else if ( (bClick & MASK_JOY2_BTN) ) {
|
||
|
menuRedraw=true;
|
||
|
action = ACTION_RUNTFT;
|
||
|
}
|
||
|
else if (bClick & MASK_JOY2_UP) {
|
||
|
if (curFile!=0) {
|
||
|
menuRedraw=true;
|
||
|
curFile--;
|
||
|
}
|
||
|
}
|
||
|
else if ( (bClick & MASK_JOY2_RIGHT) || (c == MKEY_UP) ) {
|
||
|
if ((curFile-9)>=0) {
|
||
|
menuRedraw=true;
|
||
|
curFile -= 9;
|
||
|
} else if (curFile!=0) {
|
||
|
menuRedraw=true;
|
||
|
curFile--;
|
||
|
}
|
||
|
}
|
||
|
else if (bClick & MASK_JOY2_DOWN) {
|
||
|
if ((curFile<(nbFiles-1)) && (nbFiles)) {
|
||
|
curFile++;
|
||
|
menuRedraw=true;
|
||
|
}
|
||
|
}
|
||
|
else if ( (bClick & MASK_JOY2_LEFT) || (c == MKEY_DOWN) ) {
|
||
|
if ((curFile<(nbFiles-9)) && (nbFiles)) {
|
||
|
curFile += 9;
|
||
|
menuRedraw=true;
|
||
|
}
|
||
|
else if ((curFile<(nbFiles-1)) && (nbFiles)) {
|
||
|
curFile++;
|
||
|
menuRedraw=true;
|
||
|
}
|
||
|
}
|
||
|
else if ( (bClick & MASK_KEY_USER1) || (c == MKEY_JOY) ) {
|
||
|
emu_SwapJoysticks(0);
|
||
|
menuRedraw=true;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (menuRedraw && nbFiles) {
|
||
|
|
||
|
int fileIndex = 0;
|
||
|
DIR* dir = opendir(romspath);
|
||
|
tft.drawRectNoDma(MENU_FILE_XOFFSET,MENU_FILE_YOFFSET, MENU_FILE_W, MENU_FILE_H, MENU_FILE_BGCOLOR);
|
||
|
// if (curFile <= (MAX_MENULINES/2-1)) topFile=0;
|
||
|
// else topFile=curFile-(MAX_MENULINES/2);
|
||
|
if (curFile <= (MAX_MENULINES-1)) topFile=0;
|
||
|
else topFile=curFile-(MAX_MENULINES/2);
|
||
|
|
||
|
int i=0;
|
||
|
while (i<MAX_MENULINES) {
|
||
|
struct dirent* de = readdir(dir);
|
||
|
if (!de) {
|
||
|
break;
|
||
|
}
|
||
|
if ( (de->d_type == DT_REG) || ((de->d_type == DT_DIR) && (strcmp(de->d_name,".")) && (strcmp(de->d_name,"..")) ) ) {
|
||
|
if (fileIndex >= topFile) {
|
||
|
if ((i+topFile) < nbFiles ) {
|
||
|
if ((i+topFile)==curFile) {
|
||
|
tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, de->d_name, RGBVAL16(0xff,0xff,0x00), RGBVAL16(0xff,0x00,0x00), true);
|
||
|
strcpy(selection,de->d_name);
|
||
|
}
|
||
|
else {
|
||
|
tft.drawTextNoDma(MENU_FILE_XOFFSET,i*TEXT_HEIGHT+MENU_FILE_YOFFSET, de->d_name, MENU_FILE_FGCOLOR, MENU_FILE_BGCOLOR, true);
|
||
|
}
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
fileIndex++;
|
||
|
}
|
||
|
}
|
||
|
closedir(dir);
|
||
|
|
||
|
tft.drawSpriteNoDma(0,MENU_JOYS_YOFFSET,(uint16_t*)bmpjoy);
|
||
|
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);
|
||
|
|
||
|
menuRedraw=false;
|
||
|
}
|
||
|
|
||
|
|
||
|
return (action);
|
||
|
}
|
||
|
|
||
|
char * menuSelection(void)
|
||
|
{
|
||
|
return (selection);
|
||
|
}
|
||
|
|
||
|
#ifdef HAS_I2CKBD
|
||
|
#ifdef USE_WIRE
|
||
|
#else
|
||
|
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)
|
||
|
{
|
||
|
if (size == 0) {
|
||
|
return ESP_OK;
|
||
|
}
|
||
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||
|
i2c_master_start(cmd);
|
||
|
i2c_master_write_byte(cmd, ( i2c_addr << 1 ) | I2C_MASTER_READ, ACK_CHECK_EN);
|
||
|
if (size > 1) {
|
||
|
i2c_master_read(cmd, data_rd, size - 1, (i2c_ack_type_t)ACK_VAL);
|
||
|
}
|
||
|
i2c_master_read_byte(cmd, data_rd + size - 1, (i2c_ack_type_t)NACK_VAL);
|
||
|
i2c_master_stop(cmd);
|
||
|
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
|
||
|
i2c_cmd_link_delete(cmd);
|
||
|
return ret;
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
|
||
|
void emu_init(void)
|
||
|
{
|
||
|
|
||
|
esp_err_t ret = 0;
|
||
|
|
||
|
printf("mounting sd...\n");
|
||
|
|
||
|
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
|
||
|
host.max_freq_khz = 10000;
|
||
|
//host.slot = HSPI_HOST;
|
||
|
|
||
|
sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT();
|
||
|
slot_config.gpio_miso = SPIN_NUM_MISO;
|
||
|
slot_config.gpio_mosi = SPIN_NUM_MOSI;
|
||
|
slot_config.gpio_sck = SPIN_NUM_CLK;
|
||
|
slot_config.gpio_cs = SPIN_NUM_CS;
|
||
|
slot_config.dma_channel = 2;
|
||
|
|
||
|
|
||
|
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||
|
.format_if_mount_failed = false,
|
||
|
.max_files = 5,
|
||
|
.allocation_unit_size = 16 * 1024
|
||
|
};
|
||
|
|
||
|
|
||
|
while((ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card)) != ESP_OK) {
|
||
|
printf("retrying\n");
|
||
|
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||
|
}
|
||
|
|
||
|
strcpy(romspath,"/sdcard/");
|
||
|
strcat(romspath,ROMSDIR);
|
||
|
printf("dir is : %s\n",romspath);
|
||
|
|
||
|
nbFiles = readNbFiles();
|
||
|
printf("SD initialized, files found: %d\n",nbFiles);
|
||
|
|
||
|
|
||
|
tft.touchBegin();
|
||
|
//uint16_t xt=0;
|
||
|
//uint16_t yt=0;
|
||
|
//uint16_t zt=0;
|
||
|
//tft.readRo(&xt,&yt,&zt);
|
||
|
|
||
|
|
||
|
emu_InitJoysticks();
|
||
|
readCallibration();
|
||
|
|
||
|
if ((tft.isTouching()) || (emu_ReadKeys() & MASK_JOY2_BTN) ) {
|
||
|
callibrationInit();
|
||
|
} else {
|
||
|
toggleMenu(true);
|
||
|
}
|
||
|
|
||
|
#ifdef HAS_I2CKBD
|
||
|
uint8_t msg[7]={0,0,0,0,0,0,0};
|
||
|
|
||
|
#ifdef USE_WIRE
|
||
|
Wire.begin(I2C_SDA_IO, I2C_SCL_IO);
|
||
|
Wire.requestFrom(8, 7, I2C_FREQ_HZ); // request 5 bytes from slave device #8
|
||
|
int i = 0;
|
||
|
int hitindex=-1;
|
||
|
while (Wire.available() && (i<7) ) { // slave may send less than requested
|
||
|
uint8_t b = Wire.read(); // receive a byte
|
||
|
if (b != 0xff) hitindex=i;
|
||
|
msg[i++] = b;
|
||
|
}
|
||
|
#else
|
||
|
int i2c_master_port = I2C_NUM_1;
|
||
|
i2c_config_t conf;
|
||
|
conf.mode = I2C_MODE_MASTER;
|
||
|
conf.sda_io_num = I2C_SDA_IO;
|
||
|
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
|
||
|
conf.scl_io_num = I2C_SCL_IO;
|
||
|
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
|
||
|
conf.master.clk_speed = I2C_FREQ_HZ;
|
||
|
i2c_param_config((i2c_port_t)i2c_master_port, &conf);
|
||
|
if (i2c_driver_install((i2c_port_t)i2c_master_port, conf.mode,0, 0, 0) != ESP_OK)
|
||
|
printf("I2C Failed initialized\n");
|
||
|
|
||
|
if (i2c_master_read_slave_reg( I2C_NUM_1, 8, &msg[0], 7 ) != ESP_OK)
|
||
|
printf("I2C Failed \n");
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
if ( (msg[0] == 0xff) && (msg[1] == 0xff) &&
|
||
|
(msg[2] == 0xff) && (msg[3] == 0xff) &&
|
||
|
(msg[4] == 0xff) && (msg[5] == 0xff) && (msg[6] == 0xff)) {
|
||
|
i2cKeyboardPresent = true;
|
||
|
printf("i2C keyboard found\n");
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
void emu_printf(char * text)
|
||
|
{
|
||
|
printf("%s\n",text);
|
||
|
}
|
||
|
|
||
|
|
||
|
void emu_printi(int val)
|
||
|
{
|
||
|
printf("%d\n",val);
|
||
|
}
|
||
|
|
||
|
void * emu_Malloc(int size)
|
||
|
{
|
||
|
void * retval = malloc(size);
|
||
|
if (!retval) {
|
||
|
printf("failled to allocate %d\n",size);
|
||
|
}
|
||
|
else {
|
||
|
printf("could allocate %d\n",size);
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
void emu_Free(void * pt)
|
||
|
{
|
||
|
free(pt);
|
||
|
}
|
||
|
|
||
|
|
||
|
static FILE * lastfileOpened;
|
||
|
|
||
|
|
||
|
int emu_FileOpen(char * filename)
|
||
|
{
|
||
|
int retval = 0;
|
||
|
|
||
|
char filepath[80];
|
||
|
strcpy(filepath, romspath);
|
||
|
strcat(filepath, "/");
|
||
|
strcat(filepath, filename);
|
||
|
//printf("FileOpen...%s\n",filepath);
|
||
|
|
||
|
lastfileOpened = fopen(filepath, "rb");
|
||
|
if (lastfileOpened) {
|
||
|
retval = 1;
|
||
|
}
|
||
|
else {
|
||
|
//printf("FileOpen failed\n");
|
||
|
}
|
||
|
return (retval);
|
||
|
}
|
||
|
|
||
|
int emu_FileRead(char * buf, int size)
|
||
|
{
|
||
|
int retval = fread(buf, 1, size, lastfileOpened);
|
||
|
if (retval != size) {
|
||
|
printf("FileRead failed\n");
|
||
|
}
|
||
|
return (retval);
|
||
|
}
|
||
|
|
||
|
unsigned char emu_FileGetc(void) {
|
||
|
unsigned char c;
|
||
|
int retval = fread(&c, 1, 1, lastfileOpened);
|
||
|
if (retval != 1) {
|
||
|
printf("emu_FileGetc failed\n");
|
||
|
}
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
|
||
|
void emu_FileClose(void)
|
||
|
{
|
||
|
fclose(lastfileOpened);
|
||
|
}
|
||
|
|
||
|
int emu_FileSize(char * filename)
|
||
|
{
|
||
|
int filesize=0;
|
||
|
char filepath[80];
|
||
|
strcpy(filepath, romspath);
|
||
|
strcat(filepath, "/");
|
||
|
strcat(filepath, filename);
|
||
|
printf("FileSize...%s\n",filepath);
|
||
|
|
||
|
FILE * file = fopen(filepath, "rb");
|
||
|
if (file) {
|
||
|
fseek(file, 0L, SEEK_END);
|
||
|
filesize = ftell(file);
|
||
|
//fseek(file, 0L, SEEK_SET);
|
||
|
printf("filesize is...%d\n",filesize);
|
||
|
fclose(file);
|
||
|
}
|
||
|
|
||
|
return(filesize);
|
||
|
}
|
||
|
|
||
|
int emu_FileSeek(int seek)
|
||
|
{
|
||
|
fseek(lastfileOpened, seek, SEEK_SET);
|
||
|
return (seek);
|
||
|
}
|
||
|
|
||
|
int emu_LoadFile(char * filename, char * buf, int size)
|
||
|
{
|
||
|
int filesize = 0;
|
||
|
|
||
|
char filepath[80];
|
||
|
strcpy(filepath, romspath);
|
||
|
strcat(filepath, "/");
|
||
|
strcat(filepath, filename);
|
||
|
printf("LoadFile...%s\n",filepath);
|
||
|
|
||
|
filesize = emu_FileSize(filename);
|
||
|
FILE * file = fopen(filepath, "rb");
|
||
|
if (file) {
|
||
|
if (size >= filesize)
|
||
|
{
|
||
|
if (fread(buf, 1, filesize, file) != filesize) {
|
||
|
printf("File read failed\n");
|
||
|
}
|
||
|
}
|
||
|
fclose(file);
|
||
|
}
|
||
|
|
||
|
return(filesize);
|
||
|
}
|
||
|
|
||
|
int emu_LoadFileSeek(char * filename, char * buf, int size, int seek)
|
||
|
{
|
||
|
int filesize = 0;
|
||
|
|
||
|
char filepath[80];
|
||
|
strcpy(filepath, romspath);
|
||
|
strcat(filepath, "/");
|
||
|
strcat(filepath, filename);
|
||
|
printf("LoadFileSeek...%d bytes at %d from %s\n",size,seek,filepath);
|
||
|
|
||
|
FILE * file = fopen(filepath, "rb");
|
||
|
if (file) {
|
||
|
fseek(file, seek, SEEK_SET);
|
||
|
if (fread(buf, size, 1, file) != size) {
|
||
|
printf("File read failed\n");
|
||
|
}
|
||
|
fclose(file);
|
||
|
}
|
||
|
|
||
|
return(filesize);
|
||
|
}
|
||
|
|
||
|
static int keypadval=0;
|
||
|
static bool joySwapped = false;
|
||
|
static uint16_t bLastState;
|
||
|
static int xRef;
|
||
|
static int yRef;
|
||
|
|
||
|
int emu_ReadAnalogJoyX(int min, int max)
|
||
|
{
|
||
|
int val; //adc1_get_raw((adc1_channel_t)PIN_JOY2_A1X);
|
||
|
adc2_get_raw((adc2_channel_t)PIN_JOY2_A1X, ADC_WIDTH_BIT_12,&val);
|
||
|
//printf("refX:%d X:%d\n",xRef,val);
|
||
|
val = val-xRef;
|
||
|
//val = ((val*140)/100);
|
||
|
if ( (val > -xRef/4) && (val < xRef/4) ) val = 0;
|
||
|
#if INVX
|
||
|
val = xRef-val;
|
||
|
#else
|
||
|
val = val+xRef;
|
||
|
#endif
|
||
|
|
||
|
return (val*(max-min))/(xRef*2);
|
||
|
}
|
||
|
|
||
|
int emu_ReadAnalogJoyY(int min, int max)
|
||
|
{
|
||
|
int val; //= adc1_get_raw((adc1_channel_t)PIN_JOY2_A2Y);
|
||
|
adc2_get_raw((adc2_channel_t)PIN_JOY2_A2Y, ADC_WIDTH_BIT_12,&val);
|
||
|
//printf("refY:%d Y:%d\n",yRef,val);
|
||
|
val = val-yRef;
|
||
|
//val = ((val*120)/100);
|
||
|
if ( (val > -yRef/4) && (val < yRef/4) ) val = 0;
|
||
|
#if INVY
|
||
|
val = yRef-val;
|
||
|
#else
|
||
|
val = val+yRef;
|
||
|
#endif
|
||
|
return (val*(max-min))/(yRef*2);
|
||
|
}
|
||
|
|
||
|
|
||
|
static uint16_t readAnalogJoystick(void)
|
||
|
{
|
||
|
uint16_t joysval = 0;
|
||
|
|
||
|
int xReading = emu_ReadAnalogJoyX(0,256);
|
||
|
if (xReading > 128) joysval |= MASK_JOY2_LEFT;
|
||
|
else if (xReading < 128) joysval |= MASK_JOY2_RIGHT;
|
||
|
|
||
|
int yReading = emu_ReadAnalogJoyY(0,256);
|
||
|
if (yReading < 128) joysval |= MASK_JOY2_UP;
|
||
|
else if (yReading > 128) joysval |= MASK_JOY2_DOWN;
|
||
|
|
||
|
joysval |= ((gpio_get_level((gpio_num_t)PIN_JOY2_BTN) == 1) ? 0 : MASK_JOY2_BTN);
|
||
|
|
||
|
return (joysval);
|
||
|
}
|
||
|
|
||
|
|
||
|
int emu_SwapJoysticks(int statusOnly) {
|
||
|
if (!statusOnly) {
|
||
|
if (joySwapped) {
|
||
|
joySwapped = false;
|
||
|
}
|
||
|
else {
|
||
|
joySwapped = true;
|
||
|
}
|
||
|
}
|
||
|
return(joySwapped?1:0);
|
||
|
}
|
||
|
|
||
|
int emu_GetPad(void)
|
||
|
{
|
||
|
return(keypadval|((joySwapped?1:0)<<7));
|
||
|
}
|
||
|
|
||
|
int emu_ReadKeys(void)
|
||
|
{
|
||
|
uint16_t retval;
|
||
|
uint16_t j1 = readAnalogJoystick();
|
||
|
|
||
|
uint16_t j2 = 0;
|
||
|
|
||
|
if (joySwapped) {
|
||
|
retval = ((j1 << 8) | j2);
|
||
|
}
|
||
|
else {
|
||
|
retval = ((j2 << 8) | j1);
|
||
|
}
|
||
|
|
||
|
if (gpio_get_level((gpio_num_t)PIN_KEY_USER1) == 0 ) retval |= MASK_KEY_USER1;
|
||
|
if (gpio_get_level((gpio_num_t)PIN_KEY_USER2) == 0 ) retval |= MASK_KEY_USER2;
|
||
|
if (gpio_get_level((gpio_num_t)PIN_KEY_USER3) == 0 ) retval |= MASK_KEY_USER3;
|
||
|
if (gpio_get_level((gpio_num_t)PIN_KEY_USER4) == 0 ) retval |= MASK_KEY_USER4;
|
||
|
|
||
|
//printf("%d\n",retval);
|
||
|
return (retval);
|
||
|
}
|
||
|
|
||
|
unsigned short emu_DebounceLocalKeys(void)
|
||
|
{
|
||
|
uint16_t bCurState = emu_ReadKeys();
|
||
|
uint16_t bClick = bCurState & ~bLastState;
|
||
|
bLastState = bCurState;
|
||
|
|
||
|
return (bClick);
|
||
|
}
|
||
|
|
||
|
|
||
|
int emu_ReadI2CKeyboard(void) {
|
||
|
int retval=0;
|
||
|
#ifdef HAS_I2CKBD
|
||
|
if (i2cKeyboardPresent) {
|
||
|
uint8_t msg[7];
|
||
|
#ifdef USE_WIRE
|
||
|
Wire.requestFrom(8, 7, I2C_FREQ_HZ); // request 5 bytes from slave device #8
|
||
|
int i = 0;
|
||
|
int hitindex=-1;
|
||
|
while (Wire.available() && (i<7) ) { // slave may send less than requested
|
||
|
uint8_t b = Wire.read(); // receive a byte
|
||
|
if (b != 0xff) hitindex=i;
|
||
|
msg[i++] = b;
|
||
|
}
|
||
|
#else
|
||
|
if (i2c_master_read_slave_reg( I2C_NUM_1, 8, &msg[0], 7 ) != ESP_OK)
|
||
|
printf("I2C Failed \n");
|
||
|
int hitindex=-1;
|
||
|
int i = 0;
|
||
|
while (i<7) {
|
||
|
if (msg[i] != 0xff) hitindex=i;
|
||
|
i++;
|
||
|
}
|
||
|
#endif
|
||
|
//printf("I2C 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
|
||
|
// msg[0],msg[1],msg[2],msg[3],msg[4],msg[5],msg[6]);
|
||
|
if ((hitindex >=0 ) && (hitindex <=6 )) {
|
||
|
unsigned short match = ((~msg[hitindex])&0x00FF) | (hitindex<<8);
|
||
|
for (i=0; i<sizeof(i2ckeys); i++) {
|
||
|
if (match == i2ckeys[i]) {
|
||
|
//printf("I2C %d\n",keys[i]);
|
||
|
return (keys[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
return(retval);
|
||
|
}
|
||
|
|
||
|
void emu_InitJoysticks(void) {
|
||
|
gpio_set_direction((gpio_num_t)PIN_JOY2_BTN, GPIO_MODE_INPUT);
|
||
|
gpio_set_pull_mode((gpio_num_t)PIN_JOY2_BTN, GPIO_PULLUP_ONLY);
|
||
|
gpio_set_direction((gpio_num_t)PIN_KEY_USER1, GPIO_MODE_INPUT);
|
||
|
gpio_set_pull_mode((gpio_num_t)PIN_KEY_USER1, GPIO_PULLUP_ONLY);
|
||
|
gpio_set_direction((gpio_num_t)PIN_KEY_USER2, GPIO_MODE_INPUT);
|
||
|
gpio_set_pull_mode((gpio_num_t)PIN_KEY_USER2, GPIO_PULLUP_ONLY);
|
||
|
gpio_set_direction((gpio_num_t)PIN_KEY_USER3, GPIO_MODE_INPUT);
|
||
|
gpio_set_pull_mode((gpio_num_t)PIN_KEY_USER3, GPIO_PULLUP_ONLY);
|
||
|
gpio_set_direction((gpio_num_t)PIN_KEY_USER4, GPIO_MODE_INPUT);
|
||
|
gpio_set_pull_mode((gpio_num_t)PIN_KEY_USER4, GPIO_PULLUP_ONLY);
|
||
|
|
||
|
//adc1_config_channel_atten((adc1_channel_t)PIN_JOY2_A1X,ADC_ATTEN_DB_11);
|
||
|
//adc1_config_channel_atten((adc1_channel_t)PIN_JOY2_A2Y,ADC_ATTEN_DB_11);
|
||
|
adc2_config_channel_atten((adc2_channel_t)PIN_JOY2_A1X,ADC_ATTEN_DB_11);
|
||
|
adc2_config_channel_atten((adc2_channel_t)PIN_JOY2_A2Y,ADC_ATTEN_DB_11);
|
||
|
xRef=0; yRef=0;
|
||
|
for (int i=0; i<10; i++) {
|
||
|
int val;
|
||
|
adc2_get_raw((adc2_channel_t)PIN_JOY2_A1X, ADC_WIDTH_BIT_12, &val);
|
||
|
//val = adc1_get_raw((adc1_channel_t)PIN_JOY2_A1X);
|
||
|
xRef += val;
|
||
|
adc2_get_raw((adc2_channel_t)PIN_JOY2_A2Y,ADC_WIDTH_BIT_12, &val);
|
||
|
//val = adc1_get_raw((adc1_channel_t)PIN_JOY2_A2Y);
|
||
|
yRef += val;
|
||
|
vTaskDelay(20 / portTICK_PERIOD_MS);
|
||
|
}
|
||
|
xRef /= 10;
|
||
|
yRef /= 10;
|
||
|
|
||
|
printf("refs: %d %d\n",xRef,yRef);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
static bool vkbKeepOn = false;
|
||
|
static bool vkbActive = false;
|
||
|
static bool vkeyRefresh=false;
|
||
|
static bool exitVkbd = false;
|
||
|
static uint8_t keyPressCount=0;
|
||
|
|
||
|
|
||
|
bool virtualkeyboardIsActive(void) {
|
||
|
return (vkbActive);
|
||
|
}
|
||
|
|
||
|
void toggleVirtualkeyboard(bool keepOn) {
|
||
|
if (keepOn) {
|
||
|
tft.drawSpriteNoDma(0,0,(uint16_t*)logo);
|
||
|
//prev_zt = 0;
|
||
|
vkbKeepOn = true;
|
||
|
vkbActive = true;
|
||
|
exitVkbd = false;
|
||
|
}
|
||
|
else {
|
||
|
vkbKeepOn = false;
|
||
|
if ( (vkbActive) /*|| (exitVkbd)*/ ) {
|
||
|
tft.fillScreenNoDma( RGBVAL16(0x00,0x00,0x00) );
|
||
|
#ifdef DMA_FULLgpio_get_level
|
||
|
tft.begin();
|
||
|
tft.refresh();
|
||
|
#endif
|
||
|
//prev_zt = 0;
|
||
|
vkbActive = false;
|
||
|
exitVkbd = false;
|
||
|
}
|
||
|
else {
|
||
|
#ifdef DMA_FULL
|
||
|
tft.stop();
|
||
|
tft.begin();
|
||
|
tft.start();
|
||
|
#endif
|
||
|
tft.drawSpriteNoDma(0,0,(uint16_t*)logo);
|
||
|
//prev_zt = 0;
|
||
|
vkbActive = true;
|
||
|
exitVkbd = false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void handleVirtualkeyboard() {
|
||
|
int rx=0,ry=0,rw=0,rh=0;
|
||
|
|
||
|
if (keyPressCount == 0) {
|
||
|
keypadval = 0;
|
||
|
} else {
|
||
|
keyPressCount--;
|
||
|
}
|
||
|
|
||
|
if ( (!virtualkeyboardIsActive()) && (tft.isTouching()) && (!keyPressCount) ) {
|
||
|
toggleVirtualkeyboard(false);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( ( (vkbKeepOn) || (virtualkeyboardIsActive()) ) ) {
|
||
|
char c = captureTouchZone(keysw, keys, &rx,&ry,&rw,&rh);
|
||
|
if (c) {
|
||
|
tft.drawRectNoDma( rx,ry,rw,rh, KEYBOARD_HIT_COLOR );
|
||
|
if ( (c >=1) && (c <= ACTION_MAXKBDVAL) ) {
|
||
|
keypadval = c;
|
||
|
keyPressCount = 10;
|
||
|
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||
|
vkeyRefresh = true;
|
||
|
exitVkbd = true;
|
||
|
}
|
||
|
else if (c == ACTION_EXITKBD) {
|
||
|
vkeyRefresh = true;
|
||
|
exitVkbd = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (vkeyRefresh) {
|
||
|
vkeyRefresh = false;
|
||
|
tft.drawSpriteNoDma(0,0,(uint16_t*)logo, rx, ry, rw, rh);
|
||
|
}
|
||
|
|
||
|
if ( (exitVkbd) && (vkbActive) ) {
|
||
|
if (!vkbKeepOn) {
|
||
|
toggleVirtualkeyboard(false);
|
||
|
}
|
||
|
else {
|
||
|
toggleVirtualkeyboard(true);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int emu_setKeymap(int index) {
|
||
|
if (index) {
|
||
|
//logo = ;
|
||
|
//keysw = ;
|
||
|
}
|
||
|
else {
|
||
|
//logo = ;
|
||
|
//keysw = ;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
static unsigned short palette16[PALETTE_SIZE];
|
||
|
static int fskip=0;
|
||
|
|
||
|
void emu_SetPaletteEntry(unsigned char r, unsigned char g, unsigned char b, int index)
|
||
|
{
|
||
|
if (index<PALETTE_SIZE) {
|
||
|
//printf("%d: %d %d %d\n", index, r,g,b);
|
||
|
palette16[index] = RGBVAL16(r,g,b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void emu_DrawVsync(void)
|
||
|
{
|
||
|
//printf("sync %d\n",skip);
|
||
|
fskip += 1;
|
||
|
fskip &= VID_FRAME_SKIP;
|
||
|
}
|
||
|
|
||
|
void emu_DrawLine(unsigned char * VBuf, int width, int height, int line)
|
||
|
{
|
||
|
if (fskip==0) {
|
||
|
tft.writeLine(width,height,line, VBuf, palette16);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void emu_DrawScreen(unsigned char * VBuf, int width, int height, int stride)
|
||
|
{
|
||
|
if (fskip==0) {
|
||
|
tft.writeScreen(width,height-TFT_VBUFFER_YCROP,stride, VBuf+(TFT_VBUFFER_YCROP/2)*stride, palette16);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int emu_FrameSkip(void)
|
||
|
{
|
||
|
return fskip;
|
||
|
}
|
||
|
|
||
|
void * emu_LineBuffer(int line)
|
||
|
{
|
||
|
return (void*)tft.getLineBuffer(line);
|
||
|
}
|
||
|
|
||
|
#ifdef HAS_SND
|
||
|
#include "AudioPlaySystem.h"
|
||
|
extern AudioPlaySystem audio;
|
||
|
|
||
|
void emu_sndInit() {
|
||
|
}
|
||
|
|
||
|
void emu_sndPlaySound(int chan, int volume, int freq)
|
||
|
{
|
||
|
if (chan < 6) {
|
||
|
audio.sound(chan, freq, volume);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void emu_sndPlayBuzz(int size, int val) {
|
||
|
//mymixer.buzz(size,val);
|
||
|
}
|
||
|
#endif
|
||
|
|