Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: Gameduino mbed nRF2401A
Fork of Gameduino_Invaders_game by
Diff: utils.cpp
- Revision:
- 2:20a89dc286d5
- Parent:
- 1:f44175dd69fd
--- a/utils.cpp Sat Sep 29 13:01:42 2012 +0000
+++ b/utils.cpp Thu Dec 20 21:33:52 2012 +0000
@@ -1,488 +1,490 @@
-//#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"
+#include "shield.h"
+extern GDClass GD;
+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);
+}
