Invaders game for the Gameduino

Dependencies:   Gameduino mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers utils.cpp Source File

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 }