diff options
Diffstat (limited to 'backends/platform/ds/arm7/source/main.cpp')
-rw-r--r-- | backends/platform/ds/arm7/source/main.cpp | 1130 |
1 files changed, 1130 insertions, 0 deletions
diff --git a/backends/platform/ds/arm7/source/main.cpp b/backends/platform/ds/arm7/source/main.cpp new file mode 100644 index 0000000000..f5518be647 --- /dev/null +++ b/backends/platform/ds/arm7/source/main.cpp @@ -0,0 +1,1130 @@ +/* ScummVMDS - Scumm Interpreter DS Port + * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header: /cvsroot/scummvm/scummvm/backends/fs/fs.cpp,v 1.3.2.1 2004/12/18 02:33:52 fingolfin Exp $ + */ + +////////////////////////////////////////////////////////////////////// +// Simple ARM7 stub (sends RTC, TSC, and X/Y data to the ARM 9) +// -- joat +// -- modified by Darkain and others +////////////////////////////////////////////////////////////////////// + + +#include <nds.h> + +#include <bios.h> +#include <arm7/touch.h> +#include <arm7/clock.h> +#include <stdlib.h> +#include <string.h> + +#include <nds/scummvm_ipc.h> +////////////////////////////////////////////////////////////////////// + + +#define TOUCH_CAL_X1 (*(vs16*)0x027FFCD8) +#define TOUCH_CAL_Y1 (*(vs16*)0x027FFCDA) +#define TOUCH_CAL_X2 (*(vs16*)0x027FFCDE) +#define TOUCH_CAL_Y2 (*(vs16*)0x027FFCE0) +#define SCREEN_WIDTH 256 +#define SCREEN_HEIGHT 192 +s32 TOUCH_WIDTH = TOUCH_CAL_X2 - TOUCH_CAL_X1; +s32 TOUCH_HEIGHT = TOUCH_CAL_Y2 - TOUCH_CAL_Y1; +s32 TOUCH_OFFSET_X = ( ((SCREEN_WIDTH -60) * TOUCH_CAL_X1) / TOUCH_WIDTH ) - 28; +s32 TOUCH_OFFSET_Y = ( ((SCREEN_HEIGHT-60) * TOUCH_CAL_Y1) / TOUCH_HEIGHT ) - 28; + +vu8* soundData; + +vu8* soundBuffer; +vu8* arm9Buffer; +bool soundFilled[4]; + +int playingSection; + +bool needSleep = false; +int temp; + +int adpcmBufferNum = 0; + +// those are pixel positions of the two points you click when calibrating +#define TOUCH_CNTRL_X1 (*(vu8*)0x027FFCDC) +#define TOUCH_CNTRL_Y1 (*(vu8*)0x027FFCDD) +#define TOUCH_CNTRL_X2 (*(vu8*)0x027FFCE2) +#define TOUCH_CNTRL_Y2 (*(vu8*)0x027FFCE3) + + +////////////////////////////////////////////////////////////////////// + +/* +void startSound(int sampleRate, const void* data, uint32 bytes, u8 channel=0, u8 vol=0x7F, u8 pan=63, u8 format=0) { + SCHANNEL_TIMER(channel) = SOUND_FREQ(sampleRate); + SCHANNEL_SOURCE(channel) = (uint32)data; + SCHANNEL_LENGTH(channel) = bytes; + SCHANNEL_CR(channel) = SOUND_ENABLE | SOUND_ONE_SHOT | SOUND_VOL(vol) | SOUND_PAN(pan) | (format==1?SOUND_8BIT:SOUND_16BIT); +} + + +s8 getFreeSoundChannel() { + for (int i=0; i<16; i++) { + if ( (SCHANNEL_CR(i) & SOUND_ENABLE) == 0 ) return i; + } + return -1; +} +*/ + + +s8 getFreeSoundChannel() { +// return 0; + for (int i=0; i<16; i++) { + if ( (SCHANNEL_CR(i) & SCHANNEL_ENABLE) == 0 ) return i; + } + return -1; +} + +void startSound(int sampleRate, const void* data, uint32 bytes, u8 channel=0, u8 vol=0x7F, u8 pan=63, u8 format=0) { + REG_IME = IME_DISABLE; + + channel = getFreeSoundChannel(); +/* if (format == 2) { + channel = 1; + } else { + channel = 0; + }*/ + + if (channel > 1) channel = 1; + + bytes &= ~7; // Multiple of 4 bytes! +// bytes += 4; + + SCHANNEL_CR(channel) = 0; + SCHANNEL_TIMER(channel) = SOUND_FREQ(sampleRate); + SCHANNEL_SOURCE(channel) = ((uint32) (data)); + SCHANNEL_LENGTH(channel) = ((bytes & 0x7FFFFFFF) >> 2); + SCHANNEL_REPEAT_POINT(channel) = 0; + + SCHANNEL_CR(channel + 2) = 0; + SCHANNEL_TIMER(channel + 2) = SOUND_FREQ(sampleRate); + SCHANNEL_SOURCE(channel + 2) = ((uint32) (data)); + SCHANNEL_LENGTH(channel + 2) = ((bytes & 0x7FFFFFFF) >> 2); + SCHANNEL_REPEAT_POINT(channel + 2) = 0; + + uint32 flags = SCHANNEL_ENABLE | SOUND_VOL(vol) | SOUND_PAN(pan); + + switch (format) { + case 1: { + flags |= SOUND_8BIT; + flags |= SOUND_REPEAT;// | (1 << 15); + break; + } + + case 0: { + flags |= SOUND_16BIT; + flags |= SOUND_REPEAT;// | (1 << 15); + break; + } + + case 2: { + flags |= SOUND_FORMAT_ADPCM; + flags |= SOUND_ONE_SHOT;// | (1 << 15); + + SCHANNEL_SOURCE(channel) = (unsigned int) IPC->adpcm.buffer[0]; + //bytes += 32; + SCHANNEL_LENGTH(channel) = (((bytes + 4) & 0x7FFFFFFF) >> 2); + + SCHANNEL_CR(channel + 1) = 0; + SCHANNEL_SOURCE(channel + 1) = (unsigned int) IPC->adpcm.buffer[0]; + SCHANNEL_LENGTH(channel + 1) = (((bytes + 4) & 0x7FFFFFFF) >> 2); + SCHANNEL_TIMER(channel + 1) = SOUND_FREQ(sampleRate); + SCHANNEL_REPEAT_POINT(channel + 1) = 0; + SCHANNEL_CR(channel + 1) = flags; + temp = bytes; + adpcmBufferNum = 0; + break; + } + } + + +// if (bytes & 0x80000000) { +// flags |= SOUND_REPEAT; +// } else { +// } + + + + + soundData = (vu8* ) data; + + SCHANNEL_CR(channel) = flags; + SCHANNEL_CR(channel + 2) = flags; + + + + if (channel == 0) { + for (volatile int i = 0; i < 16384 * 2; i++) { + // Delay loop - this makes everything stay in sync! + } + + TIMER0_CR = 0; + TIMER0_DATA = SOUND_FREQ(sampleRate) * 2; + TIMER0_CR = TIMER_ENABLE | TIMER_DIV_1; + + TIMER1_CR = 0; + TIMER1_DATA = 65536 - ((bytes & 0x7FFFFFFF) >> 3); // Trigger four times during the length of the buffer + TIMER1_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE; + + playingSection = 0; + } else { + for (volatile int i = 0; i < 16384 * 2; i++) { + // Delay loop - this makes everything stay in sync! + } + + TIMER2_CR = 0; + TIMER2_DATA = SOUND_FREQ(sampleRate) * 2; + TIMER2_CR = TIMER_ENABLE | TIMER_DIV_1; + + TIMER3_CR = 0; + TIMER3_DATA = 65536 - ((bytes & 0x7FFFFFFF) >> 3); // Trigger four times during the length of the buffer + TIMER3_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE; + + for (int r = 0; r < 4; r++) { +// IPC->streamFillNeeded[r] = true; + } + + IPC->streamPlayingSection = 0; + } + + + +// IPC->fillSoundFirstHalf = true; +// IPC->fillSoundSecondHalf = true; +// soundFirstHalf = true; + + REG_IME = IME_ENABLE; +} + +void stopSound(int chan) { + SCHANNEL_CR(chan) = 0; +} + +void DummyHandler() { + REG_IF = REG_IF; +} + +uint16 powerManagerWrite(uint32 command, u32 data, bool enable) { + + uint16 result; + SerialWaitBusy(); + + // Write the command and wait for it to complete + REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | (1 << 11); + REG_SPIDATA = command | 0x80; + SerialWaitBusy(); + + // Write the second command and clock in the data + REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz; + REG_SPIDATA = 0; + SerialWaitBusy(); + + result = REG_SPIDATA & 0xFF; + + + + // Write the command and wait for it to complete + REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | (1 << 11); + REG_SPIDATA = command; + SerialWaitBusy(); + + // Write the second command and clock in the data + REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz; + REG_SPIDATA = enable? (result | data): (result & ~data); + SerialWaitBusy(); +} + +/* +void performSleep() { + + powerManagerWrite(0, 0x30, true); + + // Here, I set up a dummy interrupt handler, then trigger all interrupts. + // These are just aknowledged by the handler without doing anything else. + // Why? Because without it the sleep mode will only happen once, and then + // never again. I got the idea from reading the MoonShell source. + IME = 0; + u32 irq = (u32) IRQ_HANDLER; + IRQ_HANDLER = DummyHandler; + IF = ~0; + IME = 1; + + + // Now save which interrupts are enabled, then set only the screens unfolding + // interrupt to be enabled, so that the first interrupt that happens is the + // one I want. + int saveInts = IE; + + + + IE = IRQ_TIMER0; // Screens unfolding interrupt + + // Now call the sleep function in the bios + bool b; + do { + TIMER0_CR = 0; + TIMER0_DATA = TIMER_FREQ(20); + TIMER0_CR = TIMER_ENABLE | TIMER_DIV_64; + + swiDelay(100); + + swiSleep(); + + swiDelay(100); + + powerManagerWrite(0, 0x30, b = !b); + } while (!(TIMER0_CR & TIMER_ENABLE)); + + TIMER0_CR = 0; + + // We're back from sleep, now restore the interrupt state and IRQ handler + IRQ_HANDLER = (void (*)()) irq; + IE = saveInts; + IF = ~0; + IME = 1; + + + + powerManagerWrite(0, 0x30, false); +} +*/ + + +void performSleep() { + powerManagerWrite(0, 0x30, true); + + IPC->performArm9SleepMode = true; // Tell ARM9 to sleep + +// u32 irq = (u32) IRQ_HANDLER; +// IRQ_HANDLER = DummyHandler; +// POWER_CR &= ~POWER_SOUND; + +// int saveInts = REG_IE; +// REG_IE = (1 << 22) | IRQ_VBLANK; // Lid open +// *((u32*) (0x0380FFF8)) = *((u32*) (0x0380FFF8)) | (REG_IE & REG_IF); +// VBLANK_INTR_WAIT_FLAGS = IRQ_VBLANK; + + + int r = 0; + while ((REG_KEYXY & (1 << 7))) { // Wait for lid to open + swiDelay(1000000); + r++; + } + +// IRQ_HANDLER = (void (*)()) irq; + IPC->performArm9SleepMode = false; // Tell ARM9 to wake up +// REG_IE = saveInts; + +// POWER_CR |= POWER_SOUND; + + powerManagerWrite(0, 0x30, false); +} + +////////////////////////////////////////////////////////////////////// + + +void InterruptHandler(void) { + static int heartbeat = 0; + + if (REG_IF & IRQ_TIMER1) { + + IPC->fillNeeded[playingSection] = true; + soundFilled[playingSection] = false; + + if (playingSection == 3) { +// IME = IME_DISABLED; + + // while (SCHANNEL_CR(0) & SCHANNEL_ENABLE) { + // } +// SCHANNEL_CR(0) &= ~SCHANNEL_ENABLE; + +// SCHANNEL_CR(0) |= SCHANNEL_ENABLE; +// TIMER1_CR = 0; +// TIMER1_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE; + + playingSection = 0; + +// IME = IME_ENABLED; + } else { + playingSection++; + } + + IPC->playingSection = playingSection; + +/* for (int r = 0; r < 4; r++) { + //if ((!soundFilled[r]) && (!IPC->fillNeeded[playingSection])) { + memcpy((void *) (soundBuffer + (r * 1024)), (void *) (arm9Buffer + (r * 1024)), 1024); + + vu16* p = (vu16 *) (soundBuffer); + //for (int t = 0; t < 2048; t++) { + // *(p + t) = (t & 1)? 0xF000: 0x0000; + //} + soundFilled[r] = true; + //} + }*/ + + + REG_IF = IRQ_TIMER1; + } + + + if (REG_IF & IRQ_TIMER3) { + while (IPC->adpcm.semaphore); // Wait for buffer to become free if needed + IPC->adpcm.semaphore = true; // Lock the buffer structure to prevent clashing with the ARM7 + + IPC->streamFillNeeded[IPC->streamPlayingSection] = true; + + if (IPC->streamPlayingSection == 3) { + IPC->streamPlayingSection = 0; + } else { + IPC->streamPlayingSection++; + } + + REG_IF = IRQ_TIMER3; + + IPC->adpcm.semaphore = false; + } + + +// IPC->performArm9SleepMode = false; + + // precalculate some values +// static int16 TOUCH_WIDTH = TOUCH_CAL_X2 - TOUCH_CAL_X1; +// static int16 TOUCH_HEIGHT = TOUCH_CAL_Y2 - TOUCH_CAL_Y1; +// static int16 CNTRL_WIDTH = TOUCH_CNTRL_X2 - (TOUCH_CNTRL_X1 - 8); +// static int16 CNTRL_HEIGHT = TOUCH_CNTRL_Y2 - (TOUCH_CNTRL_Y1 - 8); + + + + + + if (REG_IF & IRQ_VBLANK) { + uint16 but=0, x=0, y=0, xpx=0, ypx=0, z1=0, z2=0, batt=0, aux=0; + int t1=0, t2=0; + uint32 temp=0; + uint8 ct[sizeof(IPC->curtime)]; + + + // Update the heartbeat + heartbeat++; + + // Read the X/Y buttons and the /PENIRQ line + but = REG_KEYXY; + if (!(but & 0x40)) { + // Read the touch screen + touchPosition p = touchReadXY(); + +// x = touchRead(TSC_MEASURE_X); + // y = touchRead(TSC_MEASURE_Y); + + x = p.x; + y = p.y; + + xpx = p.px; + ypx = p.py; + +// xpx = ( ((SCREEN_WIDTH -60) * x) / TOUCH_WIDTH ) - TOUCH_OFFSET_X; + // ypx = ( ((SCREEN_HEIGHT-60) * y) / TOUCH_HEIGHT ) - TOUCH_OFFSET_Y; + +// xpx = (IPC->touchX - (int16) TOUCH_CAL_X1) * CNTRL_WIDTH / TOUCH_WIDTH + (int16) (TOUCH_CNTRL_X1 - 8); + // ypx = (IPC->touchY - (int16) TOUCH_CAL_Y1) * CNTRL_HEIGHT / TOUCH_HEIGHT + (int16) (TOUCH_CNTRL_Y1 - 8); + + + z1 = touchRead(TSC_MEASURE_Z1); + z2 = touchRead(TSC_MEASURE_Z2); + } + + if (but & (1 << 7)) { // Check if screen is folded + needSleep = true; + } + + + batt = touchRead(TSC_MEASURE_BATTERY); + aux = touchRead(TSC_MEASURE_AUX); + + // Read the time + rtcGetTime((uint8 *)ct); + BCDToInteger((uint8 *)&(ct[1]), 7); + + // Read the temperature + temp = touchReadTemperature(&t1, &t2); + + // Update the IPC struct + IPC->heartbeat = heartbeat; + IPC->buttons = but; + IPC->touchX = x; + IPC->touchY = y; + IPC->touchXpx = xpx; + IPC->touchYpx = ypx; + IPC->touchZ1 = z1; + IPC->touchZ2 = z2; + IPC->battery = batt; + IPC->aux = aux; + + for(u32 i=0; i<sizeof(ct); i++) { + IPC->curtime[i] = ct[i]; + } + + IPC->temperature = temp; + IPC->tdiode1 = t1; + IPC->tdiode2 = t2; + + + + //sound code :) + TransferSound *snd = IPC->soundData; + IPC->soundData = 0; + if (snd) { + for (int i=0; i<snd->count; i++) { + s8 chan = getFreeSoundChannel(); + if (snd->data[i].rate > 0) { + if (chan >= 0) { + startSound(snd->data[i].rate, snd->data[i].data, snd->data[i].len, chan, snd->data[i].vol, snd->data[i].pan, snd->data[i].format); + } + } else { + stopSound(-snd->data[i].rate); + } + } + } + + REG_IF = IRQ_VBLANK; + } + +} + + +////////////////////////////////////////////////////////////////////// + + +int main(int argc, char ** argv) { + // Reset the clock if needed + rtcReset(); + + //enable sound + powerON(POWER_SOUND); + SOUND_CR = SOUND_ENABLE | SOUND_VOL(0x7F); + IPC->soundData = 0; + IPC->reset = false; + + + for (int r = 0; r < 8; r++) { + IPC->adpcm.arm7Buffer[r] = (u8 *) malloc(512); + } + + for (int r = 0; r < 4; r++) { + soundFilled[r] = false; + } + + + // Set up the interrupt handler + REG_IME = 0; + IRQ_HANDLER = &InterruptHandler; + REG_IE = IRQ_VBLANK | IRQ_TIMER1 | IRQ_TIMER3; + REG_IF = ~0; + DISP_SR = DISP_VBLANK_IRQ; + REG_IME = 1; + + + + // Keep the ARM7 out of main RAM + while (1) { + if (needSleep) { + performSleep(); + needSleep = false; + } +// if (IPC->reset) { +// swiSoftReset(); +// } + } + return 0; +} + + +////////////////////////////////////////////////////////////////////// + +/* ScummVMDS - Scumm Interpreter DS Port + * Copyright (C) 2002-2004 The ScummVM project and Neil Millstone + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header: /cvsroot/scummvm/scummvm/backends/fs/fs.cpp,v 1.3.2.1 2004/12/18 02:33:52 fingolfin Exp $ + */ + +////////////////////////////////////////////////////////////////////// +// Simple ARM7 stub (sends RTC, TSC, and X/Y data to the ARM 9) +// -- joat +// -- modified by Darkain and others +////////////////////////////////////////////////////////////////////// + + +#include <nds.h> + +#include <bios.h> +#include <arm7/touch.h> +#include <arm7/clock.h> +#include <stdlib.h> +#include <string.h> + +#include <nds/scummvm_ipc.h> +////////////////////////////////////////////////////////////////////// + + +#define TOUCH_CAL_X1 (*(vs16*)0x027FFCD8) +#define TOUCH_CAL_Y1 (*(vs16*)0x027FFCDA) +#define TOUCH_CAL_X2 (*(vs16*)0x027FFCDE) +#define TOUCH_CAL_Y2 (*(vs16*)0x027FFCE0) +#define SCREEN_WIDTH 256 +#define SCREEN_HEIGHT 192 +s32 TOUCH_WIDTH = TOUCH_CAL_X2 - TOUCH_CAL_X1; +s32 TOUCH_HEIGHT = TOUCH_CAL_Y2 - TOUCH_CAL_Y1; +s32 TOUCH_OFFSET_X = ( ((SCREEN_WIDTH -60) * TOUCH_CAL_X1) / TOUCH_WIDTH ) - 28; +s32 TOUCH_OFFSET_Y = ( ((SCREEN_HEIGHT-60) * TOUCH_CAL_Y1) / TOUCH_HEIGHT ) - 28; + +vu8* soundData; + +vu8* soundBuffer; +vu8* arm9Buffer; +bool soundFilled[4]; + +int playingSection; + +bool needSleep = false; +int temp; + +int adpcmBufferNum = 0; + +// those are pixel positions of the two points you click when calibrating +#define TOUCH_CNTRL_X1 (*(vu8*)0x027FFCDC) +#define TOUCH_CNTRL_Y1 (*(vu8*)0x027FFCDD) +#define TOUCH_CNTRL_X2 (*(vu8*)0x027FFCE2) +#define TOUCH_CNTRL_Y2 (*(vu8*)0x027FFCE3) + + +////////////////////////////////////////////////////////////////////// + +/* +void startSound(int sampleRate, const void* data, uint32 bytes, u8 channel=0, u8 vol=0x7F, u8 pan=63, u8 format=0) { + SCHANNEL_TIMER(channel) = SOUND_FREQ(sampleRate); + SCHANNEL_SOURCE(channel) = (uint32)data; + SCHANNEL_LENGTH(channel) = bytes; + SCHANNEL_CR(channel) = SOUND_ENABLE | SOUND_ONE_SHOT | SOUND_VOL(vol) | SOUND_PAN(pan) | (format==1?SOUND_8BIT:SOUND_16BIT); +} + + +s8 getFreeSoundChannel() { + for (int i=0; i<16; i++) { + if ( (SCHANNEL_CR(i) & SOUND_ENABLE) == 0 ) return i; + } + return -1; +} +*/ + + +s8 getFreeSoundChannel() { +// return 0; + for (int i=0; i<16; i++) { + if ( (SCHANNEL_CR(i) & SCHANNEL_ENABLE) == 0 ) return i; + } + return -1; +} + +void startSound(int sampleRate, const void* data, uint32 bytes, u8 channel=0, u8 vol=0x7F, u8 pan=63, u8 format=0) { + REG_IME = IME_DISABLE; + + channel = getFreeSoundChannel(); +/* if (format == 2) { + channel = 1; + } else { + channel = 0; + }*/ + + if (channel > 1) channel = 1; + + bytes &= ~7; // Multiple of 4 bytes! +// bytes += 4; + + SCHANNEL_CR(channel) = 0; + SCHANNEL_TIMER(channel) = SOUND_FREQ(sampleRate); + SCHANNEL_SOURCE(channel) = ((uint32) (data)); + SCHANNEL_LENGTH(channel) = ((bytes & 0x7FFFFFFF) >> 2); + SCHANNEL_REPEAT_POINT(channel) = 0; + + SCHANNEL_CR(channel + 2) = 0; + SCHANNEL_TIMER(channel + 2) = SOUND_FREQ(sampleRate); + SCHANNEL_SOURCE(channel + 2) = ((uint32) (data)); + SCHANNEL_LENGTH(channel + 2) = ((bytes & 0x7FFFFFFF) >> 2); + SCHANNEL_REPEAT_POINT(channel + 2) = 0; + + uint32 flags = SCHANNEL_ENABLE | SOUND_VOL(vol) | SOUND_PAN(pan); + + switch (format) { + case 1: { + flags |= SOUND_8BIT; + flags |= SOUND_REPEAT;// | (1 << 15); + break; + } + + case 0: { + flags |= SOUND_16BIT; + flags |= SOUND_REPEAT;// | (1 << 15); + break; + } + + case 2: { + flags |= SOUND_FORMAT_ADPCM; + flags |= SOUND_ONE_SHOT;// | (1 << 15); + + SCHANNEL_SOURCE(channel) = (unsigned int) IPC->adpcm.buffer[0]; + //bytes += 32; + SCHANNEL_LENGTH(channel) = (((bytes + 4) & 0x7FFFFFFF) >> 2); + + SCHANNEL_CR(channel + 1) = 0; + SCHANNEL_SOURCE(channel + 1) = (unsigned int) IPC->adpcm.buffer[0]; + SCHANNEL_LENGTH(channel + 1) = (((bytes + 4) & 0x7FFFFFFF) >> 2); + SCHANNEL_TIMER(channel + 1) = SOUND_FREQ(sampleRate); + SCHANNEL_REPEAT_POINT(channel + 1) = 0; + SCHANNEL_CR(channel + 1) = flags; + temp = bytes; + adpcmBufferNum = 0; + break; + } + } + + +// if (bytes & 0x80000000) { +// flags |= SOUND_REPEAT; +// } else { +// } + + + + + soundData = (vu8* ) data; + + SCHANNEL_CR(channel) = flags; + SCHANNEL_CR(channel + 2) = flags; + + + + if (channel == 0) { + for (volatile int i = 0; i < 16384 * 2; i++) { + // Delay loop - this makes everything stay in sync! + } + + TIMER0_CR = 0; + TIMER0_DATA = SOUND_FREQ(sampleRate) * 2; + TIMER0_CR = TIMER_ENABLE | TIMER_DIV_1; + + TIMER1_CR = 0; + TIMER1_DATA = 65536 - ((bytes & 0x7FFFFFFF) >> 3); // Trigger four times during the length of the buffer + TIMER1_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE; + + playingSection = 0; + } else { + for (volatile int i = 0; i < 16384 * 2; i++) { + // Delay loop - this makes everything stay in sync! + } + + TIMER2_CR = 0; + TIMER2_DATA = SOUND_FREQ(sampleRate) * 2; + TIMER2_CR = TIMER_ENABLE | TIMER_DIV_1; + + TIMER3_CR = 0; + TIMER3_DATA = 65536 - ((bytes & 0x7FFFFFFF) >> 3); // Trigger four times during the length of the buffer + TIMER3_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE; + + for (int r = 0; r < 4; r++) { +// IPC->streamFillNeeded[r] = true; + } + + IPC->streamPlayingSection = 0; + } + + + +// IPC->fillSoundFirstHalf = true; +// IPC->fillSoundSecondHalf = true; +// soundFirstHalf = true; + + REG_IME = IME_ENABLE; +} + +void stopSound(int chan) { + SCHANNEL_CR(chan) = 0; +} + +void DummyHandler() { + REG_IF = REG_IF; +} + +uint16 powerManagerWrite(uint32 command, u32 data, bool enable) { + + uint16 result; + SerialWaitBusy(); + + // Write the command and wait for it to complete + REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | (1 << 11); + REG_SPIDATA = command | 0x80; + SerialWaitBusy(); + + // Write the second command and clock in the data + REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz; + REG_SPIDATA = 0; + SerialWaitBusy(); + + result = REG_SPIDATA & 0xFF; + + + + // Write the command and wait for it to complete + REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz | (1 << 11); + REG_SPIDATA = command; + SerialWaitBusy(); + + // Write the second command and clock in the data + REG_SPICNT = SPI_ENABLE | SPI_BAUD_1MHz; + REG_SPIDATA = enable? (result | data): (result & ~data); + SerialWaitBusy(); +} + +/* +void performSleep() { + + powerManagerWrite(0, 0x30, true); + + // Here, I set up a dummy interrupt handler, then trigger all interrupts. + // These are just aknowledged by the handler without doing anything else. + // Why? Because without it the sleep mode will only happen once, and then + // never again. I got the idea from reading the MoonShell source. + IME = 0; + u32 irq = (u32) IRQ_HANDLER; + IRQ_HANDLER = DummyHandler; + IF = ~0; + IME = 1; + + + // Now save which interrupts are enabled, then set only the screens unfolding + // interrupt to be enabled, so that the first interrupt that happens is the + // one I want. + int saveInts = IE; + + + + IE = IRQ_TIMER0; // Screens unfolding interrupt + + // Now call the sleep function in the bios + bool b; + do { + TIMER0_CR = 0; + TIMER0_DATA = TIMER_FREQ(20); + TIMER0_CR = TIMER_ENABLE | TIMER_DIV_64; + + swiDelay(100); + + swiSleep(); + + swiDelay(100); + + powerManagerWrite(0, 0x30, b = !b); + } while (!(TIMER0_CR & TIMER_ENABLE)); + + TIMER0_CR = 0; + + // We're back from sleep, now restore the interrupt state and IRQ handler + IRQ_HANDLER = (void (*)()) irq; + IE = saveInts; + IF = ~0; + IME = 1; + + + + powerManagerWrite(0, 0x30, false); +} +*/ + + +void performSleep() { + powerManagerWrite(0, 0x30, true); + + IPC->performArm9SleepMode = true; // Tell ARM9 to sleep + +// u32 irq = (u32) IRQ_HANDLER; +// IRQ_HANDLER = DummyHandler; +// POWER_CR &= ~POWER_SOUND; + +// int saveInts = REG_IE; +// REG_IE = (1 << 22) | IRQ_VBLANK; // Lid open +// *((u32*) (0x0380FFF8)) = *((u32*) (0x0380FFF8)) | (REG_IE & REG_IF); +// VBLANK_INTR_WAIT_FLAGS = IRQ_VBLANK; + + + int r = 0; + while ((REG_KEYXY & (1 << 7))) { // Wait for lid to open + swiDelay(1000000); + r++; + } + +// IRQ_HANDLER = (void (*)()) irq; + IPC->performArm9SleepMode = false; // Tell ARM9 to wake up +// REG_IE = saveInts; + +// POWER_CR |= POWER_SOUND; + + powerManagerWrite(0, 0x30, false); +} + +////////////////////////////////////////////////////////////////////// + + +void InterruptHandler(void) { + static int heartbeat = 0; + + if (REG_IF & IRQ_TIMER1) { + + IPC->fillNeeded[playingSection] = true; + soundFilled[playingSection] = false; + + if (playingSection == 3) { +// IME = IME_DISABLED; + + // while (SCHANNEL_CR(0) & SCHANNEL_ENABLE) { + // } +// SCHANNEL_CR(0) &= ~SCHANNEL_ENABLE; + +// SCHANNEL_CR(0) |= SCHANNEL_ENABLE; +// TIMER1_CR = 0; +// TIMER1_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_CASCADE; + + playingSection = 0; + +// IME = IME_ENABLED; + } else { + playingSection++; + } + + IPC->playingSection = playingSection; + +/* for (int r = 0; r < 4; r++) { + //if ((!soundFilled[r]) && (!IPC->fillNeeded[playingSection])) { + memcpy((void *) (soundBuffer + (r * 1024)), (void *) (arm9Buffer + (r * 1024)), 1024); + + vu16* p = (vu16 *) (soundBuffer); + //for (int t = 0; t < 2048; t++) { + // *(p + t) = (t & 1)? 0xF000: 0x0000; + //} + soundFilled[r] = true; + //} + }*/ + + + REG_IF = IRQ_TIMER1; + } + + + if (REG_IF & IRQ_TIMER3) { + while (IPC->adpcm.semaphore); // Wait for buffer to become free if needed + IPC->adpcm.semaphore = true; // Lock the buffer structure to prevent clashing with the ARM7 + + IPC->streamFillNeeded[IPC->streamPlayingSection] = true; + + if (IPC->streamPlayingSection == 3) { + IPC->streamPlayingSection = 0; + } else { + IPC->streamPlayingSection++; + } + + REG_IF = IRQ_TIMER3; + + IPC->adpcm.semaphore = false; + } + + +// IPC->performArm9SleepMode = false; + + // precalculate some values +// static int16 TOUCH_WIDTH = TOUCH_CAL_X2 - TOUCH_CAL_X1; +// static int16 TOUCH_HEIGHT = TOUCH_CAL_Y2 - TOUCH_CAL_Y1; +// static int16 CNTRL_WIDTH = TOUCH_CNTRL_X2 - (TOUCH_CNTRL_X1 - 8); +// static int16 CNTRL_HEIGHT = TOUCH_CNTRL_Y2 - (TOUCH_CNTRL_Y1 - 8); + + + + + + if (REG_IF & IRQ_VBLANK) { + uint16 but=0, x=0, y=0, xpx=0, ypx=0, z1=0, z2=0, batt=0, aux=0; + int t1=0, t2=0; + uint32 temp=0; + uint8 ct[sizeof(IPC->curtime)]; + + + // Update the heartbeat + heartbeat++; + + // Read the X/Y buttons and the /PENIRQ line + but = REG_KEYXY; + if (!(but & 0x40)) { + // Read the touch screen + touchPosition p = touchReadXY(); + +// x = touchRead(TSC_MEASURE_X); + // y = touchRead(TSC_MEASURE_Y); + + x = p.x; + y = p.y; + + xpx = p.px; + ypx = p.py; + +// xpx = ( ((SCREEN_WIDTH -60) * x) / TOUCH_WIDTH ) - TOUCH_OFFSET_X; + // ypx = ( ((SCREEN_HEIGHT-60) * y) / TOUCH_HEIGHT ) - TOUCH_OFFSET_Y; + +// xpx = (IPC->touchX - (int16) TOUCH_CAL_X1) * CNTRL_WIDTH / TOUCH_WIDTH + (int16) (TOUCH_CNTRL_X1 - 8); + // ypx = (IPC->touchY - (int16) TOUCH_CAL_Y1) * CNTRL_HEIGHT / TOUCH_HEIGHT + (int16) (TOUCH_CNTRL_Y1 - 8); + + + z1 = touchRead(TSC_MEASURE_Z1); + z2 = touchRead(TSC_MEASURE_Z2); + } + + if (but & (1 << 7)) { // Check if screen is folded + needSleep = true; + } + + + batt = touchRead(TSC_MEASURE_BATTERY); + aux = touchRead(TSC_MEASURE_AUX); + + // Read the time + rtcGetTime((uint8 *)ct); + BCDToInteger((uint8 *)&(ct[1]), 7); + + // Read the temperature + temp = touchReadTemperature(&t1, &t2); + + // Update the IPC struct + IPC->heartbeat = heartbeat; + IPC->buttons = but; + IPC->touchX = x; + IPC->touchY = y; + IPC->touchXpx = xpx; + IPC->touchYpx = ypx; + IPC->touchZ1 = z1; + IPC->touchZ2 = z2; + IPC->battery = batt; + IPC->aux = aux; + + for(u32 i=0; i<sizeof(ct); i++) { + IPC->curtime[i] = ct[i]; + } + + IPC->temperature = temp; + IPC->tdiode1 = t1; + IPC->tdiode2 = t2; + + + + //sound code :) + TransferSound *snd = IPC->soundData; + IPC->soundData = 0; + if (snd) { + for (int i=0; i<snd->count; i++) { + s8 chan = getFreeSoundChannel(); + if (snd->data[i].rate > 0) { + if (chan >= 0) { + startSound(snd->data[i].rate, snd->data[i].data, snd->data[i].len, chan, snd->data[i].vol, snd->data[i].pan, snd->data[i].format); + } + } else { + stopSound(-snd->data[i].rate); + } + } + } + + REG_IF = IRQ_VBLANK; + } + +} + + +////////////////////////////////////////////////////////////////////// + + +int main(int argc, char ** argv) { + // Reset the clock if needed + rtcReset(); + + //enable sound + powerON(POWER_SOUND); + SOUND_CR = SOUND_ENABLE | SOUND_VOL(0x7F); + IPC->soundData = 0; + IPC->reset = false; + + + for (int r = 0; r < 8; r++) { + IPC->adpcm.arm7Buffer[r] = (u8 *) malloc(512); + } + + for (int r = 0; r < 4; r++) { + soundFilled[r] = false; + } + + + // Set up the interrupt handler + REG_IME = 0; + IRQ_HANDLER = &InterruptHandler; + REG_IE = IRQ_VBLANK | IRQ_TIMER1 | IRQ_TIMER3; + REG_IF = ~0; + DISP_SR = DISP_VBLANK_IRQ; + REG_IME = 1; + + + + // Keep the ARM7 out of main RAM + while (1) { + if (needSleep) { + performSleep(); + needSleep = false; + } +// if (IPC->reset) { +// swiSoftReset(); +// } + } + return 0; +} + + +////////////////////////////////////////////////////////////////////// + |