21 Commits

Author SHA1 Message Date
9a0e3be4fe game counter reset 2024-05-21 14:21:35 +02:00
2827046b8b more configuration 2024-05-21 13:43:40 +02:00
faf75e158a sound volume configurable 2024-05-21 12:31:55 +02:00
f9b63c06fe another fix 2024-05-19 22:08:11 +02:00
1cbba5c8b3 fix 2024-05-19 22:06:21 +02:00
ebb0f5846d better way to clear config in case of invalid magic 2024-05-19 22:00:59 +02:00
1beb7ef04a code beautified 2024-05-19 21:57:46 +02:00
70467cf2a7 also random very first stone 2024-05-19 21:53:57 +02:00
d9769c6b28 other button to start config mode 2024-05-19 21:47:31 +02:00
d9fd18d799 color cleanup and brightness 2024-05-19 21:42:39 +02:00
7894359f30 flashcolor and highscore config done 2024-05-19 20:46:00 +02:00
4cb0a10617 colors 2024-05-18 23:11:00 +02:00
a92a3beb96 more colors 2024-05-18 20:38:54 +02:00
ccd395d6ab config 2024-05-18 20:09:21 +02:00
eb75e31577 different flash 2024-05-18 12:08:18 +02:00
ba4248ff24 flash 2024-05-17 16:08:10 +02:00
2cc5a6a4f3 changes 2024-05-05 21:48:20 +02:00
5c86d55458 dark mode 2024-05-05 17:24:29 +02:00
b9e5813223 flash 2024-05-04 12:58:02 +02:00
1b4a93d9e1 types bigger 2024-05-04 11:35:29 +02:00
30d50dcc5e seems to work but some unpleasant delays 2024-05-04 11:31:27 +02:00
29 changed files with 548 additions and 137 deletions

View File

@ -11,7 +11,7 @@ CFLAGS=-Wall -mmcu=$(MCU) -std=gnu99 -I $(TOOLCHAIN_PREFIX)/include -O1 -g0
LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include
$(ARTIFACT).elf: main.o spi.o scheduler.o canvas.o shapes.o game.o buttons.o myrand.o display.o sound.o eeprom.o $(ARTIFACT).elf: main.o spi.o scheduler.o canvas.o shapes.o game.o buttons.o myrand.o display.o sound.o eeprom.o config.o
$(CC) -o $@ $(LDFLAGS) $^ $(CC) -o $@ $(LDFLAGS) $^
$(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt $(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt

View File

@ -8,6 +8,7 @@
#include "shapes.h" #include "shapes.h"
#include "canvas.h" #include "canvas.h"
#include "sound.h" #include "sound.h"
#include "eeprom.h"
bool mutedFlag = true; bool mutedFlag = true;
@ -20,6 +21,10 @@ static uint8_t buttonsMoveLeftPressed() {
return res; return res;
} }
bool buttonsConfig1Pressed() {
return buttonsMoveLeftPressed();
}
static uint8_t buttonsMoveRightPressed() { static uint8_t buttonsMoveRightPressed() {
static uint8_t last = 0; static uint8_t last = 0;
uint8_t current = (P2IN & BIT0); uint8_t current = (P2IN & BIT0);
@ -28,6 +33,10 @@ static uint8_t buttonsMoveRightPressed() {
return res; return res;
} }
bool buttonsConfig4Pressed() {
return buttonsMoveRightPressed();
}
static uint8_t buttonsRotateLeftPressed() { static uint8_t buttonsRotateLeftPressed() {
static uint8_t last = 0; static uint8_t last = 0;
uint8_t current = (P2IN & BIT3); uint8_t current = (P2IN & BIT3);
@ -36,6 +45,10 @@ static uint8_t buttonsRotateLeftPressed() {
return res; return res;
} }
bool buttonsConfig2Pressed() {
return buttonsRotateLeftPressed();
}
static uint8_t buttonsRotateRightPressed() { static uint8_t buttonsRotateRightPressed() {
static uint8_t last = 0; static uint8_t last = 0;
uint8_t current = (P2IN & BIT1); uint8_t current = (P2IN & BIT1);
@ -44,10 +57,20 @@ static uint8_t buttonsRotateRightPressed() {
return res; return res;
} }
bool buttonsConfig3Pressed() {
return buttonsRotateRightPressed();
}
static uint8_t buttonsMoveDownPressed() { static uint8_t buttonsMoveDownPressed() {
return P2IN & BIT2; return P2IN & BIT2;
} }
bool isConfigMode() {
return (P2IN & BIT2);
}
void buttonsExec(void *handle) { void buttonsExec(void *handle) {
static uint32_t unmuteTimestamp; static uint32_t unmuteTimestamp;
uint32_t currentTimestamp = getSeconds(); uint32_t currentTimestamp = getSeconds();
@ -62,27 +85,22 @@ void buttonsExec(void *handle) {
if (buttonsMoveLeftPressed()) { if (buttonsMoveLeftPressed()) {
stoneMoveLeft(); stoneMoveLeft();
soundCtrl(SOUND_MOTION);
buttonPressed = 1; buttonPressed = 1;
} }
if (buttonsMoveRightPressed()) { if (buttonsMoveRightPressed()) {
stoneMoveRight(); stoneMoveRight();
soundCtrl(SOUND_MOTION);
buttonPressed = 1; buttonPressed = 1;
} }
if (buttonsRotateLeftPressed()) { if (buttonsRotateLeftPressed()) {
stoneRotateLeft(); stoneRotateLeft();
soundCtrl(SOUND_MOTION);
buttonPressed = 1; buttonPressed = 1;
} }
if (buttonsRotateRightPressed()) { if (buttonsRotateRightPressed()) {
stoneRotateRight(); stoneRotateRight();
soundCtrl(SOUND_MOTION);
buttonPressed = 1; buttonPressed = 1;
} }
if (buttonsMoveDownPressed()) { if (buttonsMoveDownPressed()) {
stoneMoveDown(); stoneMoveDown();
soundCtrl(SOUND_MOTION);
buttonPressed = 1; buttonPressed = 1;
} }
@ -90,6 +108,7 @@ void buttonsExec(void *handle) {
canvasShow(); canvasShow();
if (mutedFlag) { if (mutedFlag) {
eepromIncGameCounter();
soundCtrl(SOUND_UNMUTE); soundCtrl(SOUND_UNMUTE);
mutedFlag = false; mutedFlag = false;
} }
@ -104,7 +123,9 @@ void buttonsExec(void *handle) {
void buttonsInit() { void buttonsInit() {
P2DIR &= ~(BIT0|BIT1|BIT2|BIT3|BIT4); P2DIR &= ~(BIT0|BIT1|BIT2|BIT3|BIT4);
}
void buttonsStart() {
schAdd(buttonsExec, NULL, 0, 25); schAdd(buttonsExec, NULL, 0, 25);
} }

View File

@ -4,7 +4,13 @@
#include <stdbool.h> #include <stdbool.h>
void buttonsInit(); void buttonsInit();
void buttonsStart();
bool isGameActive(); bool isGameActive();
bool isConfigMode();
bool buttonsConfig1Pressed();
bool buttonsConfig2Pressed();
bool buttonsConfig3Pressed();
bool buttonsConfig4Pressed();
#endif // _BUTTONS_H_ #endif // _BUTTONS_H_

View File

@ -5,6 +5,8 @@
#include "canvas.h" #include "canvas.h"
#include "spi.h" #include "spi.h"
#include "eeprom.h"
#include "../rgb-driver/colors.h"
static uint8_t canvasStorage[CANVAS_WIDTH * CANVAS_HEIGHT]; static uint8_t canvasStorage[CANVAS_WIDTH * CANVAS_HEIGHT];
@ -22,6 +24,8 @@ const canvas_t miniCanvas = {
}; };
void canvasShow() { void canvasShow() {
uint8_t brightness_offset = _brightness_offset * eepromReadBrightness();
// wait for signal waiting for data // wait for signal waiting for data
while (!(P1IN & BIT3)); while (!(P1IN & BIT3));
@ -31,14 +35,14 @@ void canvasShow() {
if ((*((canvas.canvas)+i) & 0x80) != 0) { if ((*((canvas.canvas)+i) & 0x80) != 0) {
*((canvas.canvas)+i) &= ~0x80; *((canvas.canvas)+i) &= ~0x80;
spiSendOctet(i); spiSendOctet(i);
spiSendOctet(*((canvas.canvas)+i)); spiSendOctet((*((canvas.canvas)+i) == 0) ? 0 : (*((canvas.canvas)+i) + brightness_offset));
} }
} }
for (uint8_t i = 0; i < (MINI_CANVAS_WIDTH*MINI_CANVAS_HEIGHT); i++) { for (uint8_t i = 0; i < (MINI_CANVAS_WIDTH*MINI_CANVAS_HEIGHT); i++) {
if ((*((miniCanvas.canvas)+i) & 0x80) != 0) { if ((*((miniCanvas.canvas)+i) & 0x80) != 0) {
*((miniCanvas.canvas)+i) &= ~0x80; *((miniCanvas.canvas)+i) &= ~0x80;
spiSendOctet(i + (CANVAS_HEIGHT*CANVAS_WIDTH)); spiSendOctet(i + (CANVAS_HEIGHT*CANVAS_WIDTH));
spiSendOctet(*((miniCanvas.canvas)+i)); spiSendOctet((*((miniCanvas.canvas)+i) == 0) ? 0 : (*((miniCanvas.canvas)+i) + brightness_offset));
} }
} }
spiSendOctet(0xfe); spiSendOctet(0xfe);

135
game-ctrl/config.c Normal file
View File

@ -0,0 +1,135 @@
#include <stddef.h>
#include "config.h"
#include "canvas.h"
#include "../rgb-driver/colors.h"
#include "scheduler.h"
#include "buttons.h"
#include "eeprom.h"
#include "display.h"
#include "shapes.h"
#include "sound.h"
static bool configChanged = false;
static bool muted = false;
static void configHandleFlash() {
uint8_t color = eepromReadFlashColor();
canvasFillRow(CANVAS_HEIGHT-1, color);
displaySetValue(color);
if (buttonsConfig2Pressed()) {
configChanged = true;
color += 1;
if (color > _color_end) {
color = 0;
}
eepromSetFlashColor(color);
}
}
static void configHandleResetHighScore() {
displaySetValue(eepromReadHighScore());
if (buttonsConfig2Pressed()) {
configChanged = true;
eepromSetHighScore(0);
}
}
static void configHandleResetGameCounter() {
displaySetValue(eepromReadGameCounter());
if (buttonsConfig2Pressed()) {
configChanged = true;
eepromClearGameCounter(0);
}
}
static void configHandleBrightness() {
displaySetValue(eepromReadBrightness());
stoneDrawConfigPattern();
if (buttonsConfig2Pressed()) {
configChanged = true;
uint8_t brightness = eepromReadBrightness() + 1;
if (brightness > _brightness_shifts) {
brightness = 0;
}
eepromSetBrightness(brightness);
}
}
static void configHandleAmplitude() {
displaySetValue(eepromReadAmplitude());
if (muted) {
muted = false;
soundCtrl(SOUND_START);
soundCtrl(SOUND_UNMUTE);
}
if (buttonsConfig2Pressed()) {
configChanged = true;
uint8_t amplitude = eepromReadAmplitude() + 1;
if (amplitude > 15) {
amplitude = 0;
}
eepromSetAmplitude(amplitude);
soundCtrl(SOUND_COMMAND + SOUND_SUBCMD_AMPLITUDE + amplitude);
}
}
void (*configHandler[])(void) = {
configHandleResetHighScore,
configHandleResetGameCounter,
configHandleFlash,
configHandleBrightness,
configHandleAmplitude
};
void configExec(void *handle) {
static uint8_t configState = 0;
static uint8_t lastConfigState = 255;
if (configState != lastConfigState) {
lastConfigState = configState;
miniCanvasClear();
canvasClear();
if (! muted) {
muted = true;
soundCtrl(SOUND_MUTE);
}
uint8_t row = configState / 3;
uint8_t column = configState % 3;
miniCanvasSetPixel(column, row, _red);
}
if (buttonsConfig1Pressed()) {
configState += 1;
if (configState >= sizeof(configHandler) / sizeof(configHandler[0])) {
configState = 0;
}
}
configHandler[configState]();
if (configChanged) {
miniCanvasSetPixel(0, 3, _red);
if (buttonsConfig4Pressed()) {
eepromCommit();
configChanged = false;
}
} else {
miniCanvasSetPixel(0, 3, _green);
}
canvasShow();
}
void configInit() {
schAdd(configExec, NULL, 0, 100);
}

8
game-ctrl/config.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
void configInit();
#endif // _CONFIG_H_

View File

@ -1,9 +1,15 @@
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include <sys/param.h>
#include "eeprom.h" #include "eeprom.h"
#include "spi.h" #include "spi.h"
#include "scheduler.h"
#include "display.h"
#include "canvas.h"
#include "../rgb-driver/colors.h"
#define MAGIC 0xaffe #define MAGIC 0xb003
#define HIGHSCORE_ADDR 0x00 #define HIGHSCORE_ADDR 0x00
#define DUMMY 0x00 #define DUMMY 0x00
#define CMD_READ 0b00000011 #define CMD_READ 0b00000011
@ -12,12 +18,18 @@
#define CMD_WREN 0b00000110 #define CMD_WREN 0b00000110
typedef struct {
uint16_t magic;
uint16_t highScore;
uint16_t gameCounter;
uint8_t flashColor;
uint8_t brightness;
uint8_t amplitude;
} t_configBlock;
typedef union { typedef union {
uint8_t buffer[4]; t_configBlock v;
struct { uint8_t buffer[sizeof(t_configBlock)];
uint16_t magic;
uint16_t highScore;
} v;
} eepromBuf_t; } eepromBuf_t;
eepromBuf_t buf; eepromBuf_t buf;
@ -30,10 +42,9 @@ static void writeBuf() {
spiSendBegin(e_SPI_EEPROM); spiSendBegin(e_SPI_EEPROM);
spiSendOctet(CMD_WRITE); spiSendOctet(CMD_WRITE);
spiSendOctet(HIGHSCORE_ADDR); spiSendOctet(HIGHSCORE_ADDR);
spiSendOctet(buf.buffer[0]); for (uint8_t i = 0; i < sizeof(t_configBlock); i++) {
spiSendOctet(buf.buffer[1]); spiSendOctet(buf.buffer[i]);
spiSendOctet(buf.buffer[2]); }
spiSendOctet(buf.buffer[3]);
spiSendEnd(e_SPI_EEPROM); spiSendEnd(e_SPI_EEPROM);
} }
@ -43,14 +54,10 @@ static void readBuf() {
spiReceiveOctet(); spiReceiveOctet();
spiSendOctet(HIGHSCORE_ADDR); spiSendOctet(HIGHSCORE_ADDR);
spiReceiveOctet(); spiReceiveOctet();
spiSendOctet(DUMMY); for (uint8_t i = 0; i < sizeof(t_configBlock); i++) {
buf.buffer[0] = spiReceiveOctet(); spiSendOctet(DUMMY);
spiSendOctet(DUMMY); buf.buffer[i] = spiReceiveOctet();
buf.buffer[1] = spiReceiveOctet(); }
spiSendOctet(DUMMY);
buf.buffer[2] = spiReceiveOctet();
spiSendOctet(DUMMY);
buf.buffer[3] = spiReceiveOctet();
spiSendEnd(e_SPI_EEPROM); spiSendEnd(e_SPI_EEPROM);
} }
@ -58,18 +65,89 @@ void eepromInit() {
readBuf(); readBuf();
if (buf.v.magic != MAGIC) { if (buf.v.magic != MAGIC) {
memset(buf.buffer, 0, sizeof(t_configBlock));
buf.v.magic = MAGIC; buf.v.magic = MAGIC;
buf.v.highScore = 0;
writeBuf(); writeBuf();
} }
} }
void eepromCommit() {
writeBuf();
}
void eepromShowValues() {
canvasClear();
canvasFillRow(0, _green);
canvasShow();
displaySetValue(buf.v.highScore);
wait(2);
canvasClear();
canvasFillRow(1, _green);
canvasShow();
displaySetValue(MIN(buf.v.gameCounter, 9999));
wait(2);
canvasClear();
canvasFillRow(2, _green);
canvasShow();
displaySetValue(buf.v.flashColor);
wait(2);
canvasClear();
canvasFillRow(3, _green);
canvasShow();
displaySetValue(buf.v.brightness);
wait(2);
canvasClear();
canvasFillRow(4, _green);
canvasShow();
displaySetValue(buf.v.amplitude);
wait(2);
}
uint16_t eepromReadHighScore() { uint16_t eepromReadHighScore() {
return buf.v.highScore; return buf.v.highScore;
} }
void eepromWriteHighScore(uint16_t v) { void eepromSetHighScore(uint16_t v) {
buf.v.highScore = v; buf.v.highScore = v;
writeBuf(); writeBuf();
} }
uint8_t eepromReadFlashColor() {
return buf.v.flashColor;
}
void eepromSetFlashColor(uint8_t v) {
buf.v.flashColor = v;
}
uint8_t eepromReadBrightness() {
return buf.v.brightness;
}
void eepromSetBrightness(uint8_t v) {
buf.v.brightness = v;
}
uint8_t eepromReadAmplitude() {
return buf.v.amplitude;
}
void eepromSetAmplitude(uint8_t v) {
buf.v.amplitude = v;
}
uint16_t eepromReadGameCounter() {
return buf.v.gameCounter;
}
void eepromIncGameCounter() {
buf.v.gameCounter += 1;
writeBuf();
}
void eepromClearGameCounter() {
buf.v.gameCounter = 0;
}

View File

@ -5,8 +5,19 @@
void eepromInit(); void eepromInit();
void eepromCommit();
void eepromShowValues();
uint16_t eepromReadHighScore(); uint16_t eepromReadHighScore();
void eepromWriteHighScore(uint16_t v); void eepromSetHighScore(uint16_t v);
uint8_t eepromReadFlashColor();
void eepromSetFlashColor(uint8_t v);
uint8_t eepromReadBrightness();
void eepromSetBrightness(uint8_t v);
uint8_t eepromReadAmplitude();
void eepromSetAmplitude(uint8_t v);
void eepromIncGameCounter();
uint16_t eepromReadGameCounter();
void eepromClearGameCounter();

View File

@ -1,3 +1,5 @@
// #define STATE_DEBUGGING
#include "stddef.h" #include "stddef.h"
#include "stdint.h" #include "stdint.h"
@ -12,34 +14,46 @@
#include "buttons.h" #include "buttons.h"
#define GAME_CYCLE_TIME 50 #define GAME_CYCLE_TIME 10
#define GAMEOVER_DELAY 10 #define GAMEOVER_DELAY 10
#define MAX_LEVEL 20 #define MAX_LEVEL 100
static uint8_t delayFactor(uint8_t level) { static uint16_t delayFactor(uint16_t level) {
return MAX_LEVEL + 1 - level; return MAX_LEVEL + 1 - level;
} }
typedef enum { typedef enum {
e_Start, e_NewStone, e_Down, e_DownDelay, e_ClearRows, e_BootWait,
e_Start, e_NewStone, e_Down, e_DownDelay,
e_ClearRowInit, e_ClearRowNext, e_ClearRowCheck, e_ClearRowFlash, e_ClearRowFlashDelay, e_ClearRowWipe,
e_GameOver, e_GameOverFill, e_GameOverWipe, e_GameOverDelay e_GameOver, e_GameOverFill, e_GameOverWipe, e_GameOverDelay
} state_t; } state_t;
void gameExec(void *handle) { void gameExec(void *handle) {
static state_t state = e_Start; static state_t state = e_BootWait;
static uint16_t bootWaitTime = 2500 / GAME_CYCLE_TIME;
static uint8_t gameOverDelay; static uint8_t gameOverDelay;
static uint8_t rowIndex; static uint8_t rowIndex;
static uint8_t proceedDelay; static uint16_t proceedDelay;
static uint8_t level; static uint16_t level;
static uint16_t filledLines; static uint16_t filledLines;
static uint16_t score; static uint16_t score;
static bool newHighScoreAchieved; static bool newHighScoreAchieved;
bool wipedLines = false; static uint8_t clearCheckCnt;
#ifdef STATE_DEBUGGING
displaySetValue(state);
#endif
// --- engine begin ------------------------------------------------------- // --- engine begin -------------------------------------------------------
switch (state) { switch (state) {
case e_BootWait:
bootWaitTime -= 1;
if (bootWaitTime == 0) {
state = e_Start;
}
break;
// --- phase: game -------------------------------------------------------- // --- phase: game --------------------------------------------------------
case e_Start: case e_Start:
canvasClear(); canvasClear();
@ -64,7 +78,6 @@ void gameExec(void *handle) {
case e_DownDelay: case e_DownDelay:
proceedDelay--; proceedDelay--;
if (proceedDelay == 0) { if (proceedDelay == 0) {
rowIndex = 0;
state = e_Down; state = e_Down;
} }
break; break;
@ -73,42 +86,64 @@ void gameExec(void *handle) {
if (! stoneMoveDown()) { if (! stoneMoveDown()) {
soundCtrl(SOUND_LOCK); soundCtrl(SOUND_LOCK);
stoneLock(); stoneLock();
state = e_ClearRows; state = e_ClearRowInit;
} else { } else {
proceedDelay = delayFactor(level); proceedDelay = delayFactor(level);
state = e_DownDelay; state = e_DownDelay;
} }
break; break;
case e_ClearRows: // --- phase: clear rows --------------------------------------------------
// clear filled lines case e_ClearRowInit:
for (uint8_t r = 0; r < CANVAS_HEIGHT; r++) { clearCheckCnt = 0;
if (canvasIsRowFilled(r)) { state = e_ClearRowCheck;
score += level; break;
if (score > eepromReadHighScore()) {
newHighScoreAchieved = true; case e_ClearRowNext:
eepromWriteHighScore(score); if (clearCheckCnt >= CANVAS_HEIGHT) {
} state = e_NewStone;
displaySetValue(score); } else {
canvasWipeRow(r); clearCheckCnt += 1;
canvasShow(); state = e_ClearRowCheck;
wipedLines = true; }
filledLines += 1; break;
case e_ClearRowCheck:
if (canvasIsRowFilled(clearCheckCnt)) {
score += level;
if (score > eepromReadHighScore()) {
newHighScoreAchieved = true;
eepromSetHighScore(score);
eepromCommit();
} }
state = e_ClearRowFlash;
} else {
state = e_ClearRowNext;
} }
break;
if (wipedLines) { case e_ClearRowFlash:
soundCtrl(SOUND_PLING); canvasFillRow(clearCheckCnt, eepromReadFlashColor());
} state = e_ClearRowFlashDelay;
break;
if (wipedLines && (filledLines > 0) && ((filledLines % 10) == 0)) { case e_ClearRowFlashDelay:
state = e_ClearRowWipe;
break;
case e_ClearRowWipe:
canvasWipeRow(clearCheckCnt);
filledLines += 1;
if ((filledLines > 0) && ((filledLines % 10) == 0)) {
if (level < MAX_LEVEL) { if (level < MAX_LEVEL) {
level += 1; level += 1;
} }
soundCtrl(SOUND_FANFARE); soundCtrl(SOUND_FANFARE);
} else {
soundCtrl(SOUND_PLING);
} }
state = e_ClearRowNext;
state = e_NewStone;
break; break;
// --- phase: game over --------------------------------------------------- // --- phase: game over ---------------------------------------------------
@ -146,11 +181,13 @@ void gameExec(void *handle) {
canvasShow(); canvasShow();
#ifndef STATE_DEBUGGING
if (isGameActive()) { if (isGameActive()) {
displaySetValue(score); displaySetValue(score);
} else { } else {
displaySetValue(eepromReadHighScore()); displaySetValue(eepromReadHighScore());
} }
#endif
} }
void gameInit() { void gameInit() {

View File

@ -13,6 +13,8 @@
#include "spi.h" #include "spi.h"
#include "display.h" #include "display.h"
#include "eeprom.h" #include "eeprom.h"
#include "config.h"
#include "sound.h"
int main() { int main() {
@ -33,11 +35,19 @@ int main() {
displayInit(); displayInit();
myRandInit(); myRandInit();
canvasInit(); canvasInit();
soundInit();
shapesInit();
gameInit();
buttonsInit(); buttonsInit();
eepromShowValues();
if (isConfigMode()) {
configInit();
} else {
shapesInit();
gameInit();
buttonsStart();
}
__enable_interrupt(); __enable_interrupt();
while (1) { while (1) {

View File

@ -109,3 +109,9 @@ uint32_t getSeconds() {
return s; return s;
} }
void wait(uint8_t t) {
uint8_t startTime = getSeconds();
while (getSeconds() < (startTime + t));
}

View File

@ -32,6 +32,6 @@ void schExec();
void schUpdate(); void schUpdate();
uint8_t schTaskCnt(); uint8_t schTaskCnt();
uint32_t getSeconds(); uint32_t getSeconds();
void wait(uint8_t t);
#endif /* PONTCOOPSCHEDULER_H_ */ #endif /* PONTCOOPSCHEDULER_H_ */

View File

@ -354,14 +354,18 @@ const orientation_t nextOrientation[5][4] = { // 5 = number of directions to mov
stone_t stone; stone_t stone;
shape_t nextShape; shape_t nextShape;
static shape_t randomNextShape() {
return ((shape_t[]){ e_I, e_O, e_T, e_Z, e_S, e_L, e_J })[myRandGet() % e_ShapeInvalid];
}
void shapesInit() { void shapesInit() {
stone.shape = e_ShapeInvalid; stone.shape = e_ShapeInvalid;
nextShape = e_Z; nextShape = randomNextShape();
} }
void stoneCreate() { void stoneCreate() {
stone.shape = nextShape; stone.shape = nextShape;
nextShape = ((shape_t[]){ e_I, e_O, e_T, e_Z, e_S, e_L, e_J })[myRandGet() % e_ShapeInvalid]; nextShape = randomNextShape();
stone.orientation = e_0; stone.orientation = e_0;
stone.x = 4; stone.x = 4;
stone.y = 0; stone.y = 0;
@ -452,6 +456,21 @@ void nextStoneDraw() {
motions[nextShape].color); motions[nextShape].color);
} }
static void stoneJustDraw(uint8_t x, uint8_t y, shape_t shape) {
canvasSetPixel(x + motions[shape].draw[0].x,
y + motions[shape].draw[0].y,
motions[shape].color);
canvasSetPixel(x + motions[shape].draw[1].x,
y + motions[shape].draw[1].y,
motions[shape].color);
canvasSetPixel(x + motions[shape].draw[2].x,
y + motions[shape].draw[2].y,
motions[shape].color);
canvasSetPixel(x + motions[shape].draw[3].x,
y + motions[shape].draw[3].y,
motions[shape].color);
}
uint8_t stoneDraw() { uint8_t stoneDraw() {
nextStoneDraw(); nextStoneDraw();
@ -466,23 +485,22 @@ uint8_t stoneDraw() {
canvasIsPixelFree(stone.x + motions[stone.shape].draw[3].x, canvasIsPixelFree(stone.x + motions[stone.shape].draw[3].x,
stone.y + motions[stone.shape].draw[3].y)) { stone.y + motions[stone.shape].draw[3].y)) {
// if so, draw the shape // if so, draw the shape
canvasSetPixel(stone.x + motions[stone.shape].draw[0].x, stoneJustDraw(stone.x, stone.y, stone.shape);
stone.y + motions[stone.shape].draw[0].y,
motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].draw[1].x,
stone.y + motions[stone.shape].draw[1].y,
motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].draw[2].x,
stone.y + motions[stone.shape].draw[2].y,
motions[stone.shape].color);
canvasSetPixel(stone.x + motions[stone.shape].draw[3].x,
stone.y + motions[stone.shape].draw[3].y,
motions[stone.shape].color);
res = 1; res = 1;
} }
return res; return res;
} }
void stoneDrawConfigPattern() {
stoneJustDraw(1, 0, e_I);
stoneJustDraw(3, 4, e_O);
stoneJustDraw(4, 7, e_T);
stoneJustDraw(5, 10, e_Z);
stoneJustDraw(1, 12, e_S);
stoneJustDraw(5, 15, e_L);
stoneJustDraw(1, 17, e_J);
}
uint8_t stoneMoveDown() { uint8_t stoneMoveDown() {
return move(e_MoveDown); return move(e_MoveDown);
} }

View File

@ -14,5 +14,6 @@ uint8_t stoneMoveRight();
uint8_t stoneRotateLeft(); uint8_t stoneRotateLeft();
uint8_t stoneRotateRight(); uint8_t stoneRotateRight();
void stoneDrawConfigPattern();
#endif // _SHAPES_H_ #endif // _SHAPES_H_

View File

@ -1,10 +1,12 @@
#include <stdint.h> #include <stdint.h>
#include "sound.h" #include "sound.h"
#include "spi.h" #include "spi.h"
#include "eeprom.h"
void soundInit() { void soundInit() {
soundCtrl(SOUND_COMMAND + SOUND_SUBCMD_AMPLITUDE + eepromReadAmplitude());
} }

View File

@ -1,38 +1,55 @@
#include "colors.h" #include "colors.h"
#define DIMM_FACTOR 3
.section ".rodata","a" .section ".rodata","a"
;; color definitions according to ;; color definitions according to
;; https://learn.sparkfun.com/tutorials/lilypad-protosnap-plus-activity-guide/3-custom-color-mixing ;; https://learn.sparkfun.com/tutorials/lilypad-protosnap-plus-activity-guide/3-custom-color-mixing
colors: colors:
.global colors .global colors
;; red, green, blue, padding ;; red, green, blue, padding
off: .byte 0x00, 0x00, 0x00, 0 ;; off
.byte 0x00, 0x00, 0x00, 0
blue: .byte 0x00>>5, 0x00>>5, 0xff>>5, 0 ;; blue
.byte 0x00>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0 .byte 0x00>>5, 0xff>>5, 0x00>>5, 0 ;; green
green: .byte 0xff>>5, 0x80>>5, 0x00>>5, 0 ;; orange
.byte 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0 .byte 0x80>>5, 0x00>>5, 0xff>>5, 0 ;; violet
orange: .byte 0x00>>5, 0xff>>5, 0xff>>5, 0 ;; cyan
.byte 0xff>>DIMM_FACTOR, 0x80>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0 .byte 0xff>>5, 0xff>>5, 0x00>>5, 0 ;; yellow
rose: .byte 0xff>>5, 0x00>>5, 0x00>>5, 0 ;; red
.byte 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0x80>>DIMM_FACTOR, 0 .byte 0xff>>5, 0xff>>5, 0xff>>5, 0 ;; white
magenta:
.byte 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0 .byte 0x00>>4, 0x00>>4, 0xff>>4, 0 ;; blue
violet: .byte 0x00>>4, 0xff>>4, 0x00>>4, 0 ;; green
.byte 0x80>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0 .byte 0xff>>4, 0x80>>4, 0x00>>4, 0 ;; orange
azure: .byte 0x80>>4, 0x00>>4, 0xff>>4, 0 ;; violet
.byte 0x00>>DIMM_FACTOR, 0x80>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0 .byte 0x00>>4, 0xff>>4, 0xff>>4, 0 ;; cyan
cyan: .byte 0xff>>4, 0xff>>4, 0x00>>4, 0 ;; yellow
.byte 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0 .byte 0xff>>4, 0x00>>4, 0x00>>4, 0 ;; red
springgreen: .byte 0xff>>4, 0xff>>4, 0xff>>4, 0 ;; white
.byte 0x00>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0x80>>DIMM_FACTOR, 0
chartreuse: .byte 0x00>>3, 0x00>>3, 0xff>>3, 0 ;; blue
.byte 0x80>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0 .byte 0x00>>3, 0xff>>3, 0x00>>3, 0 ;; green
yellow: .byte 0xff>>3, 0x80>>3, 0x00>>3, 0 ;; orange
.byte 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0 .byte 0x80>>3, 0x00>>3, 0xff>>3, 0 ;; violet
white: .byte 0x00>>3, 0xff>>3, 0xff>>3, 0 ;; cyan
.byte 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0xff>>DIMM_FACTOR, 0 .byte 0xff>>3, 0xff>>3, 0x00>>3, 0 ;; yellow
red: .byte 0xff>>3, 0x00>>3, 0x00>>3, 0 ;; red
.byte 0xff>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0x00>>DIMM_FACTOR, 0 .byte 0xff>>3, 0xff>>3, 0xff>>3, 0 ;; white
.byte 0x00>>2, 0x00>>2, 0xff>>2, 0 ;; blue
.byte 0x00>>2, 0xff>>2, 0x00>>2, 0 ;; green
.byte 0xff>>2, 0x80>>2, 0x00>>2, 0 ;; orange
.byte 0x80>>2, 0x00>>2, 0xff>>2, 0 ;; violet
.byte 0x00>>2, 0xff>>2, 0xff>>2, 0 ;; cyan
.byte 0xff>>2, 0xff>>2, 0x00>>2, 0 ;; yellow
.byte 0xff>>2, 0x00>>2, 0x00>>2, 0 ;; red
.byte 0xff>>2, 0xff>>2, 0xff>>2, 0 ;; white
.byte 0x00>>1, 0x00>>1, 0xff>>1, 0 ;; blue
.byte 0x00>>1, 0xff>>1, 0x00>>1, 0 ;; green
.byte 0xff>>1, 0x80>>1, 0x00>>1, 0 ;; orange
.byte 0x80>>1, 0x00>>1, 0xff>>1, 0 ;; violet
.byte 0x00>>1, 0xff>>1, 0xff>>1, 0 ;; cyan
.byte 0xff>>1, 0xff>>1, 0x00>>1, 0 ;; yellow
.byte 0xff>>1, 0x00>>1, 0x00>>1, 0 ;; red
.byte 0xff>>1, 0xff>>1, 0xff>>1, 0 ;; white

View File

@ -2,21 +2,20 @@
#define _COLORS_H_ #define _COLORS_H_
#define _off 0x00 #define _off 0
#define _blue 0x01
#define _green 0x02
#define _orange 0x03
#define _rose 0x04
#define _magenta 0x05
#define _violet 0x06
#define _azure 0x07
#define _cyan 0x08
#define _springgreen 0x09
#define _chartreuse 0x0a
#define _yellow 0x0b
#define _white 0x0c
#define _red 0x0d
#define _blue 1
#define _green 2
#define _orange 3
#define _violet 4
#define _cyan 5
#define _yellow 6
#define _red 7
#define _white 8
#define _brightness_offset 8
#define _brightness_shifts 5
#define _color_end (_brightness_offset * _brightness_shifts)
#endif #endif

View File

@ -12,7 +12,7 @@ ASFLAGS=$(COMMONFLAGS) -D__ASSEMBLER__
LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include LDFLAGS=-mmcu=$(MCU) -L $(TOOLCHAIN_PREFIX)/include
$(ARTIFACT).elf: main.o scheduler.o spi.o spi_init.o sequencer.o melody_tetris.o melody_tusch1.o psg.o mute.o melody_pling.o $(ARTIFACT).elf: main.o scheduler.o spi.o spi_init.o sequencer.o melody_tetris.o melody_tusch1.o psg.o mute.o melody_pling.o config.o
$(CC) -o $@ $(LDFLAGS) $^ $(CC) -o $@ $(LDFLAGS) $^
$(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt $(OBJDUMP) -D $(ARTIFACT).elf > $(ARTIFACT).txt

26
sound-driver/config.c Normal file
View File

@ -0,0 +1,26 @@
#include <stdint.h>
#include <sys/param.h>
#include "config.h"
typedef struct {
uint8_t melodyAmplitude;
uint8_t effectsAmplitude;
} config_t;
config_t config;
void configSetAmplitude(uint8_t v) {
config.melodyAmplitude = MIN(v, 15);
config.effectsAmplitude = MIN(v+4, 15);
}
uint8_t *configGetMelodyAmplitudePtr() {
return &(config.melodyAmplitude);
}
uint8_t *configGetEffectsAmplitudePtr() {
return &(config.effectsAmplitude);
}

12
sound-driver/config.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include <stdint.h>
void configSetAmplitude(uint8_t v);
uint8_t *configGetMelodyAmplitudePtr();
uint8_t *configGetEffectsAmplitudePtr();
#endif // _CONFIG_H_

View File

@ -3,6 +3,8 @@
#include "psg.h" #include "psg.h"
#include "sequencer.h" #include "sequencer.h"
#include "scheduler.h" #include "scheduler.h"
#include "config.h"
const t_tone plingVoice1[] = { const t_tone plingVoice1[] = {
{ .octave = e_O_5, .note = e_C, .length = e_L_1_16, .legato = false, .staccato = false }, { .octave = e_O_5, .note = e_C, .length = e_L_1_16, .legato = false, .staccato = false },
@ -18,13 +20,14 @@ const t_tone plingVoice1[] = {
}; };
t_melodies pling = { t_melodies pling = {
.melodies = { { .amplitude = 12, .tones = plingVoice1 } }, .melodies = { { .tones = plingVoice1 } },
.numOfMelodies = 1, .numOfMelodies = 1,
.pace = 200, .pace = 200,
.chip = 1 .chip = 1
}; };
void playPling() { void playPling() {
pling.amplitude = configGetEffectsAmplitudePtr();
sequencerPlayMelodies(&pling); sequencerPlayMelodies(&pling);
} }

View File

@ -3,6 +3,7 @@
#include "psg.h" #include "psg.h"
#include "sequencer.h" #include "sequencer.h"
#include "scheduler.h" #include "scheduler.h"
#include "config.h"
/* /*
@ -924,7 +925,7 @@ const t_tone voice3[] = {
#define INITIAL_PACE 160 #define INITIAL_PACE 160
t_melodies tetrisTheme = { t_melodies tetrisTheme = {
.melodies = { { .amplitude = 8, .tones = voice1 }, { .amplitude = 8, .tones = voice2 }, { .amplitude = 8, .tones = voice3 } }, .melodies = { { .tones = voice1 }, { .tones = voice2 }, { .tones = voice3 } },
.numOfMelodies = 3, .numOfMelodies = 3,
.pace = INITIAL_PACE, .pace = INITIAL_PACE,
.chip = 0 .chip = 0
@ -932,6 +933,7 @@ t_melodies tetrisTheme = {
void playMelodyTetris() { void playMelodyTetris() {
tetrisTheme.pace = INITIAL_PACE; // reset to start value each time tetrisTheme.pace = INITIAL_PACE; // reset to start value each time
tetrisTheme.amplitude = configGetMelodyAmplitudePtr();
sequencerPlayMelodies(&tetrisTheme); sequencerPlayMelodies(&tetrisTheme);
} }

View File

@ -5,5 +5,6 @@
void playMelodyTetris(); void playMelodyTetris();
void stopMelodyTetris(); void stopMelodyTetris();
void playMelodyTetrisFaster(); void playMelodyTetrisFaster();
void playMelodyTetrisAmplitude(uint8_t a);
#endif // _MELODY_TETRIS_H_ #endif // _MELODY_TETRIS_H_

View File

@ -3,7 +3,7 @@
#include "psg.h" #include "psg.h"
#include "sequencer.h" #include "sequencer.h"
#include "scheduler.h" #include "scheduler.h"
#include "melody_tetris.h" #include "config.h"
const t_tone tusch1voice1[] = { const t_tone tusch1voice1[] = {
{ .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = true }, { .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = true },
@ -72,15 +72,15 @@ const t_tone tusch1voice3[] = {
}; };
t_melodies tusch1 = { t_melodies tusch1 = {
.melodies = { { .amplitude = 12, .tones = tusch1voice1 }, { .amplitude = 12, .tones = tusch1voice2 }, { .amplitude = 12, .tones = tusch1voice3 } }, .melodies = { { .tones = tusch1voice1 }, { .tones = tusch1voice2 }, { .tones = tusch1voice3 } },
.numOfMelodies = 3, .numOfMelodies = 3,
.pace = 200, .pace = 200,
.chip = 1 .chip = 1
}; };
void playTusch1() { void playTusch1() {
tusch1.amplitude = configGetEffectsAmplitudePtr();
sequencerPlayMelodies(&tusch1); sequencerPlayMelodies(&tusch1);
// playMelodyTetrisFaster();
} }

View File

@ -59,7 +59,7 @@ void sequencerExec(void *handle) {
if (melody->tones[melody->idx].length == e_L_EndMark) { if (melody->tones[melody->idx].length == e_L_EndMark) {
melody->idx = 0; melody->idx = 0;
} }
psgPlayTone(melodies->chip, channel, melody->amplitude, melody->tones[melody->idx].octave, melody->tones[melody->idx].note); psgPlayTone(melodies->chip, channel, *(melodies->amplitude), melody->tones[melody->idx].octave, melody->tones[melody->idx].note);
melody->lengthCnt = (melody->tones[melody->idx].staccato) ? melody->lengthCnt = (melody->tones[melody->idx].staccato) ?
(calcLength(melodies, melody->tones[melody->idx].length) / 2) : (calcLength(melodies, melody->tones[melody->idx].length) / 2) :
calcLength(melodies, melody->tones[melody->idx].length); calcLength(melodies, melody->tones[melody->idx].length);

View File

@ -44,7 +44,6 @@ typedef struct {
uint16_t idx; uint16_t idx;
uint16_t lengthCnt; uint16_t lengthCnt;
t_sequencerState state; t_sequencerState state;
uint8_t amplitude;
const t_tone *tones; const t_tone *tones;
} t_melody; } t_melody;
@ -53,6 +52,7 @@ typedef struct {
typedef struct { typedef struct {
uint8_t slotMask; uint8_t slotMask;
uint8_t chip; uint8_t chip;
uint8_t *amplitude;
uint8_t taskId; uint8_t taskId;
uint16_t quarterLength; uint16_t quarterLength;
uint8_t numOfMelodies; uint8_t numOfMelodies;

View File

@ -8,7 +8,9 @@
#define SOUND_GAMEOVER 0x08 #define SOUND_GAMEOVER 0x08
#define SOUND_FANFARE 0x10 #define SOUND_FANFARE 0x10
#define SOUND_LOCK 0x20 #define SOUND_LOCK 0x20
#define SOUND_MOTION 0x40 #define SOUND_PLING 0x40
#define SOUND_PLING 0x80 #define SOUND_COMMAND 0x80
#define SOUND_SUBCMD_AMPLITUDE 0x40
#endif // _SOUND_CODES_H_ #endif // _SOUND_CODES_H_

View File

@ -6,12 +6,21 @@
receive_isr: receive_isr:
bit #UCB0RXIFG, &UC0IFG bit #UCB0RXIFG, &UC0IFG
jz receive_isr_no_data jz receive_isr_no_data
bit #SOUND_COMMAND, &cmd
jnz receive_isr_no_data
bis UCB0RXBUF, &cmd bis UCB0RXBUF, &cmd
receive_isr_no_data: receive_isr_no_data:
reti reti
.global spiCmdHandler .global spiCmdHandler
spiCmdHandler: spiCmdHandler:
spiCmdHandler_0:
bit #SOUND_COMMAND, &cmd
jz spiCmdHandler_1
;; insert a call here
call #spiCommandDispatcher
mov.b #0, &cmd
ret
spiCmdHandler_1: spiCmdHandler_1:
bit #SOUND_MUTE, &cmd bit #SOUND_MUTE, &cmd
jz spiCmdHandler_2 jz spiCmdHandler_2
@ -44,11 +53,6 @@ spiCmdHandler_6:
;; insert a call here ;; insert a call here
bic #SOUND_LOCK, &cmd bic #SOUND_LOCK, &cmd
spiCmdHandler_7: spiCmdHandler_7:
bit #SOUND_MOTION, &cmd
jz spiCmdHandler_8
;; insert a call here
bic #SOUND_MOTION, &cmd
spiCmdHandler_8:
bit #SOUND_PLING, &cmd bit #SOUND_PLING, &cmd
jz spiCmdHandler_end jz spiCmdHandler_end
call #playPling call #playPling

View File

@ -4,9 +4,10 @@
#include "scheduler.h" #include "scheduler.h"
#include "spi.h" #include "spi.h"
#include "soundCodes.h" #include "soundCodes.h"
#include "config.h"
uint8_t cmd; volatile uint8_t cmd;
void spiInit() { void spiInit() {
// SPI slave // SPI slave
@ -25,7 +26,14 @@ void spiInit() {
UC0IE |= UCB0RXIE; UC0IE |= UCB0RXIE;
cmd = SOUND_IDLE; cmd = SOUND_IDLE;
schAdd(spiCmdHandler, NULL, 0, 100); schAdd(spiCmdHandler, NULL, 0, 5);
} }
void spiCommandDispatcher() {
cmd &= ~SOUND_COMMAND;
if (cmd & SOUND_SUBCMD_AMPLITUDE) {
cmd &= ~SOUND_SUBCMD_AMPLITUDE;
configSetAmplitude(cmd);
}
}