195 lines
5.2 KiB
C++
195 lines
5.2 KiB
C++
#include <Arduino.h>
|
|
#include <Adafruit_GFX.h>
|
|
#include <Adafruit_SSD1351.h>
|
|
#include <SPI.h>
|
|
#include <ezButton.h>
|
|
#include <EEPROM.h>
|
|
#include "RF24.h"
|
|
|
|
// Screen dimensions
|
|
#define SCREEN_WIDTH 128
|
|
#define SCREEN_HEIGHT 128 // Change this to 96 for 1.27" OLED.
|
|
|
|
// You can use any (4 or) 5 pins
|
|
#define SCLK_PIN 13
|
|
#define MOSI_PIN 11
|
|
#define MISO_PIN 12
|
|
#define DC_PIN 9 // was pin 4
|
|
#define CS_PIN 10 // was pin 5
|
|
#define RST_PIN 8 // was pin 6
|
|
|
|
#define RF_CE_PIN 7 // (chicp enable)
|
|
#define RF_CSN_PIN 6 // (SPI select)
|
|
|
|
// Control Data
|
|
#define BUTTON_TOP 0
|
|
#define BUTTON_BOTTOM 1
|
|
#define JOYSTICK_BUTTON A4
|
|
#define JOYSTICK_X A6
|
|
#define JOYSTICK_Y A5
|
|
|
|
#include "Programs/Calculator/Calculator.h"
|
|
#include "Programs/Snake/Snake.h"
|
|
#include "Programs/Settings/Settings.h"
|
|
#include "Programs/Asteroids/Asteroids.h"
|
|
|
|
#include "Bitmaps.h"
|
|
#include "Menu.h"
|
|
#include "utility.h"
|
|
|
|
Adafruit_SSD1351 tft = Adafruit_SSD1351(SCREEN_WIDTH, SCREEN_HEIGHT, &SPI, CS_PIN, DC_PIN, RST_PIN);
|
|
RF24 radio(RF_CE_PIN, RF_CSN_PIN);
|
|
inputData userInputs(BUTTON_TOP, BUTTON_BOTTOM, JOYSTICK_BUTTON);
|
|
//programID currentProgram = NO_PROGRAM;
|
|
|
|
unsigned long interval=1000; // the time we need to wait
|
|
unsigned long previousMillis=0; // millis() returns an unsigned long.
|
|
|
|
Program* currentProgram = nullptr; // will be renamed to currentProgram when fully implemented
|
|
Program* nextProgram = nullptr;
|
|
|
|
struct state {
|
|
bool SoundEnabled = true;
|
|
bool RunningProgram = false;
|
|
bool InMenu = false;
|
|
bool RadioEnabled = true;
|
|
} MachineState;
|
|
|
|
|
|
void displaySplashScreen(int duration);
|
|
void getUserInput(inputData* inputs);
|
|
void requestProgramChange(Program* program);
|
|
void drawInfoBar();
|
|
float normalizeJoystick(int analogValue);
|
|
|
|
|
|
|
|
void requestProgramChange(Program* program){
|
|
nextProgram = program;
|
|
}
|
|
|
|
// --- STARTUP -- //
|
|
void setup(void) {
|
|
Serial.begin(9600);
|
|
Serial.println("Starting up...");
|
|
userInputs.buttonTop.setDebounceTime(25);
|
|
userInputs.buttonBottom.setDebounceTime(25);
|
|
userInputs.joyStickButton.setDebounceTime(25);
|
|
|
|
tft.begin();
|
|
|
|
// spash screen goes here!
|
|
displaySplashScreen(2000); // show spash for 2 seconds
|
|
MachineState.InMenu = true;
|
|
currentProgram = new Menu::Menu();
|
|
currentProgram->onEnter(&tft);
|
|
Serial.println("Start sucsessful");
|
|
}
|
|
|
|
// --- PROGRAM LOOP --- //
|
|
void loop() {
|
|
// need to loop as fast a possible to maintain framerate and responce time
|
|
unsigned long currentMillis = millis(); // grab current time
|
|
|
|
// handle program transistion
|
|
if (nextProgram != nullptr) {
|
|
if (currentProgram != nullptr) {
|
|
currentProgram->onExit();
|
|
delete currentProgram;
|
|
}
|
|
currentProgram = nextProgram;
|
|
nextProgram = nullptr;
|
|
if (currentProgram != nullptr){
|
|
currentProgram->onEnter(&tft);
|
|
}
|
|
}
|
|
|
|
// update current program
|
|
if (currentProgram != nullptr){
|
|
getUserInput(&userInputs);
|
|
currentProgram->loop(&tft, &userInputs);
|
|
if (!currentProgram->disableInfoBar){ drawInfoBar(); }
|
|
}
|
|
|
|
// check if "interval" time has passed (1000 milliseconds)
|
|
if ((unsigned long)(currentMillis - previousMillis) >= interval) {
|
|
// do task
|
|
previousMillis = millis();
|
|
}
|
|
}
|
|
|
|
|
|
void getUserInput(inputData *inputs){
|
|
// Call the loop() function for each button. This is required by ezButton.
|
|
inputs->buttonTop.loop();
|
|
inputs->buttonBottom.loop();
|
|
inputs->joyStickButton.loop();
|
|
|
|
// The rest of the code can now get button states directly, e.g.:
|
|
// if (inputs->buttonTop.isPressed()) { ... }
|
|
|
|
// For now, let's keep joystick values simple
|
|
int rawX = analogRead(JOYSTICK_X);
|
|
int rawY = analogRead(JOYSTICK_Y);
|
|
inputs->joyX = normalizeJoystick(rawX);
|
|
inputs->joyY = normalizeJoystick(rawY);
|
|
|
|
|
|
inputs->joystickCommand = COMMAND_NO;
|
|
|
|
// check left/right commands
|
|
if (rawX < LEFT_THRESHOLD){
|
|
inputs->joystickCommand = inputs->joystickCommand | COMMAND_LEFT;
|
|
}
|
|
else if (rawX > RIGHT_THRESHOLD){
|
|
inputs->joystickCommand = inputs->joystickCommand | COMMAND_RIGHT;
|
|
}
|
|
|
|
// check up/down commands
|
|
if (rawY < UP_THRESHOLD){
|
|
inputs->joystickCommand = inputs->joystickCommand | COMMAND_UP;
|
|
}
|
|
else if (rawY > DOWN_THRESHOLD){
|
|
inputs->joystickCommand = inputs->joystickCommand | COMMAND_DOWN;
|
|
}
|
|
}
|
|
|
|
|
|
void displaySplashScreen(int duration){
|
|
// - could play a tune and also show off the capability of the display with some
|
|
// stylish graphics! maybe even 3d graphics if build a library for it
|
|
tft.fillScreen(BLACK);
|
|
tft.drawBitmap(0, 0, spash_screen_BMP, 128, 128, WHITE);
|
|
tft.setCursor(10, 10);
|
|
tft.setTextColor(GREEN);
|
|
tft.println(F("B-TEK Advanced"));
|
|
tft.setCursor(30, 10);
|
|
tft.println(F("Booting in progress..."));
|
|
delay(duration);
|
|
tft.fillScreen(BLACK);
|
|
}
|
|
|
|
|
|
void drawInfoBar(){
|
|
// a bar on the time with data like battery life and current time and wifi status... maybe more (:
|
|
tft.drawRect(0, 0, 128, 12, RED);
|
|
tft.setCursor(5, 2);
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(WHITE);
|
|
tft.println(F("20:34"));
|
|
tft.setCursor(90, 2);
|
|
tft.println(F("[-->]"));
|
|
}
|
|
|
|
|
|
float normalizeJoystick(int analogValue) {
|
|
// Account for the dead zone
|
|
if (abs(analogValue - 512) < JOY_DEAD_ZONE) {
|
|
return 0.0;
|
|
}
|
|
// Shift the range so the center is 0
|
|
float shiftedValue = analogValue - 512;
|
|
|
|
return shiftedValue / 512.0;
|
|
}
|