Documentation
📖
Select a topic from the sidebar
Documentation is loaded dynamically — choose any section to begin.
Documentation is loaded dynamically — choose any section to begin.
Real snippets from the framework — copy and adapt for your build.
void loop() {
readRS485(); // drain bus → queue
processNextEvent(); // one event per pass
updateGameLogic(); // state + timers
updateSolenoids(); // millis() pulses
}
// RS485 frame format: "S<id>:<state>\n"
// e.g. "S3:1\n" = switch 3, closed
// pin | id | solPin | holdPin | ms | debounce
static const SwEntry SW[] = {
// Type 2 — fires local coil immediately
{ 3, SW_SLINGSHOT_LEFT, 5, -1, 25, 5 },
// Type 1 — sensor only, no coil
{ 7, SW_ROLLOVER_F, -1, -1, 0, 10 },
// Type 3 — dual wound flipper
// (add #define DUAL_WOUND at top)
{ 4, SW_FLIPPER_LEFT, 5, 6, 30, 5 },
};
// Five functions — the entire interface
void gXInit() { /* game start */ }
void gXBallReset() { /* per-ball reset */}
void gXShot(int sw) {
if (tiltActive) return;
switch (sw) {
case SW_ROLLOVER_F:
addScore(500);
sendSound(SND_ROLLOVER);
sendLight(LGT_LANE_F);
break;
}
}
void gXTimerTick() { /* mode timers */ }
void gXBallDrain() { /* bonus + done */ }
// Wire format: "TYPE:PAYLOAD\n"
// Sound → Serial2
sendSound(SND_BUMPER); // "SOUND:BUMPER\n"
sendSound(SND_JACKPOT); // "SOUND:JACKPOT\n"
// Lights → Serial3
sendLight(LGT_LANE_F); // "LIGHT:LANE_F\n"
sendLight(LGT_FRENZY_ON); // "LIGHT:FRENZY_ON\n"
// Score display → Serial3
addScore(1000); // "SCORE:<total>\n"
// Mode broadcast → all Nanos (Serial1/RS485)
broadcastNanoMode(MODE_FRENZY); // "N*:M:FRENZY\n"
// All coil timing via millis() — never delay()
fireSolenoid(IDX_TROUGH, TROUGH_PULSE_MS); // 60ms
fireSolenoid(IDX_KNOCKER); // 30ms default
fireSolenoid(IDX_SLING_LEFT);
// Called every loop() pass — releases coils
void updateSolenoids() {
unsigned long now = millis();
for (int i = 0; i < NUM_SOLENOIDS; i++) {
if (solenoids[i].active &&
now >= solenoids[i].endMs) {
digitalWrite(solenoids[i].pin, LOW);
solenoids[i].active = false;
}
}
}
enum GameState {
STATE_ATTRACT,
STATE_GAME_RUNNING,
STATE_BALL_DRAIN,
STATE_GAME_OVER
};
// startGame() — attract → running
void startGame(uint8_t style) {
currentGame = &gameStyles[style];
credits--;
score = 0;
ballsRemaining = BALLS_PER_GAME;
currentGame->onInit();
gameState = STATE_GAME_RUNNING;
broadcastNanoMode(MODE_GAME);
sendSound(SND_GAME_START);
fireSolenoid(IDX_TROUGH, TROUGH_PULSE_MS);
}