wrapemu.cpp
1 #include <stdio.h> 2 #include <string.h> 3 4 extern "C" { 5 #include "emuapi.h" 6 #include "platform_config.h" 7 } 8 #include <Arduino.h> 9 #include "handy.h" 10 11 12 // Emulation includes 13 14 static CSystem *lynx = NULL; 15 16 17 18 #define AUDIORPTRMASK (((AUDIO_BUFFER_LENGTH-1)<<8)+0xff) 19 20 static ULONG sndbuffer[AUDIO_BUFFER_LENGTH]; // (short)(L<<16)+(short)R 21 22 static long audioowptr = 0; 23 static long audioorptr = 0; 24 static long audiorptr = 0; 25 static long deltar = 0; 26 27 28 29 #define AVG_COUNT 16 30 static int avgcounter = AVG_COUNT; 31 static long avgr = 0; 32 static long avgw = 0; 33 static long inc = 0; 34 static long incdelta = 0; 35 static long sndinc = 0x100; // default read increment 36 37 // distance between read and write buffer 38 static long pdelta = 0x1000; 39 static bool pdown = true; 40 41 42 static int dpad_mapped_up; 43 static int dpad_mapped_down; 44 static int dpad_mapped_left; 45 static int dpad_mapped_right; 46 47 #define DISPLAY_ROTATION_OFF 0 48 #define DISPLAY_ROTATION_LEFT 1 49 #define DISPLAY_ROTATION_RIGHT 2 50 51 static int ik; // joypad key 52 static int pik=0; 53 54 static int ihk; // I2C keyboard key 55 static int iusbhk;// USB keyboard key 56 57 void lnx_Input(int bClick) { 58 ik = emu_GetPad(); 59 ihk = emu_ReadI2CKeyboard(); 60 } 61 62 void emu_KeyboardOnDown(int keymodifer, int key) { 63 int keyCode = -1; //INV_KEY; 64 if ((key >=0xc0) && (key <=0xdf)) { 65 keyCode = ((key-0xc0) & 0x1f) + 0x7f; 66 } 67 else { 68 keyCode = key & 0x7f; 69 } 70 71 //Serial.println(keyCode); 72 73 if (keyCode != -1) { 74 iusbhk = keyCode; 75 } 76 } 77 78 void emu_KeyboardOnUp(int keymodifer, int key) { 79 iusbhk = 0; 80 } 81 82 void lnx_Init(void) 83 { 84 } 85 86 87 void lnx_Start(char * filename) 88 { 89 emu_printf("emu starting"); 90 91 lynx = new CSystem(filename, MIKIE_PIXEL_FORMAT_16BPP_565, HANDY_AUDIO_SAMPLE_FREQ); 92 if (lynx->mFileType == HANDY_FILETYPE_ILLEGAL) 93 { 94 emu_printf("illegal"); 95 return; 96 } 97 98 // gPrimaryFrameBuffer = (UBYTE*)(emu_SMalloc((HANDY_SCREEN_HEIGHT+1)*HANDY_SCREEN_STRIDE*sizeof(HandyPixel))); 99 gPrimaryFrameBuffer = (UBYTE*)(emu_SMalloc((OUTPUT_SCREEN_HEIGHT)*OUTPUT_SCREEN_WIDTH*sizeof(HandyPixel))); 100 memset((void *)gPrimaryFrameBuffer, 0,(OUTPUT_SCREEN_HEIGHT)*OUTPUT_SCREEN_WIDTH*sizeof(HandyPixel)); 101 gAudioBuffer = &sndbuffer[0]; 102 memset(&sndbuffer[0], AUDIO_BUFFER_LENGTH*4,0); 103 gAudioEnabled = 1; 104 gAudioBufferPointer = AUDIO_BUFFER_LENGTH/2; 105 106 int rotation = DISPLAY_ROTATION_OFF; 107 108 uint32_t crc32 = lynx->mCart->CRC32(); 109 emu_printh(crc32); 110 switch (crc32) 111 { 112 case 0x97501709: // Centipede 113 case 0x0271B6E9: // Lexis 114 case 0x006FD398: // NFL Football 115 case 0x1D9EC645: 116 case 0xBCD10C3A: // Raiden 117 rotation = DISPLAY_ROTATION_LEFT; 118 break; 119 case 0x7F0EC7AD: // Gauntlet 120 case 0xAC564BAA: // Gauntlet - The Third Encounter 121 case 0xFE19F59F: 122 case 0xA53649F1: // Klax 123 case 0xB8C75C2C: // Klax 124 rotation = DISPLAY_ROTATION_RIGHT; 125 break; 126 default: 127 if (lynx->mCart->CartGetRotate() == CART_ROTATE_LEFT) 128 rotation = DISPLAY_ROTATION_LEFT; 129 if (lynx->mCart->CartGetRotate() == CART_ROTATE_RIGHT) 130 rotation = DISPLAY_ROTATION_RIGHT; 131 } 132 switch(rotation) 133 { 134 case DISPLAY_ROTATION_LEFT: 135 lynx->mMikie->SetRotation(MIKIE_ROTATE_L); 136 dpad_mapped_up = BUTTON_RIGHT; 137 dpad_mapped_down = BUTTON_LEFT; 138 dpad_mapped_left = BUTTON_UP; 139 dpad_mapped_right = BUTTON_DOWN; 140 break; 141 case DISPLAY_ROTATION_RIGHT: 142 lynx->mMikie->SetRotation(MIKIE_ROTATE_R); 143 dpad_mapped_up = BUTTON_LEFT; 144 dpad_mapped_down = BUTTON_RIGHT; 145 dpad_mapped_left = BUTTON_DOWN; 146 dpad_mapped_right = BUTTON_UP; 147 break; 148 default: 149 lynx->mMikie->SetRotation(MIKIE_NO_ROTATE); 150 dpad_mapped_up = BUTTON_UP; 151 dpad_mapped_down = BUTTON_DOWN; 152 dpad_mapped_left = BUTTON_LEFT; 153 dpad_mapped_right = BUTTON_RIGHT; 154 break; 155 } 156 157 158 emu_printf("emu started"); 159 } 160 161 void lnx_Step(void) 162 { 163 ULONG buttons = 0; 164 165 int k=ik; 166 #ifdef TEECOMPUTER 167 int hk = ihk; 168 if (hk == 'q') { 169 buttons |= BUTTON_OPT1; 170 } 171 if (hk == 'w') { 172 buttons |= BUTTON_OPT2; 173 } 174 if (hk == 'e') { 175 buttons |= BUTTON_PAUSE; 176 } 177 #endif 178 if ( (k & MASK_JOY2_UP) || (k & MASK_JOY1_UP) ) buttons |= dpad_mapped_up; 179 if ( (k & MASK_JOY2_DOWN) || (k & MASK_JOY1_DOWN) ) buttons |= dpad_mapped_down; 180 if ( (k & MASK_JOY2_LEFT) || (k & MASK_JOY1_LEFT) ) buttons |= dpad_mapped_left; 181 if ( (k & MASK_JOY2_RIGHT) || (k & MASK_JOY1_RIGHT) ) buttons |= dpad_mapped_right; 182 if ( (k & MASK_JOY2_BTN) || (k & MASK_JOY1_BTN) ) buttons |= BUTTON_A; 183 if ( (k & MASK_KEY_USER1) ) buttons |= BUTTON_A; 184 if ( (k & MASK_KEY_USER2) ) buttons |= BUTTON_B; 185 if ( (k & MASK_KEY_USER3) ) buttons |= BUTTON_OPT1; 186 187 lynx->SetButtonData(buttons); 188 189 lynx->UpdateFrame(true); 190 191 HandyPixel * buf = (HandyPixel *)gPrimaryFrameBuffer; 192 for (int j=0; j<OUTPUT_SCREEN_HEIGHT; j++) { 193 emu_DrawLine16(&buf[OUTPUT_SCREEN_STRIDE*j], OUTPUT_SCREEN_WIDTH, OUTPUT_SCREEN_HEIGHT, j); 194 } 195 196 emu_DrawVsync(); 197 198 pik = k; 199 200 201 // #sample written per frame 202 long ptr = gAudioBufferPointer; 203 long wdelta = ptr - audioowptr; 204 if (wdelta < 0) wdelta = AUDIO_BUFFER_LENGTH+wdelta; 205 audioowptr = ptr; 206 207 // #sample read per frame 208 int rdelta = deltar; 209 deltar = 0; 210 211 212 // Compute average R/W over AVG_COUNT frame 213 avgcounter--; 214 avgw += wdelta; 215 avgr += rdelta; 216 inc = (wdelta<<8)/(rdelta); 217 if (avgcounter == 0) { 218 219 wdelta = avgw/AVG_COUNT; 220 rdelta = avgr/AVG_COUNT; 221 avgw = 0; 222 avgr = 0; 223 avgcounter = AVG_COUNT; 224 225 //emu_printi(wdelta); 226 //emu_printi(rdelta); 227 228 long delta = ptr - audiorptr>>8; 229 if (delta < 0) delta = AUDIO_BUFFER_LENGTH+delta; 230 231 232 // we try to be keep read and write buffer at half distance of each other 233 bool down; 234 if (delta < pdelta) { 235 down = true; // keep going down 236 if (delta < (AUDIO_BUFFER_LENGTH/2)) { 237 if ( (down) && (pdown) ) 238 incdelta += 2; 239 else 240 incdelta = 1; 241 } 242 } 243 else if (delta > pdelta) { 244 down = false; // goes up again 245 if (delta > (AUDIO_BUFFER_LENGTH/2)) { 246 if ( (!down) && (!pdown) ) 247 incdelta -= 2; 248 else 249 incdelta = -1; 250 } 251 } 252 else { 253 incdelta = 0; 254 } 255 // Hard reset sound buffer? 256 257 if ( (delta < AUDIO_BUFFER_LENGTH/4) || (delta > (AUDIO_BUFFER_LENGTH-AUDIO_BUFFER_LENGTH/4)) ) { 258 /* 259 memset(sndbuffer,sizeof(sndbuffer),0); 260 gAudioBufferPointer = 0; 261 audioowptr = 0; 262 audiorptr=(AUDIO_BUFFER_LENGTH/2)<<8; 263 delta = AUDIO_BUFFER_LENGTH/2; 264 */ 265 //emu_printf("reset"); 266 } 267 268 pdelta = delta; 269 pdown = down; 270 //emu_printi(delta); 271 } 272 //emu_printi(incdelta); 273 274 sndinc = inc+incdelta; 275 } 276 277 278 279 280 void SND_Process(void *stream, int len) { 281 282 short * dst = (short*)stream; 283 284 len = len >> 1; 285 for (int i=0;i<len;i++) 286 { 287 ULONG val = sndbuffer[audiorptr>>8]; 288 *dst++ = (val >> 16); 289 *dst++ = (val & 0xffff); 290 audiorptr += sndinc; 291 audiorptr &= AUDIORPTRMASK; 292 deltar +=1; 293 } 294 /* 295 long pt = (gAudioBufferPointer) - len; 296 if (pt < 0) pt+=AUDIO_BUFFER_LENGTH; 297 for (int i=0;i<len;i++) 298 { 299 ULONG val = sndbuffer[pt++]; 300 *dst++ = (val >> 16); 301 *dst++ = (val & 0xffff); 302 pt &= (AUDIO_BUFFER_LENGTH-1); 303 } 304 */ 305 } 306