Chris Dick
/
Gameduino_Invaders_game
Invaders game for the Gameduino
utils.cpp
- Committer:
- TheChrisyd
- Date:
- 2012-09-29
- Revision:
- 1:f44175dd69fd
- Parent:
- 0:8a7c58553b44
- Child:
- 2:20a89dc286d5
File content as of revision 1:f44175dd69fd:
//#include <SPI.h> #include "utils.h" SPI spiutils(ARD_MOSI, ARD_MISO, ARD_SCK); // mosi, miso, sclk Serial pcu(USBTX, USBRX); /*--------------------------------------------- Coprocessor controller ---------------------------------------------*/ enum { COPPERCTRL = COMM, COPPERLISTSTART = COPPERCTRL, SAMPLEREADPOS = COPPERCTRL+2, SAMPLEREADPAGE = COPPERCTRL+4, COPPERLISTPTR = COPPERCTRL+6, YLINEECHO = COPPERCTRL+8, DUMMYCOPPERLIST = COPPERCTRL+10 }; // Available commands enum copper_commands { cp_halt='@', cp_wait, cp_write8, cp_write16, cp_copy }; #include "j1.h" void crash() { unsigned int p; while (1) { GD.wr(0,p++); } } static unsigned int samplePage_, listStart_; void Coprocessor::reset(unsigned int spg) { samplePage_ = spg; GD.wr(J1_RESET, 1); // Halt the coprocessor GD.copy(J1_CODE, copper_code, sizeof(copper_code)); for (unsigned int i=J1_CODE; i<J1_CODE+256; i+=2) { unsigned int w = GD.rd16(i); if (w == 0xbf00) { GD.wr16(i,spg+0x8000); } else if (w == COMM+0x8000) { listStart_ = i; } } CopperlistBuilder d; // Set up a fake copperlist GD.wr(DUMMYCOPPERLIST,cp_halt); GD.wr16(listStart_,DUMMYCOPPERLIST+0x8000); GD.wr16(SAMPLEREADPAGE,samplePage_); SoundController::reset(); GD.wr(J1_RESET, 0); // Go! delay(10); SoundController::update(); } void Coprocessor::setCopperlist(unsigned int addr) { GD.wr(J1_RESET, 1); // Halt the coprocessor GD.wr16(listStart_,addr+0x8000); GD.wr(J1_RESET, 0); // Go! } int Coprocessor::yline() { return GD.rd16(YLINEECHO); } unsigned int Coprocessor::samplePage() { return samplePage_; } byte Coprocessor::sampleReadPos() { return GD.rd(SAMPLEREADPOS); } // CopperlistBuilder void CopperlistBuilder::put(byte b) { GD.wr(out++,b); } void CopperlistBuilder::put16(unsigned int v) { put(lowByte(v)); put(highByte(v)); } void CopperlistBuilder::begin(unsigned int dest) { out = start = dest; #if 0 // Debugging... write(0,65); write(1,66); write(2,67); write(3,68); write(4,69); copy(0,64,4); copy(64,128,3); copy(128,131,5); #endif } void CopperlistBuilder::wait(int line) { if (line > 0) { put(cp_wait); put16(line); } } void CopperlistBuilder::write(unsigned int addr, byte val) { put(cp_write8); put(val); put16(addr); } void CopperlistBuilder::write16(unsigned int addr, unsigned int val) { put(cp_write16); put16(val); put16(addr); } void CopperlistBuilder::copy(unsigned int src, unsigned int dst, unsigned int numBytes) { if (numBytes > 0) { put(cp_copy); put16(src); put16(dst); put16(numBytes); } } void CopperlistBuilder::end(bool executeNow) { put(cp_halt); // Nice end to the list if (executeNow) { Coprocessor::setCopperlist(start); } } unsigned int CopperlistBuilder::position() { return out; } /*--------------------------------------------- Sound ---------------------------------------------*/ // The amount of space to leave in the buffer #define BUFFERGAP 8 /*--------------------------------------------- Sample playback ---------------------------------------------*/ static byte sampleWritePos; static prog_char *sampleStart0, *samplePos0, *sampleEnd0; static prog_char *sampleStart1, *samplePos1, *sampleEnd1; static prog_char *sampleStart2, *samplePos2, *sampleEnd2; static prog_char *sampleStart3, *samplePos3, *sampleEnd3; static bool repeatSample0, repeatSample1, repeatSample2, repeatSample3; static void writeSamples(byte num) { if (num > 0) { GD.__wstart(Coprocessor::samplePage()+sampleWritePos); prog_char *s0=samplePos0, *se0=sampleEnd0; prog_char *s1=samplePos1, *se1=sampleEnd1; prog_char *s2=samplePos2, *se2=sampleEnd2; prog_char *s3=samplePos3, *se3=sampleEnd3; for (byte i=0; i<num; ++i) { int val = 0; if (s0) { val += (char)pgm_read_byte(s0++); if (s0 == se0) { s0 = (repeatSample0)? sampleStart0: 0; } } if (s1) { val += (char)pgm_read_byte(s1++); if (s1 == se1) { s1 = (repeatSample1)? sampleStart1: 0; } } if (s2) { val += (char)pgm_read_byte(s2++); if (s2 == se2) { s2 = (repeatSample2)? sampleStart2: 0; } } if (s3) { val += (char)pgm_read_byte(s3++); if (s3 == se3) { s3 = (repeatSample3)? sampleStart3: 0; } } spiutils.write(val>>2); } GD.__end(); samplePos0 = s0; samplePos1 = s1; samplePos2 = s2; samplePos3 = s3; sampleWritePos += num; } } void SoundController::playSample(prog_char *s, int n, byte ch) { bool repeat = (n < 0); if (repeat) { n = -n; } switch (ch) { case 0: sampleStart0 = s; samplePos0 = s; sampleEnd0 = s+n; repeatSample0 = repeat; break; case 1: sampleStart1 = s; samplePos1 = s; sampleEnd1 = s+n; repeatSample1 = repeat; break; case 2: sampleStart2 = s; samplePos2 = s; sampleEnd2 = s+n; repeatSample2 = repeat; break; case 3: sampleStart3 = s; samplePos3 = s; sampleEnd3 = s+n; repeatSample3 = repeat; break; } } #if SYNTHSOUNDS /*--------------------------------------------- Synthesized sounds ---------------------------------------------*/ static SoundPlayer *soundPlayerList=0; ADSR::ADSR(byte a, byte d, byte s, byte r) : attack(a), decay(d), sustain(s), release(r) { } byte ADSR::evaluate(unsigned int t, unsigned int r) { if (t > r) { // In release phase... t -= r; if (t > release) { return 0; } t = sustain*(release-t); return t/release; } else if (t >= (attack+decay)) { // In sustain phase return sustain; } else if (t > attack) { // In decay phase t -= attack; t = (255-sustain)*t; return 255-(t/decay); } else if (t > 0) { // In attack phase return (t*255)/attack; } return 0; } SoundPlayer::SoundPlayer() { volume = 255; active = false; isLinked = false; } SoundPlayer& SoundPlayer::setVolume(byte v) { volume = v; return *this; } SoundPlayer& SoundPlayer::setSound(const Sound& s) { sound = s; return *this; } void SoundPlayer::play(unsigned int p, unsigned int d) { if (!isLinked) { // Add me to the list of sounds to be updated isLinked = true; link = soundPlayerList; soundPlayerList = this; } ticks = 0; pitch = p; duration = d; releasing = false; active = true; } void SoundPlayer::release() { releasing = true; duration = ticks; } void SoundPlayer::update() { if (active) { if (releasing) { if (++ticks > (duration+sound.adsr.release)) { stop(); } } else { if (ticks!=infinite) { ++ticks; } if ((ticks==duration) and (duration!=infinite)) { release(); } } if (active) { GD.__wstart(VOICES); spimain.write(lowByte(pitch)); spimain.write(highByte(pitch)); unsigned int b = sound.adsr.evaluate(ticks,duration); b = highByte(b*volume); //spimain.write(b); //spimain.write(b); GD.__end(); } } } void SoundPlayer::stop() { if (active) { active = false; GD.__wstart(VOICES+2); spimain.write(0); spimain.write(0); GD.__end(); } } #endif /*--------------------------------------------- SoundController object ---------------------------------------------*/ void SoundController::reset() { samplePos0 = 0; samplePos1 = 0; samplePos2 = 0; samplePos3 = 0; GD.__wstart(Coprocessor::samplePage()); for (int i=0; i<256; ++i) { spiutils.write(0); } GD.__end(); #if SYNTHSOUNDS SoundPlayer *p = soundPlayerList; while (p) { p->stop(); p->isLinked = false; p = p->link; } #endif } void SoundController::update() { #if SYNTHSOUNDS { // Synthesized sounds byte b = '0'; SoundPlayer *p = soundPlayerList; while (p) { ++b; p->update(); p = p->link; } GD.wr(0,b); } #endif { // Sampled sounds unsigned int rp = Coprocessor::sampleReadPos(); unsigned int wp = sampleWritePos; unsigned int emptySpace = (rp-wp)&255; if (emptySpace > BUFFERGAP) { emptySpace -= BUFFERGAP; if ((wp+emptySpace) > 256) { // Write would overflow the buffer - need to split it into two unsigned int b = 256-wp; writeSamples(b); writeSamples(emptySpace-b); } else { // Can write a single block writeSamples(emptySpace); } } } } /*------------------------------------------------------------ Useful little functions ------------------------------------------------------------*/ void showNumber(int n, byte x, byte y) { char temp[8]; boolean neg = (n<0); if (neg) { n = -n; } char *o = temp; int m = 10000; while (m != 0) { int d = n/m; *o++ = d+'0'; n -= d*m; m /= 10; } *o-- = 0; // Remove leading zeros char *s = temp; while ((s<o) and (*s=='0')) { *s++ = ' '; } if (neg) { *--s = '-'; } GD.__wstart((64*y)+x); while (*s) { spiutils.write(*s++); } GD.__end(); } static void hexDigit(byte b) { b = (b&0x0f)+'0'; if (b > '9') { b += 'a'-('9'+1); } spiutils.write(b); } static void hexPair(byte b) { hexDigit(b>>4); hexDigit(b); } void showHexNumber(unsigned int n, byte x, byte y) { GD.__wstart((64*y)+x); hexPair(highByte(n)); hexPair(lowByte(n)); GD.__end(); } void writeColor(int c) { // Colors are five bits - encode in base 32 c = (c&31)+'0'; if (c > '9') { c += 'A'-('9'+1); } pcu.printf("%d", c); } void sendScreenshot() { pcu.baud(115200); for (int i=0; i<300; ++i) { // Ask for the line... GD.wr16(SCREENSHOT_Y, 0x8000|i); // Wait for it to appear while ((GD.rd(SCREENSHOT_Y+1)&0x80)==0) { delay(1); } // Send the line of pixels to the serial port for (int x=0; x<400; ++x) { uint16_t pixel = GD.rd16(SCREENSHOT+(x*2)); writeColor(pixel>>10); // Red writeColor(pixel>>5); // Green writeColor(pixel); // Blue } pcu.printf("\n"); } // Restore sanity GD.wr16(SCREENSHOT_Y, 0); }