Space invaders with a nRF2401A wireless joypad
Dependencies: Gameduino mbed nRF2401A
Fork of Gameduino_Invaders_game by
utils.cpp
00001 //#include <SPI.h> 00002 00003 #include "utils.h" 00004 #include "shield.h" 00005 extern GDClass GD; 00006 SPI spiutils(ARD_MOSI, ARD_MISO, ARD_SCK); // mosi, miso, sclk 00007 Serial pcu(USBTX, USBRX); 00008 /*--------------------------------------------- 00009 Coprocessor controller 00010 ---------------------------------------------*/ 00011 enum { 00012 COPPERCTRL = COMM, 00013 COPPERLISTSTART = COPPERCTRL, 00014 SAMPLEREADPOS = COPPERCTRL+2, 00015 SAMPLEREADPAGE = COPPERCTRL+4, 00016 COPPERLISTPTR = COPPERCTRL+6, 00017 YLINEECHO = COPPERCTRL+8, 00018 DUMMYCOPPERLIST = COPPERCTRL+10 00019 }; 00020 00021 // Available commands 00022 enum copper_commands { 00023 cp_halt='@', 00024 cp_wait, 00025 cp_write8, 00026 cp_write16, 00027 cp_copy 00028 }; 00029 00030 #include "j1.h" 00031 void crash() 00032 { 00033 unsigned int p; 00034 while (1) { 00035 GD.wr(0,p++); 00036 } 00037 } 00038 static unsigned int samplePage_, listStart_; 00039 void Coprocessor::reset(unsigned int spg) 00040 { 00041 samplePage_ = spg; 00042 GD.wr(J1_RESET, 1); // Halt the coprocessor 00043 GD.copy(J1_CODE, copper_code, sizeof(copper_code)); 00044 for (unsigned int i=J1_CODE; i<J1_CODE+256; i+=2) { 00045 unsigned int w = GD.rd16(i); 00046 if (w == 0xbf00) { GD.wr16(i,spg+0x8000); } 00047 else if (w == COMM+0x8000) { listStart_ = i; } 00048 } 00049 CopperlistBuilder d; // Set up a fake copperlist 00050 GD.wr(DUMMYCOPPERLIST,cp_halt); 00051 GD.wr16(listStart_,DUMMYCOPPERLIST+0x8000); 00052 GD.wr16(SAMPLEREADPAGE,samplePage_); 00053 SoundController::reset(); 00054 GD.wr(J1_RESET, 0); // Go! 00055 delay(10); 00056 SoundController::update(); 00057 } 00058 00059 void Coprocessor::setCopperlist(unsigned int addr) 00060 { 00061 GD.wr(J1_RESET, 1); // Halt the coprocessor 00062 GD.wr16(listStart_,addr+0x8000); 00063 GD.wr(J1_RESET, 0); // Go! 00064 } 00065 00066 int Coprocessor::yline() 00067 { 00068 return GD.rd16(YLINEECHO); 00069 } 00070 unsigned int Coprocessor::samplePage() 00071 { 00072 return samplePage_; 00073 } 00074 byte Coprocessor::sampleReadPos() 00075 { 00076 return GD.rd(SAMPLEREADPOS); 00077 } 00078 00079 // CopperlistBuilder 00080 void CopperlistBuilder::put(byte b) 00081 { 00082 GD.wr(out++,b); 00083 } 00084 void CopperlistBuilder::put16(unsigned int v) 00085 { 00086 put(lowByte(v)); 00087 put(highByte(v)); 00088 } 00089 00090 void CopperlistBuilder::begin(unsigned int dest) 00091 { 00092 out = start = dest; 00093 #if 0 00094 // Debugging... 00095 write(0,65); 00096 write(1,66); 00097 write(2,67); 00098 write(3,68); 00099 write(4,69); 00100 copy(0,64,4); 00101 copy(64,128,3); 00102 copy(128,131,5); 00103 #endif 00104 } 00105 void CopperlistBuilder::wait(int line) 00106 { 00107 if (line > 0) { 00108 put(cp_wait); 00109 put16(line); 00110 } 00111 } 00112 void CopperlistBuilder::write(unsigned int addr, byte val) 00113 { 00114 put(cp_write8); 00115 put(val); 00116 put16(addr); 00117 } 00118 void CopperlistBuilder::write16(unsigned int addr, unsigned int val) 00119 { 00120 put(cp_write16); 00121 put16(val); 00122 put16(addr); 00123 } 00124 void CopperlistBuilder::copy(unsigned int src, unsigned int dst, unsigned int numBytes) 00125 { 00126 if (numBytes > 0) { 00127 put(cp_copy); 00128 put16(src); 00129 put16(dst); 00130 put16(numBytes); 00131 } 00132 } 00133 void CopperlistBuilder::end(bool executeNow) 00134 { 00135 put(cp_halt); // Nice end to the list 00136 if (executeNow) { 00137 Coprocessor::setCopperlist(start); 00138 } 00139 } 00140 00141 unsigned int CopperlistBuilder::position() 00142 { 00143 return out; 00144 } 00145 00146 /*--------------------------------------------- 00147 Sound 00148 ---------------------------------------------*/ 00149 // The amount of space to leave in the buffer 00150 #define BUFFERGAP 8 00151 00152 /*--------------------------------------------- 00153 Sample playback 00154 ---------------------------------------------*/ 00155 static byte sampleWritePos; 00156 static prog_char *sampleStart0, *samplePos0, *sampleEnd0; 00157 static prog_char *sampleStart1, *samplePos1, *sampleEnd1; 00158 static prog_char *sampleStart2, *samplePos2, *sampleEnd2; 00159 static prog_char *sampleStart3, *samplePos3, *sampleEnd3; 00160 static bool repeatSample0, repeatSample1, repeatSample2, repeatSample3; 00161 00162 static void writeSamples(byte num) 00163 { 00164 if (num > 0) { 00165 GD.__wstart(Coprocessor::samplePage()+sampleWritePos); 00166 prog_char *s0=samplePos0, *se0=sampleEnd0; 00167 prog_char *s1=samplePos1, *se1=sampleEnd1; 00168 prog_char *s2=samplePos2, *se2=sampleEnd2; 00169 prog_char *s3=samplePos3, *se3=sampleEnd3; 00170 for (byte i=0; i<num; ++i) { 00171 int val = 0; 00172 if (s0) { 00173 val += (char)pgm_read_byte(s0++); 00174 if (s0 == se0) { 00175 s0 = (repeatSample0)? sampleStart0: 0; 00176 } 00177 } 00178 if (s1) { 00179 val += (char)pgm_read_byte(s1++); 00180 if (s1 == se1) { 00181 s1 = (repeatSample1)? sampleStart1: 0; 00182 } 00183 } 00184 if (s2) { 00185 val += (char)pgm_read_byte(s2++); 00186 if (s2 == se2) { 00187 s2 = (repeatSample2)? sampleStart2: 0; 00188 } 00189 } 00190 if (s3) { 00191 val += (char)pgm_read_byte(s3++); 00192 if (s3 == se3) { 00193 s3 = (repeatSample3)? sampleStart3: 0; 00194 } 00195 } 00196 spiutils.write(val>>2); 00197 } 00198 GD.__end(); 00199 samplePos0 = s0; 00200 samplePos1 = s1; 00201 samplePos2 = s2; 00202 samplePos3 = s3; 00203 sampleWritePos += num; 00204 } 00205 } 00206 00207 void SoundController::playSample(prog_char *s, int n, byte ch) 00208 { 00209 bool repeat = (n < 0); 00210 if (repeat) { 00211 n = -n; 00212 } 00213 switch (ch) { 00214 case 0: sampleStart0 = s; 00215 samplePos0 = s; 00216 sampleEnd0 = s+n; 00217 repeatSample0 = repeat; 00218 break; 00219 case 1: sampleStart1 = s; 00220 samplePos1 = s; 00221 sampleEnd1 = s+n; 00222 repeatSample1 = repeat; 00223 break; 00224 case 2: sampleStart2 = s; 00225 samplePos2 = s; 00226 sampleEnd2 = s+n; 00227 repeatSample2 = repeat; 00228 break; 00229 case 3: sampleStart3 = s; 00230 samplePos3 = s; 00231 sampleEnd3 = s+n; 00232 repeatSample3 = repeat; 00233 break; 00234 } 00235 } 00236 00237 #if SYNTHSOUNDS 00238 /*--------------------------------------------- 00239 Synthesized sounds 00240 ---------------------------------------------*/ 00241 static SoundPlayer *soundPlayerList=0; 00242 ADSR::ADSR(byte a, byte d, byte s, byte r) : attack(a), decay(d), sustain(s), release(r) 00243 { 00244 } 00245 byte ADSR::evaluate(unsigned int t, unsigned int r) 00246 { 00247 if (t > r) { 00248 // In release phase... 00249 t -= r; 00250 if (t > release) { 00251 return 0; 00252 } 00253 t = sustain*(release-t); 00254 return t/release; 00255 } 00256 else if (t >= (attack+decay)) { 00257 // In sustain phase 00258 return sustain; 00259 } 00260 else if (t > attack) { 00261 // In decay phase 00262 t -= attack; 00263 t = (255-sustain)*t; 00264 return 255-(t/decay); 00265 } 00266 else if (t > 0) { 00267 // In attack phase 00268 return (t*255)/attack; 00269 } 00270 return 0; 00271 } 00272 00273 SoundPlayer::SoundPlayer() 00274 { 00275 volume = 255; 00276 active = false; 00277 isLinked = false; 00278 } 00279 SoundPlayer& SoundPlayer::setVolume(byte v) 00280 { 00281 volume = v; 00282 return *this; 00283 } 00284 SoundPlayer& SoundPlayer::setSound(const Sound& s) 00285 { 00286 sound = s; 00287 return *this; 00288 } 00289 void SoundPlayer::play(unsigned int p, unsigned int d) 00290 { 00291 if (!isLinked) { 00292 // Add me to the list of sounds to be updated 00293 isLinked = true; 00294 link = soundPlayerList; 00295 soundPlayerList = this; 00296 } 00297 ticks = 0; 00298 pitch = p; 00299 duration = d; 00300 releasing = false; 00301 active = true; 00302 } 00303 void SoundPlayer::release() 00304 { 00305 releasing = true; 00306 duration = ticks; 00307 } 00308 void SoundPlayer::update() 00309 { 00310 if (active) { 00311 if (releasing) { 00312 if (++ticks > (duration+sound.adsr.release)) { 00313 stop(); 00314 } 00315 } 00316 else { 00317 if (ticks!=infinite) { 00318 ++ticks; 00319 } 00320 if ((ticks==duration) and (duration!=infinite)) { 00321 release(); 00322 } 00323 } 00324 if (active) { 00325 GD.__wstart(VOICES); 00326 spimain.write(lowByte(pitch)); 00327 spimain.write(highByte(pitch)); 00328 unsigned int b = sound.adsr.evaluate(ticks,duration); 00329 b = highByte(b*volume); 00330 //spimain.write(b); 00331 //spimain.write(b); 00332 GD.__end(); 00333 } 00334 } 00335 } 00336 void SoundPlayer::stop() 00337 { 00338 if (active) { 00339 active = false; 00340 GD.__wstart(VOICES+2); 00341 spimain.write(0); 00342 spimain.write(0); 00343 GD.__end(); 00344 } 00345 } 00346 #endif 00347 /*--------------------------------------------- 00348 SoundController object 00349 ---------------------------------------------*/ 00350 void SoundController::reset() 00351 { 00352 samplePos0 = 0; 00353 samplePos1 = 0; 00354 samplePos2 = 0; 00355 samplePos3 = 0; 00356 GD.__wstart(Coprocessor::samplePage()); 00357 for (int i=0; i<256; ++i) { 00358 spiutils.write(0); 00359 } 00360 GD.__end(); 00361 #if SYNTHSOUNDS 00362 SoundPlayer *p = soundPlayerList; 00363 while (p) { 00364 p->stop(); 00365 p->isLinked = false; 00366 p = p->link; 00367 } 00368 #endif 00369 } 00370 00371 void SoundController::update() 00372 { 00373 #if SYNTHSOUNDS 00374 { // Synthesized sounds 00375 byte b = '0'; 00376 SoundPlayer *p = soundPlayerList; 00377 while (p) { 00378 ++b; 00379 p->update(); 00380 p = p->link; 00381 } 00382 GD.wr(0,b); 00383 } 00384 #endif 00385 { // Sampled sounds 00386 unsigned int rp = Coprocessor::sampleReadPos(); 00387 unsigned int wp = sampleWritePos; 00388 unsigned int emptySpace = (rp-wp)&255; 00389 if (emptySpace > BUFFERGAP) { 00390 emptySpace -= BUFFERGAP; 00391 if ((wp+emptySpace) > 256) { 00392 // Write would overflow the buffer - need to split it into two 00393 unsigned int b = 256-wp; 00394 writeSamples(b); 00395 writeSamples(emptySpace-b); 00396 } 00397 else { 00398 // Can write a single block 00399 writeSamples(emptySpace); 00400 } 00401 } 00402 } 00403 } 00404 00405 00406 /*------------------------------------------------------------ 00407 Useful little functions 00408 ------------------------------------------------------------*/ 00409 void showNumber(int n, byte x, byte y) 00410 { 00411 char temp[8]; 00412 boolean neg = (n<0); 00413 if (neg) { 00414 n = -n; 00415 } 00416 char *o = temp; 00417 int m = 10000; 00418 while (m != 0) { 00419 int d = n/m; 00420 *o++ = d+'0'; 00421 n -= d*m; 00422 m /= 10; 00423 } 00424 *o-- = 0; 00425 // Remove leading zeros 00426 char *s = temp; 00427 while ((s<o) and (*s=='0')) { 00428 *s++ = ' '; 00429 } 00430 if (neg) { 00431 *--s = '-'; 00432 } 00433 GD.__wstart((64*y)+x); 00434 while (*s) { 00435 spiutils.write(*s++); 00436 } 00437 GD.__end(); 00438 } 00439 00440 static void hexDigit(byte b) 00441 { 00442 b = (b&0x0f)+'0'; 00443 if (b > '9') { 00444 b += 'a'-('9'+1); 00445 } 00446 spiutils.write(b); 00447 } 00448 static void hexPair(byte b) 00449 { 00450 hexDigit(b>>4); 00451 hexDigit(b); 00452 } 00453 void showHexNumber(unsigned int n, byte x, byte y) 00454 { 00455 GD.__wstart((64*y)+x); 00456 hexPair(highByte(n)); 00457 hexPair(lowByte(n)); 00458 GD.__end(); 00459 } 00460 void writeColor(int c) 00461 { 00462 // Colors are five bits - encode in base 32 00463 c = (c&31)+'0'; 00464 if (c > '9') { 00465 c += 'A'-('9'+1); 00466 } 00467 pcu.printf("%d", c); 00468 } 00469 void sendScreenshot() 00470 { 00471 pcu.baud(115200); 00472 for (int i=0; i<300; ++i) { 00473 // Ask for the line... 00474 GD.wr16(SCREENSHOT_Y, 0x8000|i); 00475 // Wait for it to appear 00476 while ((GD.rd(SCREENSHOT_Y+1)&0x80)==0) { 00477 delay(1); 00478 } 00479 // Send the line of pixels to the serial port 00480 for (int x=0; x<400; ++x) { 00481 uint16_t pixel = GD.rd16(SCREENSHOT+(x*2)); 00482 writeColor(pixel>>10); // Red 00483 writeColor(pixel>>5); // Green 00484 writeColor(pixel); // Blue 00485 } 00486 pcu.printf("\n"); 00487 } 00488 // Restore sanity 00489 GD.wr16(SCREENSHOT_Y, 0); 00490 }
Generated on Fri Jul 15 2022 06:07:12 by 1.7.2