bla
This commit is contained in:
parent
703e365da4
commit
f03c8fc9ae
|
@ -0,0 +1,212 @@
|
|||
#include <sysinit.h>
|
||||
#include <stdint.h>
|
||||
#include "basic/basic.h"
|
||||
#include "funk/nrf24l01p.h"
|
||||
//#include "usetable.h"
|
||||
|
||||
|
||||
#define AWAKE_PACKET_RETRIES 20
|
||||
#define AWAKE_MIN_WINNERS 3
|
||||
#define AWAKE_FONT_HEIGHT 8
|
||||
|
||||
|
||||
typedef enum packet_type_e {
|
||||
PCKT_WINNER0,
|
||||
PCKT_WINNER1,
|
||||
PCKT_WINNER2,
|
||||
PCKT_WINNER3,
|
||||
PCKT_WINNER4,
|
||||
PCKT_WINNER5,
|
||||
PCKT_WINNER6,
|
||||
PCKT_WINNER7,
|
||||
PCKT_WAKEUP,
|
||||
PCKT_STANDBY,
|
||||
PCKT_NONE
|
||||
} packet_type_t;
|
||||
|
||||
|
||||
static char const *const awake_gPackets[] = {
|
||||
"winner0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"wake up\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"standby\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initializes wireless stuff.
|
||||
*/
|
||||
static void awake_initNrf(void) {
|
||||
nrf_init();
|
||||
static struct NRF_CFG config = {
|
||||
.channel = 81,
|
||||
.txmac = "\x1\x2\x3\x2\x1",
|
||||
.nrmacs = 1,
|
||||
.mac0 = "\x1\x2\x3\x2\x1",
|
||||
.maclen = "\x20"
|
||||
};
|
||||
nrf_config_set(&config);
|
||||
nrf_set_strength(3);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Polls for a special packet which indicates the success of a player.
|
||||
*/
|
||||
static packet_type_t awake_waitForPacket(void) {
|
||||
uint8_t buffer[32];
|
||||
if (nrf_rcv_pkt_time(100, 32, buffer) == 32) {
|
||||
for (packet_type_t p = PCKT_WINNER0; p < PCKT_NONE; ++p) {
|
||||
unsigned int bEqual = 1;
|
||||
for (unsigned int i = 0; i < 8; ++i) {
|
||||
if (buffer[i] != awake_gPackets[p][i]) {
|
||||
bEqual = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bEqual) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PCKT_NONE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Waits for either pushed buttons or a signal on the hacker bus.
|
||||
*/
|
||||
static void awake_waitForKeyPressOrHackerbus(void) {
|
||||
gpioSetDir(RB_HB0, gpioDirection_Input);
|
||||
// watch out for pushed buttons and/or hacker bus activity
|
||||
while (gpioGetValue(RB_HB0) != 0)
|
||||
{
|
||||
if (getInput() != BTN_NONE)
|
||||
{
|
||||
getInputWaitRelease();
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (gpioGetValue(RB_HB0) == 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The greeter!
|
||||
*/
|
||||
static void awake_promptUserBegin(void) {
|
||||
gpioSetDir(RB_HB0, gpioDirection_Input);
|
||||
|
||||
lcdFill(0);
|
||||
DoString(0, 0, "Eine Taste");
|
||||
DoString(0, 8, "druecken um");
|
||||
DoString(0,16, "das Spiel");
|
||||
DoString(0,24, "zu starten!");
|
||||
lcdDisplay();
|
||||
|
||||
awake_waitForKeyPressOrHackerbus();
|
||||
|
||||
lcdFill(0);
|
||||
DoString(0, 0, "Spiel laeuft!");
|
||||
DoString(0, 16, "FEUERTASTE");
|
||||
DoString(0, 24, "fuer Standby");
|
||||
lcdDisplay();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Informs about the happy end!
|
||||
*/
|
||||
static void awake_promptUserEnd(void){
|
||||
lcdFill(0);
|
||||
DoString(0, 0, "Es wurden ge-");
|
||||
DoString(0, 8, "nug Gewinner ");
|
||||
DoString(0, 16, "ermittelt! ");
|
||||
lcdDisplay();
|
||||
|
||||
// toggle RB_HB1 pin from 0V to 3,3 for 200ms
|
||||
GPIO_GPIO0DATA |= (1u << 10);
|
||||
delayms_queue(200);
|
||||
GPIO_GPIO0DATA &= ~(1u << 10);
|
||||
|
||||
awake_waitForKeyPressOrHackerbus();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Explains a brief moment of unresponsiveness.
|
||||
*/
|
||||
static void awake_promptStandby(void){
|
||||
lcdFill(0);
|
||||
DoString(0, 0, "Bitte warten!");
|
||||
DoString(0, 8, "Sende Standby");
|
||||
DoString(0, 16, "Pakete... ");
|
||||
lcdDisplay();
|
||||
}
|
||||
|
||||
|
||||
void awake_initHackerBus() {
|
||||
// set RB_HB1 to GPIO mode (output)
|
||||
#define IOCON_PIO0_10 (*((REG32*) (0x40044068)))
|
||||
IOCON_PIO0_10 &= ~(00000007);
|
||||
IOCON_PIO0_10 |= 0x00000001;
|
||||
GPIO_GPIO0DIR |= (1 << 10);
|
||||
GPIO_GPIO0DATA &= ~(1 << 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function of the l0dable.
|
||||
*/
|
||||
void main_awake(void) {
|
||||
awake_initNrf();
|
||||
awake_initHackerBus();
|
||||
|
||||
while (1) {
|
||||
awake_promptUserBegin();
|
||||
uint8_t joyinput = BTN_NONE;
|
||||
unsigned int nWinnerFlags = 0, nWinnerCount = 0;
|
||||
while ((joyinput != BTN_ENTER) && (nWinnerCount < AWAKE_MIN_WINNERS)) {
|
||||
if ((joyinput = getInput()) != BTN_NONE)
|
||||
{
|
||||
getInputWaitRelease();
|
||||
}
|
||||
|
||||
// send a "wake up" packet every loop cycle so that in case a r0ket
|
||||
// is rebooted, the player can continue the game
|
||||
uint8_t packet[32];
|
||||
memcpy(packet, awake_gPackets[PCKT_WAKEUP], 32);
|
||||
delayms(10);
|
||||
nrf_snd_pkt_crc(32, packet);
|
||||
|
||||
// watch out for winners!
|
||||
packet_type_t const ePacket = awake_waitForPacket();
|
||||
unsigned int const nWinnerMask = (1 << ePacket) & 0xFF;
|
||||
if ((ePacket <= PCKT_WINNER7) && !(nWinnerFlags & nWinnerMask)) {
|
||||
nWinnerFlags |= nWinnerMask;
|
||||
++nWinnerCount;
|
||||
DoIntX(0, 32, nWinnerMask);
|
||||
lcdDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
if (nWinnerCount >= AWAKE_MIN_WINNERS) {
|
||||
awake_promptUserEnd();
|
||||
}
|
||||
|
||||
awake_promptStandby();
|
||||
uint8_t packet[32];
|
||||
for (int i = 0; i < AWAKE_PACKET_RETRIES; ++i) {
|
||||
delayms_queue(50);
|
||||
memcpy(packet, awake_gPackets[PCKT_STANDBY], 32);
|
||||
nrf_snd_pkt_crc(32, packet);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,649 @@
|
|||
#include <sysinit.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "basic/basic.h"
|
||||
#include "basic/random.h"
|
||||
#include "basic/config.h"
|
||||
#include "lcd/render.h"
|
||||
#include "lcd/backlight.h"
|
||||
#include "lcd/allfonts.h"
|
||||
#include "funk/nrf24l01p.h"
|
||||
|
||||
|
||||
#define POEM_ID 4
|
||||
|
||||
#define BTN_WAKEUP (1 << 5)
|
||||
#define BTN_STANDBY (1 << 6)
|
||||
|
||||
#define POEM_FONT_WIDTH 5
|
||||
#define POEM_FONT_HEIGHT 8
|
||||
#define POEM_FONT Font_5x8
|
||||
|
||||
#define POEM_COUNT 5u
|
||||
#define POEM_VERSE_COUNT 4u
|
||||
#define POEM_MAX_LINE_COUNT (RESY / POEM_FONT_HEIGHT)
|
||||
#define POEM_LINE_LIMIT ((RESX - 4) / POEM_FONT_WIDTH)
|
||||
|
||||
|
||||
#define POEM_PACKET_RETRIES 10
|
||||
|
||||
typedef enum packet_type_e {
|
||||
PCKT_WINNER0,
|
||||
PCKT_WINNER1,
|
||||
PCKT_WINNER2,
|
||||
PCKT_WINNER3,
|
||||
PCKT_WINNER4,
|
||||
PCKT_WINNER5,
|
||||
PCKT_WINNER6,
|
||||
PCKT_WINNER7,
|
||||
PCKT_WAKEUP,
|
||||
PCKT_STANDBY,
|
||||
PCKT_NONE
|
||||
} packet_type_t;
|
||||
|
||||
|
||||
static char const *const poem_gPackets[10] = {
|
||||
"winner0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner2\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"winner7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"wake up\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
|
||||
"standby\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
};
|
||||
|
||||
|
||||
typedef enum poem_state_e {
|
||||
POEM_STATE_STANDBY,
|
||||
POEM_STATE_USAGE,
|
||||
POEM_STATE_PLAYING,
|
||||
POEM_STATE_WON
|
||||
} poem_state_t;
|
||||
|
||||
|
||||
typedef struct poem_break_marker_s {
|
||||
unsigned int nStart;
|
||||
unsigned int nStop;
|
||||
} poem_break_marker_t;
|
||||
|
||||
|
||||
typedef struct poem_s {
|
||||
char const * const pszVerses[POEM_VERSE_COUNT];
|
||||
unsigned int nLineCounts[POEM_VERSE_COUNT];
|
||||
unsigned int nPermut[POEM_VERSE_COUNT];
|
||||
poem_break_marker_t pszMarkers[POEM_VERSE_COUNT][POEM_MAX_LINE_COUNT];
|
||||
} poem_t;
|
||||
|
||||
|
||||
static poem_t g_poem_aPoems[POEM_COUNT]=
|
||||
{
|
||||
#if POEM_ID == 0
|
||||
// Goethe - An den Mond, 3. Vers
|
||||
{{"Jeden Nachklang fuehlt mein Herz",
|
||||
"Froh und trueber Zeit,",
|
||||
"Wandle zwischen Freud' und Schmerz",
|
||||
"In der Einsamkeit."}},
|
||||
|
||||
// Goethe - Gefunden, 3. Vers
|
||||
{{"Ich wollt es brechen,",
|
||||
"Da sagt es fein:",
|
||||
"Soll ich zum Welken",
|
||||
"Gebrochen sein?"}},
|
||||
|
||||
// Grillparzer - In der Fremde, 2. Vers
|
||||
{{"So willst Du denn nach Hause?",
|
||||
"O nein! Nur nicht nach Haus!",
|
||||
"Dort stirbt des Lebens Leben",
|
||||
"Im Einerlei mir aus."}},
|
||||
|
||||
// Friedrich Schiller - Pilgrim, 1. Vers
|
||||
{{"Noch in meines Lebens Lenze",
|
||||
"War ich, und ich wandert' aus,",
|
||||
"Und der Jugend frohe Taenze",
|
||||
"Liess ich in des Vaters Haus."}},
|
||||
|
||||
// Frank Wedekind - Erdgeist, 2. Vers
|
||||
{{"Meide nicht die ird'schen Schaetze:",
|
||||
"Wo sie liegen, nimm sie mit.",
|
||||
"Hat die Welt doch nur Gesetze,",
|
||||
"Dass man sie mit Fuessen tritt."}},
|
||||
#elif POEM_ID == 1
|
||||
// Clemens Brentano - Loreley
|
||||
{{"Zu Bacharach am Rheine",
|
||||
"Wohnt eine Zauberin,",
|
||||
"Die war so schoen und feine",
|
||||
"Und riss viel Herzen hin."}},
|
||||
|
||||
// Wilhelm Busch - Frueher, da ich unerfahren
|
||||
{{"Frueher, da ich unerfahren",
|
||||
"Und bescheidner war als heute,",
|
||||
"Hatten meine hoechste Achtung",
|
||||
"Andre Leute."}},
|
||||
|
||||
// Heinz Erhardt - Warum die Zitronen sauer wurden
|
||||
{{"Bis sie einst sprachen: 'Wir Zitronen,",
|
||||
"wir wollen gross sein wie Melonen!",
|
||||
"Auch finden wir das Gelb abscheulich,",
|
||||
"wir wollen rot sein oder blaeulich!'"}},
|
||||
|
||||
// Joseph von Eichendorff - Mondnacht
|
||||
{{"Die Luft ging durch die Felder,",
|
||||
"Die Aehren wogten sacht,",
|
||||
"Es rauschten leis' die Waelder,",
|
||||
"So sternklar war die Nacht."}},
|
||||
|
||||
// Theodor Fontane - Trost
|
||||
{{"Harre, hoffe. Nicht vergebens",
|
||||
"zaehlest du der Stunden Schlag:",
|
||||
"Wechsel ist das Los des Lebens,",
|
||||
"Und - es kommt ein andrer Tag."}},
|
||||
#elif POEM_ID == 2
|
||||
// Goethe - Der Zauberlehrling
|
||||
{{"Ach, da kommt der Meister!",
|
||||
"Herr, die Not ist gross!",
|
||||
"Die ich rief, die Geister,",
|
||||
"Werd ich nun nicht los."}},
|
||||
|
||||
// Schiller - Das Lied von der Glocke
|
||||
{{"Fest gemauert in der Erden",
|
||||
"Steht die Form, aus Lehm gebrannt.",
|
||||
"Heute muss die Glocke werden!",
|
||||
"Frisch, Gesellen, seid zur Hand!"}},
|
||||
|
||||
// Hermann Hesse - Im Nebel
|
||||
{{"Voll von Freunden war mir die Welt",
|
||||
"Als noch mein Leben licht war;",
|
||||
"Nun, da der Nebel faellt,",
|
||||
"Ist keiner mehr sichtbar."}},
|
||||
|
||||
// irgend ein Kinderlied
|
||||
{{"Schoen ist der Zylinderhut",
|
||||
"Wenn man ihn besitzen tut",
|
||||
"Doch von ganz besondrer Guete",
|
||||
"Sind stets zwei Zylinderhuete"}},
|
||||
|
||||
// Conrad Ferdinand Meyer - Alles war ein Spiel
|
||||
{{"In diesen Liedern suche du",
|
||||
"Nach keinem ernsten Ziel!",
|
||||
"Ein wenig Schmerz, ein wenig Lust,",
|
||||
"Und alles war ein Spiel."}},
|
||||
#elif POEM_ID == 3
|
||||
// Friedrich Nietzsche - Vereinsamt
|
||||
{{"Die Kraehen schrein",
|
||||
"Und ziehen schwirren Flugs zur Stadt:",
|
||||
"Bald wird es schnein, -",
|
||||
"Wohl dem, der jetzt noch - Heimat hat!"}},
|
||||
|
||||
// Christian Morgenstern - Der Werwolf
|
||||
{{"Dem Werwolf schmeichelten die Faelle,",
|
||||
"er rollte seine Augenbaelle.",
|
||||
"Indessen, bat er, fuege doch",
|
||||
"zur Einzahl auch die Mehrzahl noch!"}},
|
||||
|
||||
// Wilhelm Busch - Dummheit, die man bei den anderen sieht
|
||||
{{"Wenn andere klueger sind als wir,",
|
||||
"Das macht uns selten nur Plaesier,",
|
||||
"Doch die Gewissheit, dass sie duemmer,",
|
||||
"Erfreut fast immer."}},
|
||||
|
||||
// August von Kotzebue - Gesellschaftslied, 2. Vers
|
||||
{{"Wir sitzen so froehlich beisammen",
|
||||
"Wir haben uns alle so lieb,",
|
||||
"Wir heitern einander das Leben,",
|
||||
"Ach wenn es doch immer so blieb'!"}},
|
||||
|
||||
// Gotthold Ephraim Lessing - Antwort eines trunknen Dichters, 1. Vers
|
||||
{{"Ein trunkner Dichter leerte",
|
||||
"Sein Glas auf jeden Zug;",
|
||||
"Ihn warnte sein Gefaehrte:",
|
||||
"Hoer' auf! du hast genug."}},
|
||||
#elif POEM_ID == 4
|
||||
// Hermann von Lingg - Das Krokodil, 1. Vers
|
||||
{{"Im heil'gen Teich zu Singapur,",
|
||||
"Da liegt ein altes Krokodil",
|
||||
"Von aeusserst graemlicher Natur",
|
||||
"Und kaut an einem Lotosstiel."}},
|
||||
|
||||
// Hermann Loens - Wegewarte, 2. Vers
|
||||
{{"Ich stand an dem Wege,",
|
||||
"Hielt auf meine Hand,",
|
||||
"Du hast Deine Augen",
|
||||
"Von mir abgewandt."}},
|
||||
|
||||
// Christian Morgenstern - An meine Taschenuhr, 1. und einziger Vers
|
||||
{{"Du schlimme Uhr, du gehst mir viel zu schnell;",
|
||||
"und doch - dich schauend, sah ich selber hell.",
|
||||
"Unschuldig Raederwerk, was schalt ich dich?",
|
||||
"Ich geh zu langsam, ach zu langsam - ich."}},
|
||||
|
||||
// Eduard Moerike - Jaegerlied, 2.Vers
|
||||
{{"In die Luefte hoch der Reiher steigt,",
|
||||
"dahin weder Pfeil noch Kugel fleugt:",
|
||||
"Tausendmal so hoch und so geschwind",
|
||||
"die Gedanken treuer Liebe sind."}},
|
||||
|
||||
// Erich Muehsam - Liebesweh, 3. Vers
|
||||
{{"Ach, es ist der Traum der Liebe,",
|
||||
"den ich durch die Seele siebe.",
|
||||
"Ach, es ist der Liebe Weh,",
|
||||
"das mich zwickt vom Kopf zur Zeh."}},
|
||||
#elif POEM_ID == 5
|
||||
// Wilhelm Mueller - Der Glockenguss zu Breslau, 6. Vers
|
||||
{{"Wie hat der gute Meister",
|
||||
"So treu das Werk bedacht!",
|
||||
"Wie hat er seine Haende",
|
||||
"Geruehrt bei Tag und Nacht!"}},
|
||||
|
||||
// Ludwig Pfau - Der Geiger von Oppenau, 2. Vers
|
||||
{{"Wo seine Fiedel geklungen,",
|
||||
"Da konnte kein Fuss mehr stehn,",
|
||||
"Da sprangen die Alten und Jungen,",
|
||||
"Die Stube fing an zu drehn."}},
|
||||
|
||||
// Robert Reinick - Der Faule, 2. Vers
|
||||
{{"Doch die Zeit wird lang mir werden,",
|
||||
"Und wie bring' ich sie herum?",
|
||||
"Spitz! komm her! dich will ich lehren",
|
||||
"Hund, du bist mir viel zu dumm!"}},
|
||||
|
||||
// Rainer Maria Rilke - Herbsttag, 2. Vers
|
||||
{{"Befiehl den letzten Fruechten voll zu sein;",
|
||||
"gib ihnen noch zwei suedlichere Tage,",
|
||||
"draenge sie zur Vollendung hin und jage",
|
||||
"die letzte Suesse in den schweren Wein."}},
|
||||
|
||||
// Joachim Ringelnatz - Ehrgeiz
|
||||
{{"Ich habe meinen Soldaten aus Blei",
|
||||
"Als Kind Verdienstkreuzchen eingeritzt.",
|
||||
"Mir selber ging alle Ehre vorbei,",
|
||||
"Bis auf zwei Orden, die jeder besitzt."}}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prepares markers for line wrapping and determines the number of lines
|
||||
* required to display a verse.
|
||||
*/
|
||||
static void poem_prepareLineWrappingMarkers(void) {
|
||||
for (unsigned int iPoem = 0; iPoem < POEM_COUNT; ++iPoem) {
|
||||
for (unsigned int iVerse = 0; iVerse < POEM_VERSE_COUNT; ++iVerse) {
|
||||
char const * const psz = g_poem_aPoems[iPoem].pszVerses[iVerse];
|
||||
size_t const nLen = strlen(psz);
|
||||
unsigned int nPos = 0, nCharCnt = 0, nLineCount = 0;
|
||||
int nLastSpc = -1;
|
||||
|
||||
poem_break_marker_t *pMarker =
|
||||
&g_poem_aPoems[iPoem].pszMarkers[iVerse][nLineCount];
|
||||
while ((nPos < nLen) && (nLineCount < POEM_MAX_LINE_COUNT)) {
|
||||
if (nCharCnt < POEM_LINE_LIMIT && (nPos != (nLen - 1))) {
|
||||
if (psz[nPos] == ' ') {
|
||||
nLastSpc = nPos;
|
||||
}
|
||||
++nCharCnt;
|
||||
} else {
|
||||
pMarker->nStart = nPos - nCharCnt;
|
||||
if (nPos == (nLen - 1)) {
|
||||
pMarker->nStop = nPos;
|
||||
} else if (nLastSpc < (nPos - nCharCnt)) {
|
||||
pMarker->nStop = nPos - 1;
|
||||
} else {
|
||||
pMarker->nStop = nLastSpc;
|
||||
nPos = nLastSpc;
|
||||
}
|
||||
pMarker = &g_poem_aPoems[iPoem].pszMarkers[iVerse][++nLineCount];
|
||||
nCharCnt = 0;
|
||||
}
|
||||
++nPos;
|
||||
}
|
||||
g_poem_aPoems[iPoem].nLineCounts[iVerse] = nLineCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints a physical line (that is one row of displayed characters) from a given
|
||||
* poem and verse.
|
||||
* @param pPoem The poem where to look for that line.
|
||||
* @param nVerse The verse where the to be printed line resides.
|
||||
* @param nLine The position (counting from 0) of that line within that verse.
|
||||
* @param y The vertical offset where text should be rendered.
|
||||
*/
|
||||
static void poem_printLine(poem_t const *const pPoem, unsigned int nVerse,
|
||||
unsigned int nLine, int y) {
|
||||
char pszLine[POEM_LINE_LIMIT + 1] = { 0 };
|
||||
poem_break_marker_t const * const pMarker =
|
||||
&pPoem->pszMarkers[nVerse][nLine];
|
||||
for (unsigned int k = pMarker->nStart; k <= pMarker->nStop; ++k) {
|
||||
pszLine[k - pMarker->nStart] = pPoem->pszVerses[nVerse][k];
|
||||
}
|
||||
DoString(2, y, pszLine);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shuffles the verses of a given poem.
|
||||
* @param pPoem The poem whose verses need to be shuffled.
|
||||
*/
|
||||
static void poem_initPermutation(poem_t *const pPoem) {
|
||||
for (unsigned int i = POEM_VERSE_COUNT; i--;) {
|
||||
pPoem->nPermut[i] = i;
|
||||
}
|
||||
while ((pPoem->nPermut[0] < pPoem->nPermut[1])
|
||||
&& (pPoem->nPermut[1] < pPoem->nPermut[2])
|
||||
&& (pPoem->nPermut[2] < pPoem->nPermut[3])) {
|
||||
for (unsigned int i = 4; i--;) {
|
||||
unsigned int const nIndexA = getRandom() % POEM_VERSE_COUNT;
|
||||
unsigned int const nIndexB = getRandom() % POEM_VERSE_COUNT;
|
||||
|
||||
unsigned int nSwap = pPoem->nPermut[nIndexA];
|
||||
pPoem->nPermut[nIndexA] = pPoem->nPermut[nIndexB];
|
||||
pPoem->nPermut[nIndexB] = nSwap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t poem_identifyPacket(uint8_t *packet){
|
||||
uint8_t input = BTN_NONE;
|
||||
if (strncmp((char *)packet, poem_gPackets[PCKT_STANDBY], 8) == 0) {
|
||||
input = BTN_STANDBY;
|
||||
} else if (strncmp((char *)packet, poem_gPackets[PCKT_WAKEUP], 8) == 0) {
|
||||
input = BTN_WAKEUP;
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Watches for both joystick movements and standby NRF packets. It's blocks the
|
||||
* control flow as long as there are neither appropriate joystick activities nor
|
||||
* standby/wake up packets received.
|
||||
* @param filter A mask of events to which this function should react.
|
||||
* @return One of BTN_(UP|DOWN|LEFT|RIGHT|ENTER|STANDBY|WAKEUP).
|
||||
*/
|
||||
uint8_t poem_getInputBlocking(uint8_t filter) {
|
||||
uint8_t pkt[32];
|
||||
uint8_t input = BTN_NONE;
|
||||
nrf_rcv_pkt_start();
|
||||
do {
|
||||
if ((nrf_rcv_pkt_poll(sizeof(pkt), pkt) != 32) ||
|
||||
!((input = poem_identifyPacket(pkt)) & filter)) {
|
||||
input = getInput();
|
||||
}
|
||||
} while (!(filter & input));
|
||||
nrf_rcv_pkt_end();
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Watches for both joystick movements and standby NRF packets. It returns
|
||||
* BTN_NONE if there's neither a NRF packet nor joystick input.
|
||||
* @return One of BTN_(NONE|UP|DOWN|LEFT|RIGHT|ENTER|STANDBY|WAKEUP).
|
||||
*/
|
||||
uint8_t poem_getInputNonBlocking(void) {
|
||||
uint8_t pkt[32];
|
||||
uint8_t input;
|
||||
if (nrf_rcv_pkt_poll(sizeof(pkt), pkt) == 32) {
|
||||
input = poem_identifyPacket(pkt);
|
||||
if (input == BTN_NONE)
|
||||
input == getInput();
|
||||
}
|
||||
else {
|
||||
input = getInput();
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Displays a small description of the game.
|
||||
*/
|
||||
static void poem_printUsage(void) {
|
||||
// show usage
|
||||
int dy = 0;
|
||||
lcdFill(0);
|
||||
DoString(0, dy, "Sortiere die Verse "); dy += POEM_FONT_HEIGHT;
|
||||
DoString(0, dy, "in die richtige "); dy += POEM_FONT_HEIGHT;
|
||||
DoString(0, dy, "Reihenfolge! Der "); dy += POEM_FONT_HEIGHT;
|
||||
DoString(0, dy, "Knopf ist ein Joy- "); dy += POEM_FONT_HEIGHT;
|
||||
DoString(0, dy, "stick. Waehle einen"); dy += POEM_FONT_HEIGHT;
|
||||
DoString(0, dy, "Vers mit OBEN oder "); dy += POEM_FONT_HEIGHT;
|
||||
DoString(0, dy, "UNTEN. Verschiebe "); dy += POEM_FONT_HEIGHT;
|
||||
DoString(0, dy, "ihn per FEUERTASTE."); dy += POEM_FONT_HEIGHT;
|
||||
lcdDisplay();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the wireless stuff.
|
||||
*/
|
||||
static void poem_initRadio(void) {
|
||||
nrf_init();
|
||||
static struct NRF_CFG config = {
|
||||
.channel = 81,
|
||||
.txmac = "\x1\x2\x3\x2\x1",
|
||||
.nrmacs = 1,
|
||||
.mac0 = "\x1\x2\x3\x2\x1",
|
||||
.maclen = "\x20",
|
||||
};
|
||||
nrf_config_set(&config);
|
||||
delayms(50);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Turns on the backlight and switches to dark text on a light background.
|
||||
*/
|
||||
static void poem_turnOnBacklight(void) {
|
||||
GLOBAL(daytrig) = 255;
|
||||
GLOBAL(daytrighyst) = 50;
|
||||
GLOBAL(dayinvert) = 0;
|
||||
GLOBAL(lcdinvert) = 1;
|
||||
backlightSetBrightness(100);
|
||||
lcdSetInvert(1);
|
||||
lcdFill(0);
|
||||
lcdDisplay();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Turns off the backlight and switches to light text on a dark background.
|
||||
*/
|
||||
static void poem_turnOffBacklight(void) {
|
||||
GLOBAL(daytrig) = 0;
|
||||
GLOBAL(daytrighyst) = 50;
|
||||
GLOBAL(dayinvert) = 0;
|
||||
GLOBAL(lcdinvert) = 0;
|
||||
backlightSetBrightness(0);
|
||||
lcdSetInvert(0);
|
||||
lcdFill(0);
|
||||
lcdDisplay();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Highlights the specified item by drawing a bounding box around it (to
|
||||
* indicate a selection) or by inverting its representation (dragging).
|
||||
* @param bIsDragging Whether the item is just selected or about to be dragged.
|
||||
* @param nStartY The (absolute) start offset (in pixels) of the item.
|
||||
* @param nStopY The (absolute) stop offset (in pixels) of the item.
|
||||
* @param nScroll The vertical scrolling offset.
|
||||
*/
|
||||
static void poem_hightlightSelectedItem(unsigned int const bIsDragging,
|
||||
int nStartY, int const nStopY, int const nScroll) {
|
||||
// invert or draw a bounding box around the selected verse
|
||||
if (bIsDragging) {
|
||||
// dragging mode: invert the to be dragged item
|
||||
for (int y = nStartY; y < nStopY; ++y) {
|
||||
for (int x = 0; x < RESX; ++x) {
|
||||
lcdSetPixel(x, y - nScroll, !lcdGetPixel(x, y - nScroll));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// selection mode: draw a border around the selected item
|
||||
for (int x = 0; x < RESX; ++x) {
|
||||
lcdSetPixel(x, nStartY - nScroll, 1);
|
||||
lcdSetPixel(x, nStopY - nScroll, 1);
|
||||
}
|
||||
for (int y = nStartY; y < nStopY; ++y) {
|
||||
lcdSetPixel(0, y - nScroll, 1);
|
||||
lcdSetPixel(RESX - 1, y - nScroll, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Informs the master device that the player has accomplished the task and
|
||||
* blocks as long as there are no "standby" or "wakeup" packets.
|
||||
*/
|
||||
static void poem_sendSuccessMessage(packet_type_t pktWinner) {
|
||||
// send our winner information packet
|
||||
static uint8_t pkt[32];
|
||||
|
||||
nrf_rcv_pkt_start();
|
||||
while (1) {
|
||||
memcpy(pkt, poem_gPackets[pktWinner], sizeof(pkt));
|
||||
nrf_snd_pkt_crc(sizeof(pkt), pkt);
|
||||
delayms_queue(80 + (getRandom() % 50));
|
||||
uint8_t input = poem_getInputNonBlocking();
|
||||
if (input == BTN_STANDBY) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
nrf_rcv_pkt_end();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Starts a game where the user has to sort verses of a poem into the right
|
||||
* order.
|
||||
*/
|
||||
void main_poem(void) {
|
||||
packet_type_t pktWinner = POEM_ID;
|
||||
|
||||
// display initialization
|
||||
font = &POEM_FONT;
|
||||
|
||||
// init wireless stuff
|
||||
poem_initRadio();
|
||||
poem_prepareLineWrappingMarkers();
|
||||
|
||||
poem_state_t state = POEM_STATE_STANDBY;
|
||||
|
||||
while (1) {
|
||||
switch (state) {
|
||||
case POEM_STATE_STANDBY:
|
||||
poem_turnOffBacklight();
|
||||
lcdFill(0);
|
||||
DoInt(0, 0, pktWinner);
|
||||
lcdDisplay();
|
||||
poem_getInputBlocking(BTN_WAKEUP);
|
||||
state = POEM_STATE_USAGE;
|
||||
break;
|
||||
|
||||
case POEM_STATE_USAGE:
|
||||
poem_turnOnBacklight();
|
||||
poem_printUsage();
|
||||
{
|
||||
uint8_t input = poem_getInputBlocking(BTN_UP | BTN_DOWN |
|
||||
BTN_LEFT | BTN_RIGHT | BTN_ENTER | BTN_STANDBY);
|
||||
if (input == BTN_STANDBY) {
|
||||
state = POEM_STATE_STANDBY;
|
||||
}
|
||||
else if (input != BTN_WAKEUP) {
|
||||
state = POEM_STATE_PLAYING;
|
||||
}
|
||||
}
|
||||
DoString(20,0, "bla");
|
||||
lcdDisplay();
|
||||
break;
|
||||
|
||||
case POEM_STATE_PLAYING:
|
||||
{
|
||||
// print the verses
|
||||
poem_t *const pPoem = &g_poem_aPoems[getRandom() % POEM_COUNT];
|
||||
poem_initPermutation(pPoem);
|
||||
unsigned int nSelectedVerse = 0, nNextSelected = 0;
|
||||
unsigned int bIsDragging = 0;
|
||||
while (state == POEM_STATE_PLAYING) {
|
||||
// Calculate position and size of the bounding box of the selected
|
||||
// verse. Also, calculate a vertical scrolling offset to ensure
|
||||
// that the selected verse is visible.
|
||||
int nStartY = 0;
|
||||
for (unsigned int i = 0; i < nSelectedVerse; ++i) {
|
||||
unsigned int index = pPoem->nPermut[i];
|
||||
nStartY += POEM_FONT_HEIGHT * pPoem->nLineCounts[index] + 3;
|
||||
}
|
||||
const int nStopY = 2 + nStartY + (POEM_FONT_HEIGHT
|
||||
* pPoem->nLineCounts[pPoem->nPermut[nSelectedVerse]]);
|
||||
int nScroll = nStopY >= RESY ? nStopY - RESY + 1 : 0;
|
||||
// display verses
|
||||
lcdFill(0);
|
||||
int dy = 2;
|
||||
for (unsigned int i = 0; i < POEM_VERSE_COUNT; ++i) {
|
||||
unsigned int const index = pPoem->nPermut[i];
|
||||
for (unsigned int j = 0; j < pPoem->nLineCounts[index]; ++j) {
|
||||
poem_printLine(pPoem, index, j, dy - nScroll);
|
||||
dy += POEM_FONT_HEIGHT;
|
||||
}
|
||||
dy += 3;
|
||||
}
|
||||
// draw a bounding box around the selected verse (or invert it)
|
||||
poem_hightlightSelectedItem(bIsDragging, nStartY, nStopY, nScroll);
|
||||
// flush display buffer
|
||||
lcdDisplay();
|
||||
|
||||
// both query joystick and listen for "standby" packets;
|
||||
switch (poem_getInputBlocking(BTN_UP | BTN_DOWN |
|
||||
BTN_ENTER | BTN_STANDBY)) {
|
||||
case BTN_ENTER:
|
||||
bIsDragging = !bIsDragging;
|
||||
if (!bIsDragging && pPoem->nPermut[0] < pPoem->nPermut[1]
|
||||
&& pPoem->nPermut[1] < pPoem->nPermut[2]
|
||||
&& pPoem->nPermut[2] < pPoem->nPermut[3]) {
|
||||
state = POEM_STATE_WON;
|
||||
}
|
||||
break;
|
||||
|
||||
case BTN_UP:
|
||||
nNextSelected = nSelectedVerse > 0 ?
|
||||
nSelectedVerse - 1 : nSelectedVerse;
|
||||
break;
|
||||
|
||||
case BTN_DOWN:
|
||||
nNextSelected = nSelectedVerse < (POEM_VERSE_COUNT - 1) ?
|
||||
nSelectedVerse + 1 : nSelectedVerse;
|
||||
break;
|
||||
|
||||
case BTN_STANDBY:
|
||||
state = POEM_STATE_STANDBY;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (nSelectedVerse != nNextSelected && bIsDragging) {
|
||||
unsigned int temp = pPoem->nPermut[nSelectedVerse];
|
||||
pPoem->nPermut[nSelectedVerse] = pPoem->nPermut[nNextSelected];
|
||||
pPoem->nPermut[nNextSelected] = temp;
|
||||
}
|
||||
nSelectedVerse = nNextSelected;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case POEM_STATE_WON:
|
||||
lcdFill(0);
|
||||
DoString(22, 30, "Geschafft!");
|
||||
lcdDisplay();
|
||||
poem_sendSuccessMessage(pktWinner);
|
||||
state = POEM_STATE_STANDBY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue