Chris Dick
/
Gameduino_Invaders_game
Invaders game for the Gameduino
Diff: utils.cpp
- Revision:
- 1:f44175dd69fd
- Parent:
- 0:8a7c58553b44
- Child:
- 2:20a89dc286d5
--- a/utils.cpp Thu Jun 21 19:13:34 2012 +0000 +++ b/utils.cpp Sat Sep 29 13:01:42 2012 +0000 @@ -1,488 +1,488 @@ -//#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); -} +//#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); +}