Move sketch to appropriately named subfolder
The Arduino IDE requires that a sketch be located in a folder of the same name. Although the name of the repository does match the sketch name, when GitHub's popular Clone or download > Download ZIP feature is used to download the contents of a repository the branch/release/commit name is appended to the folder name, causing a mismatch. When opening a file that does not meet this sketch/folder name matching requirement the Arduino IDE presents a dialog: The file "TWANG32.ino" needs to be inside a sketch folder named "TWANG32". Create this folder, move the file, and continue? After clicking "OK" the Arduino IDE currently moves only the file TWANG32.ino to the new folder, leaving behind the other source files. This causes compilation of the sketch to fail: TWANG32-master\TWANG32\TWANG32.ino:30:23: fatal error: twang_mpu.h: No such file or directory
This commit is contained in:
42
TWANG32/Boss.h
Normal file
42
TWANG32/Boss.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
class Boss
|
||||
{
|
||||
public:
|
||||
void Spawn();
|
||||
void Hit();
|
||||
void Kill();
|
||||
bool Alive();
|
||||
int _pos;
|
||||
int _lives;
|
||||
int _ticks;
|
||||
private:
|
||||
bool _alive;
|
||||
};
|
||||
|
||||
void Boss::Spawn(){
|
||||
_pos = 800;
|
||||
_lives = 3;
|
||||
_alive = 1;
|
||||
}
|
||||
|
||||
void Boss::Hit(){
|
||||
_lives --;
|
||||
if(_lives == 0) {
|
||||
Kill();
|
||||
return;
|
||||
}
|
||||
if(_lives == 2){
|
||||
_pos = 200;
|
||||
}else if(_lives == 1){
|
||||
_pos = 600;
|
||||
}
|
||||
}
|
||||
|
||||
bool Boss::Alive(){
|
||||
return _alive;
|
||||
}
|
||||
|
||||
void Boss::Kill(){
|
||||
_alive = 0;
|
||||
}
|
||||
24
TWANG32/Conveyor.h
Normal file
24
TWANG32/Conveyor.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "Arduino.h"
|
||||
#include "settings.h"
|
||||
|
||||
class Conveyor
|
||||
{
|
||||
public:
|
||||
void Spawn(int startPoint, int endPoint, int speed);
|
||||
void Kill();
|
||||
int _startPoint;
|
||||
int _endPoint;
|
||||
int _speed;
|
||||
bool _alive;
|
||||
};
|
||||
|
||||
void Conveyor::Spawn(int startPoint, int endPoint, int speed){
|
||||
_startPoint = startPoint;
|
||||
_endPoint = endPoint;
|
||||
_speed = constrain(speed, -MAX_PLAYER_SPEED+1, MAX_PLAYER_SPEED - 1); // must allow some player speed
|
||||
_alive = true;
|
||||
}
|
||||
|
||||
void Conveyor::Kill(){
|
||||
_alive = false;
|
||||
}
|
||||
55
TWANG32/Enemy.h
Normal file
55
TWANG32/Enemy.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
class Enemy
|
||||
{
|
||||
public:
|
||||
void Spawn(int pos, int dir, int speed, int wobble);
|
||||
void Tick();
|
||||
void Kill();
|
||||
bool Alive();
|
||||
int _pos;
|
||||
int _wobble;
|
||||
int playerSide;
|
||||
private:
|
||||
int _dir;
|
||||
int _speed;
|
||||
int _alive;
|
||||
int _origin;
|
||||
};
|
||||
|
||||
void Enemy::Spawn(int pos, int dir, int speed, int wobble){
|
||||
_pos = pos;
|
||||
_dir = dir; // 0 = left, 1 = right
|
||||
_wobble = wobble; // 0 = no, >0 = yes, value is width of wobble
|
||||
_origin = pos;
|
||||
_speed = speed;
|
||||
_alive = 1;
|
||||
}
|
||||
|
||||
void Enemy::Tick(){
|
||||
if(_alive){
|
||||
if(_wobble > 0){
|
||||
_pos = _origin + (sin((millis()/3000.0)*_speed)*_wobble);
|
||||
}else{
|
||||
if(_dir == 0){
|
||||
_pos -= _speed;
|
||||
}else{
|
||||
_pos += _speed;
|
||||
}
|
||||
if(_pos > 1000) {
|
||||
Kill();
|
||||
}
|
||||
if(_pos <= 0) {
|
||||
Kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Enemy::Alive(){
|
||||
return _alive;
|
||||
}
|
||||
|
||||
void Enemy::Kill(){
|
||||
_alive = 0;
|
||||
}
|
||||
39
TWANG32/Lava.h
Normal file
39
TWANG32/Lava.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
class Lava
|
||||
{
|
||||
public:
|
||||
void Spawn(int left, int right, int ontime, int offtime, int offset, int state);
|
||||
void Kill();
|
||||
int Alive();
|
||||
int _left;
|
||||
int _right;
|
||||
int _ontime;
|
||||
int _offtime;
|
||||
int _offset;
|
||||
long _lastOn;
|
||||
int _state;
|
||||
static const int OFF = 0;
|
||||
static const int ON = 1;
|
||||
private:
|
||||
int _alive;
|
||||
};
|
||||
|
||||
void Lava::Spawn(int left, int right, int ontime, int offtime, int offset, int state){
|
||||
_left = left;
|
||||
_right = right;
|
||||
_ontime = ontime;
|
||||
_offtime = offtime;
|
||||
_offset = offset;
|
||||
_alive = 1;
|
||||
_lastOn = millis()-offset;
|
||||
_state = state;
|
||||
}
|
||||
|
||||
void Lava::Kill(){
|
||||
_alive = 0;
|
||||
}
|
||||
|
||||
int Lava::Alive(){
|
||||
return _alive;
|
||||
}
|
||||
59
TWANG32/Particle.h
Normal file
59
TWANG32/Particle.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "Arduino.h"
|
||||
#define FRICTION 1
|
||||
|
||||
class Particle
|
||||
{
|
||||
public:
|
||||
void Spawn(int pos);
|
||||
void Tick(int USE_GRAVITY);
|
||||
void Kill();
|
||||
bool Alive();
|
||||
int _pos;
|
||||
int _power;
|
||||
private:
|
||||
int _life;
|
||||
int _alive;
|
||||
int _sp;
|
||||
};
|
||||
|
||||
void Particle::Spawn(int pos){
|
||||
_pos = pos;
|
||||
_sp = random(-200, 200);
|
||||
_power = 255;
|
||||
_alive = 1;
|
||||
_life = 220 - abs(_sp);
|
||||
}
|
||||
|
||||
void Particle::Tick(int USE_GRAVITY){
|
||||
if(_alive){
|
||||
_life ++;
|
||||
if(_sp > 0){
|
||||
_sp -= _life/10;
|
||||
}else{
|
||||
_sp += _life/10;
|
||||
}
|
||||
if(USE_GRAVITY && _pos > 500) _sp -= 10;
|
||||
_power = 100 - _life;
|
||||
if(_power <= 0){
|
||||
Kill();
|
||||
}else{
|
||||
_pos += _sp/7.0;
|
||||
if(_pos > 1000){
|
||||
_pos = 1000;
|
||||
_sp = 0-(_sp/2);
|
||||
}
|
||||
else if(_pos < 0){
|
||||
_pos = 0;
|
||||
_sp = 0-(_sp/2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Particle::Alive(){
|
||||
return _alive;
|
||||
}
|
||||
|
||||
void Particle::Kill(){
|
||||
_alive = 0;
|
||||
}
|
||||
1329
TWANG32/SoundData.h
Normal file
1329
TWANG32/SoundData.h
Normal file
File diff suppressed because it is too large
Load Diff
35
TWANG32/Spawner.h
Normal file
35
TWANG32/Spawner.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
class Spawner
|
||||
{
|
||||
public:
|
||||
void Spawn(int pos, int rate, int sp, int dir, long activate);
|
||||
void Kill();
|
||||
int Alive();
|
||||
int _pos;
|
||||
int _rate;
|
||||
int _sp;
|
||||
int _dir;
|
||||
long _lastSpawned;
|
||||
long _activate;
|
||||
private:
|
||||
int _alive;
|
||||
};
|
||||
|
||||
void Spawner::Spawn(int pos, int rate, int sp, int dir, long activate){
|
||||
_pos = pos;
|
||||
_rate = rate;
|
||||
_sp = sp;
|
||||
_dir = dir;
|
||||
_activate = millis()+activate;
|
||||
_alive = 1;
|
||||
}
|
||||
|
||||
void Spawner::Kill(){
|
||||
_alive = 0;
|
||||
_lastSpawned = 0;
|
||||
}
|
||||
|
||||
int Spawner::Alive(){
|
||||
return _alive;
|
||||
}
|
||||
1242
TWANG32/TWANG32.ino
Normal file
1242
TWANG32/TWANG32.ino
Normal file
File diff suppressed because it is too large
Load Diff
38
TWANG32/iSin.h
Normal file
38
TWANG32/iSin.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
class iSin
|
||||
{
|
||||
public:
|
||||
int convert(long x);
|
||||
private:
|
||||
uint8_t isinTable8[91] = {
|
||||
0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44,
|
||||
49, 53, 57, 62, 66, 70, 75, 79, 83, 87,
|
||||
91, 96, 100, 104, 108, 112, 116, 120, 124, 128,
|
||||
131, 135, 139, 143, 146, 150, 153, 157, 160, 164,
|
||||
167, 171, 174, 177, 180, 183, 186, 190, 192, 195,
|
||||
198, 201, 204, 206, 209, 211, 214, 216, 219, 221,
|
||||
223, 225, 227, 229, 231, 233, 235, 236, 238, 240,
|
||||
241, 243, 244, 245, 246, 247, 248, 249, 250, 251,
|
||||
252, 253, 253, 254, 254, 254, 255, 255, 255, 255
|
||||
};
|
||||
};
|
||||
|
||||
int iSin::convert(long x)
|
||||
{
|
||||
boolean pos = true; // positive - keeps an eye on the sign.
|
||||
if (x < 0)
|
||||
{
|
||||
x = -x;
|
||||
pos = !pos;
|
||||
}
|
||||
if (x >= 360) x %= 360;
|
||||
if (x > 180)
|
||||
{
|
||||
x -= 180;
|
||||
pos = !pos;
|
||||
}
|
||||
if (x > 90) x = 180 - x;
|
||||
if (pos) return isinTable8[x]/2 ;
|
||||
return -isinTable8[x]/2 ;
|
||||
}
|
||||
411
TWANG32/settings.h
Normal file
411
TWANG32/settings.h
Normal file
@@ -0,0 +1,411 @@
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
#include <EEPROM.h>
|
||||
#include "sound.h"
|
||||
|
||||
// Version 2 adds the number of LEDs
|
||||
|
||||
// change this whenever the saved settings are not compatible with a change
|
||||
// It forces a reset from defaults.
|
||||
#define SETTINGS_VERSION 2
|
||||
#define EEPROM_SIZE 256
|
||||
|
||||
// LEDS
|
||||
#define NUM_LEDS 144
|
||||
#define MIN_LEDS 60
|
||||
#define MAX_LEDS 1000
|
||||
|
||||
|
||||
#define DEFAULT_BRIGHTNESS 150
|
||||
#define MIN_BRIGHTNESS 10
|
||||
#define MAX_BRIGHTNESS 255
|
||||
|
||||
// PLAYER
|
||||
const uint8_t MAX_PLAYER_SPEED = 10; // Max move speed of the player
|
||||
const uint8_t LIVES_PER_LEVEL = 3; // default lives per level
|
||||
#define MIN_LIVES_PER_LEVEL 3
|
||||
#define MAX_LIVES_PER_LEVEL 9
|
||||
|
||||
// JOYSTICK
|
||||
#define JOYSTICK_ORIENTATION 1 // 0, 1 or 2 to set the axis of the joystick
|
||||
#define JOYSTICK_DIRECTION 1 // 0/1 to flip joystick direction
|
||||
#define DEFAULT_ATTACK_THRESHOLD 30000 // The threshold that triggers an attack
|
||||
#define MIN_ATTACK_THRESHOLD 20000
|
||||
#define MAX_ATTACK_THRESHOLD 30000
|
||||
|
||||
|
||||
#define DEFAULT_JOYSTICK_DEADZONE 8 // Angle to ignore
|
||||
#define MIN_JOYSTICK_DEADZONE 3
|
||||
#define MAX_JOYSTICK_DEADZONE 12
|
||||
|
||||
// AUDIO
|
||||
#define DEFAULT_VOLUME 180 // 0 to 255
|
||||
#define MIN_VOLUME 0
|
||||
#define MAX_VOLUME 255
|
||||
|
||||
|
||||
|
||||
|
||||
#define DAC_AUDIO_PIN 25 // should be 25 or 26 only
|
||||
|
||||
enum ErrorNums{
|
||||
ERR_SETTING_NUM,
|
||||
ERR_SETTING_RANGE
|
||||
};
|
||||
|
||||
long lastInputTime = 0;
|
||||
|
||||
|
||||
//TODO ... move all the settings to this file.
|
||||
|
||||
// Function prototypes
|
||||
//void reset_settings();
|
||||
void settings_init();
|
||||
void show_game_stats();
|
||||
void settings_eeprom_write();
|
||||
void settings_eeprom_read();
|
||||
void change_setting_serial(char *line);
|
||||
void processSerial(char inChar);
|
||||
void printError(int reason);
|
||||
void show_settings_menu();
|
||||
void reset_settings();
|
||||
void change_setting(char paramCode, uint16_t newValue);
|
||||
|
||||
SemaphoreHandle_t xMutex;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t settings_version; // stores the settings format version
|
||||
|
||||
uint16_t led_count;
|
||||
uint8_t led_brightness;
|
||||
|
||||
uint8_t joystick_deadzone;
|
||||
uint16_t attack_threshold;
|
||||
|
||||
uint8_t audio_volume;
|
||||
|
||||
uint8_t lives_per_level;
|
||||
|
||||
// saved statistics
|
||||
uint16_t games_played;
|
||||
uint32_t total_points;
|
||||
uint16_t high_score;
|
||||
uint16_t boss_kills;
|
||||
|
||||
}settings_t;
|
||||
|
||||
settings_t user_settings;
|
||||
|
||||
#define READ_BUFFER_LEN 10
|
||||
#define CARRIAGE_RETURN 13
|
||||
char readBuffer[READ_BUFFER_LEN];
|
||||
uint8_t readIndex = 0;
|
||||
|
||||
void settings_init() {
|
||||
|
||||
settings_eeprom_read();
|
||||
show_settings_menu();
|
||||
show_game_stats();
|
||||
}
|
||||
|
||||
void checkSerialInput() {
|
||||
if (Serial.available()) {
|
||||
processSerial(Serial.read());
|
||||
}
|
||||
}
|
||||
|
||||
void processSerial(char inChar)
|
||||
{
|
||||
readBuffer[readIndex] = inChar;
|
||||
switch(readBuffer[readIndex]){
|
||||
case '?':
|
||||
readIndex = 0;
|
||||
show_settings_menu();
|
||||
return;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
readIndex = 0;
|
||||
reset_settings();
|
||||
settings_eeprom_write();
|
||||
return;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
user_settings.games_played = 0;
|
||||
user_settings.total_points = 0;
|
||||
user_settings.high_score = 0;
|
||||
user_settings.boss_kills = 0;
|
||||
settings_eeprom_write();
|
||||
return;
|
||||
break;
|
||||
|
||||
case '!':
|
||||
ESP.restart();
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (readBuffer[readIndex] == CARRIAGE_RETURN) {
|
||||
if (readIndex < 3) {
|
||||
// not enough characters
|
||||
readIndex = 0;
|
||||
}
|
||||
else {
|
||||
readBuffer[readIndex] = 0; // mark it as the end of the string
|
||||
change_setting_serial(readBuffer);
|
||||
readIndex = 0;
|
||||
}
|
||||
}
|
||||
else if (readIndex >= READ_BUFFER_LEN) {
|
||||
readIndex = 0; // too many characters. Reset and try again
|
||||
}
|
||||
else
|
||||
readIndex++;
|
||||
}
|
||||
|
||||
void change_setting_serial(char *line) {
|
||||
// line formate should be ss=nn
|
||||
// ss is always a 2 character integer
|
||||
// nn starts at index 3 and can be up to a 5 character unsigned integer
|
||||
|
||||
//12=12345
|
||||
//01234567
|
||||
|
||||
char setting_val[6];
|
||||
char param;
|
||||
uint16_t newValue;
|
||||
//Serial.print("Read Buffer: "); Serial.println(readBuffer);
|
||||
|
||||
if (readBuffer[1] != '='){ // check if the equals sign is there
|
||||
Serial.print("Missing '=' in command");
|
||||
readIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// move the value characters into a char array while verifying they are digits
|
||||
for(int i=0; i<5; i++) {
|
||||
if (i+2 < readIndex) {
|
||||
if (isDigit(readBuffer[i+2]))
|
||||
setting_val[i] = readBuffer[i+2];
|
||||
else {
|
||||
Serial.println("Invalid setting value");
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
setting_val[i] = 0;
|
||||
}
|
||||
|
||||
param = readBuffer[0];
|
||||
newValue = atoi(setting_val); // convert the val section to an integer
|
||||
|
||||
memset(readBuffer,0,sizeof(readBuffer));
|
||||
|
||||
change_setting(param, newValue);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void change_setting(char paramCode, uint16_t newValue)
|
||||
{
|
||||
switch (paramCode) {
|
||||
|
||||
|
||||
lastInputTime = millis(); // reset screensaver count
|
||||
|
||||
case 'C': // LED Count
|
||||
user_settings.led_count = constrain(newValue, MIN_LEDS, MAX_LEDS);
|
||||
settings_eeprom_write();
|
||||
break;
|
||||
|
||||
case 'B': // brightness
|
||||
user_settings.led_brightness = constrain(newValue, MIN_BRIGHTNESS, MAX_BRIGHTNESS);
|
||||
FastLED.setBrightness(user_settings.led_brightness);
|
||||
settings_eeprom_write();
|
||||
break;
|
||||
|
||||
case 'S': // sound
|
||||
user_settings.audio_volume = constrain(newValue, MIN_VOLUME, MAX_VOLUME);
|
||||
settings_eeprom_write();
|
||||
break;
|
||||
|
||||
case 'D': // deadzone, joystick
|
||||
user_settings.joystick_deadzone = constrain(newValue, MIN_JOYSTICK_DEADZONE, MAX_JOYSTICK_DEADZONE);
|
||||
settings_eeprom_write();
|
||||
break;
|
||||
|
||||
case 'A': // attack threshold, joystick
|
||||
user_settings.attack_threshold = constrain(newValue, MIN_ATTACK_THRESHOLD, MAX_ATTACK_THRESHOLD);
|
||||
settings_eeprom_write();
|
||||
break;
|
||||
|
||||
case 'L': // lives per level
|
||||
user_settings.lives_per_level = constrain(newValue, MIN_LIVES_PER_LEVEL, MAX_LIVES_PER_LEVEL);
|
||||
settings_eeprom_write();
|
||||
break;
|
||||
|
||||
default:
|
||||
Serial.print("Command Error: ");
|
||||
Serial.println(readBuffer[0]);
|
||||
return;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
show_settings_menu();
|
||||
|
||||
}
|
||||
|
||||
void reset_settings() {
|
||||
|
||||
|
||||
user_settings.settings_version = SETTINGS_VERSION;
|
||||
|
||||
user_settings.led_count = NUM_LEDS;
|
||||
user_settings.led_brightness = DEFAULT_BRIGHTNESS;
|
||||
|
||||
user_settings.joystick_deadzone = DEFAULT_JOYSTICK_DEADZONE;
|
||||
user_settings.attack_threshold = DEFAULT_ATTACK_THRESHOLD;
|
||||
|
||||
user_settings.audio_volume = DEFAULT_VOLUME;
|
||||
|
||||
user_settings.lives_per_level = LIVES_PER_LEVEL;
|
||||
|
||||
user_settings.games_played = 0;
|
||||
user_settings.total_points = 0;
|
||||
user_settings.high_score = 0;
|
||||
user_settings.boss_kills = 0;
|
||||
|
||||
Serial.println("Settings reset...");
|
||||
|
||||
settings_eeprom_write();
|
||||
}
|
||||
|
||||
void show_settings_menu() {
|
||||
Serial.println("\r\n====== TWANG Settings Menu ========");
|
||||
Serial.println("= Current values are shown =");
|
||||
Serial.println("= Send new values like B=150 =");
|
||||
Serial.println("= with a carriage return =");
|
||||
Serial.println("===================================");
|
||||
|
||||
Serial.print("\r\nC=");
|
||||
Serial.print(user_settings.led_count);
|
||||
Serial.println(" (LED Count 100-1000..forces restart)");
|
||||
|
||||
Serial.print("B=");
|
||||
Serial.print(user_settings.led_brightness);
|
||||
Serial.println(" (LED Brightness 5-255)");
|
||||
|
||||
Serial.print("S=");
|
||||
Serial.print(user_settings.audio_volume);
|
||||
Serial.println(" (Sound Volume 0-10)");
|
||||
|
||||
Serial.print("D=");
|
||||
Serial.print(user_settings.joystick_deadzone);
|
||||
Serial.println(" (Joystick Deadzone 3-12)");
|
||||
|
||||
Serial.print("A=");
|
||||
Serial.print(user_settings.attack_threshold);
|
||||
Serial.println(" (Attack Sensitivity 20000-35000)");
|
||||
|
||||
Serial.print("L=");
|
||||
Serial.print(user_settings.lives_per_level);
|
||||
Serial.println(" (Lives per Level (3-9))");
|
||||
|
||||
Serial.println("\r\n(Send...)");
|
||||
Serial.println(" ? to show current settings");
|
||||
Serial.println(" R to reset everything to defaults)");
|
||||
Serial.println(" P to reset play statistics)");
|
||||
}
|
||||
|
||||
void show_game_stats()
|
||||
{
|
||||
Serial.println("\r\n ===== Play statistics ======");
|
||||
Serial.print("Games played: ");Serial.println(user_settings.games_played);
|
||||
if (user_settings.games_played > 0) {
|
||||
Serial.print("Average Score: ");Serial.println(user_settings.total_points / user_settings.games_played);
|
||||
}
|
||||
Serial.print("High Score: ");Serial.println(user_settings.high_score);
|
||||
Serial.print("Boss kills: ");Serial.println(user_settings.boss_kills);
|
||||
}
|
||||
|
||||
void settings_eeprom_read() {
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
|
||||
uint8_t ver = EEPROM.read(0);
|
||||
uint8_t temp[sizeof(user_settings)];
|
||||
|
||||
if (ver != SETTINGS_VERSION) {
|
||||
Serial.print("Error: EEPROM settings read failed:"); Serial.println(ver);
|
||||
Serial.println("Loading defaults...");
|
||||
EEPROM.end();
|
||||
reset_settings();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
Serial.print("Settings version: "); Serial.println(ver);
|
||||
}
|
||||
|
||||
for (int i=0; i<sizeof(user_settings); i++)
|
||||
{
|
||||
temp[i] = EEPROM.read(i);
|
||||
}
|
||||
|
||||
EEPROM.end();
|
||||
|
||||
memcpy((char*)&user_settings, temp, sizeof(user_settings));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void settings_eeprom_write() {
|
||||
|
||||
Serial.println("Settings write...");
|
||||
|
||||
sound_pause(); // prevent interrupt from causing crash
|
||||
|
||||
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
|
||||
Serial.println("EEPROM open for write...");
|
||||
|
||||
uint8_t temp[sizeof(user_settings)];
|
||||
memcpy(temp, (uint8_t*)&user_settings, sizeof(user_settings));
|
||||
|
||||
for (int i=0; i<sizeof(user_settings); i++)
|
||||
{
|
||||
EEPROM.write(i, temp[i]);
|
||||
}
|
||||
|
||||
EEPROM.commit();
|
||||
|
||||
EEPROM.end();
|
||||
|
||||
sound_resume(); // restore sound interrupt
|
||||
|
||||
}
|
||||
|
||||
void printError(int reason) {
|
||||
|
||||
switch(reason) {
|
||||
case ERR_SETTING_NUM:
|
||||
Serial.print("Error: Invalid setting number");
|
||||
break;
|
||||
case ERR_SETTING_RANGE:
|
||||
Serial.print("Error: Setting out of range");
|
||||
break;
|
||||
default:
|
||||
Serial.print("Error:");Serial.println(reason);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
99
TWANG32/sound.h
Normal file
99
TWANG32/sound.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* This creates sound tones by outputting a square wave on a DAC pin. The
|
||||
* volume of the tone is the level of the DAC pin.
|
||||
*
|
||||
* The square wave is created by a timer. The timer runs at 2x the freq, because
|
||||
* it needs to transition high and then low.
|
||||
*
|
||||
*
|
||||
*/
|
||||
#ifndef SOUND_H
|
||||
#define SOUND_H
|
||||
|
||||
#include "esp32-hal-timer.h";
|
||||
|
||||
#define ESP32_F_CPU 80000000 // the speed of the processor
|
||||
#define AUDIO_INTERRUPT_PRESCALER 80
|
||||
#define SOUND_TIMER_NO 0
|
||||
//#define AUDIO_PIN 25
|
||||
#define MIN_FREQ 20
|
||||
#define MAX_FREQ 16000
|
||||
|
||||
hw_timer_t * sndTimer = NULL;
|
||||
|
||||
bool sound_on = true;
|
||||
bool sound_wave_high = true; // this toggles to create the high/low transitions of the wave
|
||||
uint8_t sound_volume = 0;
|
||||
|
||||
void sound_init(int pin);
|
||||
bool sound(uint16_t freq, uint8_t volume);
|
||||
void soundOff();
|
||||
|
||||
int dac_pin;
|
||||
|
||||
|
||||
|
||||
void IRAM_ATTR onSoundTimer()
|
||||
{
|
||||
if (sound_on) {
|
||||
dacWrite(dac_pin, (sound_wave_high?sound_volume:0));
|
||||
sound_wave_high = ! sound_wave_high;
|
||||
|
||||
}
|
||||
else
|
||||
dacWrite(dac_pin, 0);
|
||||
}
|
||||
|
||||
void sound_init(int pin){ // pin must be a DAC pin number !! (typically 25 or 26)
|
||||
dac_pin = pin;
|
||||
sound_on = false;
|
||||
pinMode(dac_pin, OUTPUT);
|
||||
sound_volume = 0;
|
||||
|
||||
sndTimer = timerBegin(SOUND_TIMER_NO, AUDIO_INTERRUPT_PRESCALER, true);
|
||||
timerAttachInterrupt(sndTimer, &onSoundTimer, true);
|
||||
timerAlarmWrite(sndTimer, ESP32_F_CPU/AUDIO_INTERRUPT_PRESCALER/MIN_FREQ, true); // lower timer freq
|
||||
timerAlarmEnable(sndTimer);
|
||||
}
|
||||
|
||||
void sound_pause() // this prevents the interrupt from firing ... use during eeprom write
|
||||
{
|
||||
if (sndTimer != NULL)
|
||||
timerStop(sndTimer);
|
||||
}
|
||||
|
||||
void sound_resume() // resume from pause ... after eeprom write
|
||||
{
|
||||
if (sndTimer != NULL)
|
||||
timerRestart(sndTimer);
|
||||
}
|
||||
|
||||
bool sound(uint16_t freq, uint8_t volume){
|
||||
if (volume == 0) {
|
||||
soundOff();
|
||||
return false;
|
||||
}
|
||||
if (freq < MIN_FREQ || freq > MAX_FREQ) {
|
||||
return false;
|
||||
}
|
||||
sound_on = true;
|
||||
sound_volume = volume;
|
||||
timerAlarmWrite(sndTimer, ESP32_F_CPU/AUDIO_INTERRUPT_PRESCALER/(freq * 2), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
void soundOff(){
|
||||
sound_on = false;
|
||||
sound_volume = 0;
|
||||
timerAlarmWrite(sndTimer, ESP32_F_CPU/AUDIO_INTERRUPT_PRESCALER/(MIN_FREQ), true); // lower timer freq
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
55
TWANG32/twang_mpu.h
Normal file
55
TWANG32/twang_mpu.h
Normal file
@@ -0,0 +1,55 @@
|
||||
// A very simple implementation of the MPU-6050 limited to the
|
||||
// TWANG requirements
|
||||
// I reused the function names to make it compatible
|
||||
// B. Dring 2/2018
|
||||
|
||||
class Twang_MPU
|
||||
{
|
||||
|
||||
public:
|
||||
void initialize();
|
||||
void getMotion6(int16_t* xAccel, int16_t* yAccel, int16_t* zAccel, int16_t* xGyro, int16_t* yGyro, int16_t* zGyro);
|
||||
bool verify();
|
||||
|
||||
private:
|
||||
static const uint8_t MPU_ADDR = 0x68;
|
||||
static const uint8_t PWR_MGMT_1 = 0x6B;
|
||||
static const uint8_t MPU_DATA_REG_START = 0x3B;
|
||||
static const uint8_t MPU_DATA_LEN = 14;
|
||||
static const uint8_t MPU_DATA_WHO_AM_I = 0x75;
|
||||
|
||||
};
|
||||
|
||||
void Twang_MPU::initialize()
|
||||
{
|
||||
Wire.beginTransmission(MPU_ADDR);
|
||||
Wire.write(PWR_MGMT_1); // PWR_MGMT_1 register
|
||||
Wire.write(0); // set to zero (wakes up the MPU-6050)
|
||||
Wire.endTransmission(true);
|
||||
}
|
||||
|
||||
bool Twang_MPU::verify()
|
||||
{
|
||||
Wire.beginTransmission(MPU_ADDR);
|
||||
Wire.write(MPU_DATA_WHO_AM_I);
|
||||
Wire.endTransmission(false);
|
||||
Wire.requestFrom(MPU_ADDR,1,true); // read the whole MPU data section
|
||||
return (Wire.read() == MPU_ADDR);
|
||||
}
|
||||
|
||||
void Twang_MPU::getMotion6(int16_t* xAccel, int16_t* yAccel, int16_t* zAccel, int16_t* xGyro, int16_t* yGyro, int16_t* zGyro)
|
||||
{
|
||||
|
||||
Wire.beginTransmission(MPU_ADDR);
|
||||
Wire.write(MPU_DATA_REG_START); // starting with register 0x3B (ACCEL_XOUT_H)
|
||||
Wire.endTransmission(false);
|
||||
Wire.requestFrom(MPU_ADDR,MPU_DATA_LEN,true); // read the whole MPU data section
|
||||
*xAccel=Wire.read()<<8|Wire.read(); // x Accel
|
||||
*yAccel=Wire.read()<<8|Wire.read(); // y Accel
|
||||
*zAccel=Wire.read()<<8|Wire.read(); // z Accel
|
||||
Wire.read(); Wire.read(); // Temperature..not used, but need to read it
|
||||
*xGyro=Wire.read()<<8|Wire.read(); // x Gyro
|
||||
*yGyro=Wire.read()<<8|Wire.read(); // y Gyro
|
||||
*zGyro=Wire.read()<<8|Wire.read(); // z Gyro
|
||||
}
|
||||
|
||||
148
TWANG32/wifi_ap.h
Normal file
148
TWANG32/wifi_ap.h
Normal file
@@ -0,0 +1,148 @@
|
||||
#include <WiFi.h>
|
||||
#include "settings.h"
|
||||
|
||||
const char* ssid = "TWANG_AP";
|
||||
const char* passphrase = "esp32rocks";
|
||||
|
||||
WiFiServer server(80);
|
||||
|
||||
char linebuf[80];
|
||||
int charcount=0;
|
||||
|
||||
void ap_setup() {
|
||||
bool ret;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Set up an access point
|
||||
* @param ssid Pointer to the SSID (max 63 char).
|
||||
* @param passphrase (for WPA2 min 8 char, for open use NULL)
|
||||
* @param channel WiFi channel number, 1 - 13.
|
||||
* @param ssid_hidden Network cloaking (0 = broadcast SSID, 1 = hide SSID)
|
||||
*/
|
||||
ret = WiFi.softAP(ssid, passphrase, 2, 0);
|
||||
|
||||
//Serial.println("\r\nWiFi AP online ...");
|
||||
server.begin();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void sendStatsPage(WiFiClient client) {
|
||||
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
|
||||
// and a content-type so the client knows what's coming, then a blank line:
|
||||
client.println("HTTP/1.1 200 OK");
|
||||
client.println("Content-type:text/html");
|
||||
client.println();
|
||||
client.println("<html>");
|
||||
client.println("<body>");
|
||||
client.println("<h1>TWANG32 Play Stats</h1>");
|
||||
client.println("<ul>");
|
||||
|
||||
|
||||
client.print("<li>Games played: "); client.print(user_settings.games_played); client.println("</li>");
|
||||
if (user_settings.games_played > 0) { // prevent divide by 0
|
||||
client.print("<li>Average score: "); client.print(user_settings.total_points / user_settings.games_played); client.println("</li>");
|
||||
}
|
||||
client.print("<li>High score: "); client.print(user_settings.high_score); client.println("</li>");
|
||||
client.print("<li>Boss kills: "); client.print(user_settings.boss_kills); client.println("</li>");
|
||||
|
||||
client.print("<button onClick=\"location.href = 'http://192.168.4.1'\">Refresh</button>");
|
||||
|
||||
client.print("<h2>Adjustable Settings </h2>");
|
||||
|
||||
client.print("<table>");
|
||||
|
||||
client.print("<tr><td>LED Count (60-1000)</td><td><form><input type='number' name='C' value='");
|
||||
client.print(user_settings.led_count);
|
||||
client.print ("' min='60' max='1000'><input type='submit'></form></td></tr>");
|
||||
|
||||
client.print("<tr><td>Brightness (10-255)</td><td><form><input type='number' name='B' value='");
|
||||
client.print(user_settings.led_brightness);
|
||||
client.print ("' min='10' max='255'><input type='submit'></form></td></tr>");
|
||||
|
||||
client.print("<tr><td>Sound Volume (0-255)</td><td><form><input type='number' name='S' value='");
|
||||
client.print(user_settings.audio_volume);
|
||||
client.print("' min='0' max='255'><input type='submit'></form></td></tr>");
|
||||
|
||||
client.print("<tr><td>Joystick Deadzone (3-12)</td><td><form><input type='number' name='D' value='");
|
||||
client.print(user_settings.joystick_deadzone);
|
||||
client.print("' min='3' max='12'><input type='submit'></form></td></tr>");
|
||||
|
||||
client.print("<tr><td>Attack Sensitivity (20000-35000)</td><td><form><input type='number' name='A' value='");
|
||||
client.print(user_settings.attack_threshold);
|
||||
client.print("' min='2000' max='35000'><input type='submit'></form></td></tr>");
|
||||
|
||||
client.print("<tr><td>Lives Per Level (3-9)</td><td><form><input type='number' name='L' value='");
|
||||
client.print(user_settings.lives_per_level);
|
||||
client.print("' min='3' max='9'><input type='submit'></form></td></tr>");
|
||||
|
||||
client.print("</table>");
|
||||
|
||||
client.println("</body>");
|
||||
client.println("</html>");
|
||||
client.println();
|
||||
|
||||
}
|
||||
|
||||
void ap_client_check(){
|
||||
int cnt;
|
||||
bool newconn=false;
|
||||
int stat;
|
||||
WiFiClient client = server.available(); // listen for incoming clients
|
||||
|
||||
//if (client) { // if you get a client,
|
||||
// sendStatsPage(client);
|
||||
// Serial.println("printUploadForm");
|
||||
//}
|
||||
bool currentLineIsBlank = true;
|
||||
|
||||
while (client.connected()) {
|
||||
if (client.available()) {
|
||||
char c = client.read();
|
||||
//Serial.write(c);
|
||||
linebuf[charcount]=c;
|
||||
if (charcount<sizeof(linebuf)-1)
|
||||
charcount++;
|
||||
|
||||
if (c == '\n' && currentLineIsBlank) {
|
||||
sendStatsPage(client);
|
||||
break;
|
||||
}
|
||||
if (c == '\n') {
|
||||
// you're starting a new line
|
||||
currentLineIsBlank = true;
|
||||
|
||||
|
||||
if (strstr(linebuf,"GET /?") > 0)
|
||||
{
|
||||
String line = String(linebuf);
|
||||
|
||||
int start = line.indexOf('=', 0);
|
||||
|
||||
char paramCode = line.charAt(start - 1);
|
||||
|
||||
int finish = line.indexOf('H', start+1)-1;
|
||||
String val = line.substring(start+1, finish);
|
||||
// if it is not numeric, it will convert to 0.
|
||||
// The the change_setting function will make sure the range is OK
|
||||
|
||||
change_setting(paramCode, val.toInt());
|
||||
|
||||
|
||||
}
|
||||
|
||||
// you're starting a new line
|
||||
currentLineIsBlank = true;
|
||||
memset(linebuf,0,sizeof(linebuf));
|
||||
charcount=0;
|
||||
} else if (c != '\r') {
|
||||
// you've gotten a character on the current line
|
||||
currentLineIsBlank = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user