parent
e79cbc265a
commit
211740d51a
95
Globals.cpp
95
Globals.cpp
@ -2,6 +2,7 @@
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "StateHandler.h"
|
#include "StateHandler.h"
|
||||||
#include "LowPower.h"
|
#include "LowPower.h"
|
||||||
|
#include "EEPROM.h"
|
||||||
|
|
||||||
|
|
||||||
SegmentDisplay* display;
|
SegmentDisplay* display;
|
||||||
@ -15,6 +16,13 @@ uint32_t hits = 0;
|
|||||||
unsigned long currentTime;
|
unsigned long currentTime;
|
||||||
AbstractStateHandler* currentState;
|
AbstractStateHandler* currentState;
|
||||||
|
|
||||||
|
byte shotCounterOffset;
|
||||||
|
byte hitCounterOffset;
|
||||||
|
|
||||||
|
|
||||||
|
#define counterTreshold (uint32_t)10000
|
||||||
|
uint32_t lastShotCounterIteration;
|
||||||
|
uint32_t lastHitCounterIteration;
|
||||||
|
|
||||||
void setCurrentState(AbstractStateHandler* value)
|
void setCurrentState(AbstractStateHandler* value)
|
||||||
{
|
{
|
||||||
@ -36,7 +44,7 @@ void update()
|
|||||||
|
|
||||||
// Count the shot no matter which state we're in
|
// Count the shot no matter which state we're in
|
||||||
if (buttonArmed->changed() && !buttonArmed->pressed())
|
if (buttonArmed->changed() && !buttonArmed->pressed())
|
||||||
shots++;
|
addShot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -73,3 +81,88 @@ void sleep()
|
|||||||
buttonB->block();
|
buttonB->block();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define counterLocation(offset) 2 + (offset * sizeof(uint32_t))
|
||||||
|
|
||||||
|
void readCounters()
|
||||||
|
{
|
||||||
|
shotCounterOffset = EEPROM.read(0);
|
||||||
|
hitCounterOffset = EEPROM.read(1);
|
||||||
|
|
||||||
|
EEPROM.get(counterLocation(shotCounterOffset), shots);
|
||||||
|
EEPROM.get(counterLocation(hitCounterOffset), hits);
|
||||||
|
|
||||||
|
lastShotCounterIteration = shots / counterTreshold;
|
||||||
|
lastHitCounterIteration = hits / counterTreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void setShots(uint32_t value)
|
||||||
|
{
|
||||||
|
shots = value;
|
||||||
|
|
||||||
|
uint32_t newShotCounterIteration = shots / counterTreshold;
|
||||||
|
if (newShotCounterIteration != lastShotCounterIteration || value == 0)
|
||||||
|
{
|
||||||
|
shotCounterOffset++;
|
||||||
|
if (counterLocation(shotCounterOffset) > EEPROM.length() - sizeof(uint32_t))
|
||||||
|
{
|
||||||
|
shotCounterOffset = 0;
|
||||||
|
if (shotCounterOffset == hitCounterOffset)
|
||||||
|
shotCounterOffset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
EEPROM.write(0, shotCounterOffset);
|
||||||
|
lastShotCounterIteration = newShotCounterIteration;
|
||||||
|
}
|
||||||
|
|
||||||
|
EEPROM.write(counterLocation(shotCounterOffset), shots);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void addShot()
|
||||||
|
{
|
||||||
|
setShots(shots + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void setHits(uint32_t value)
|
||||||
|
{
|
||||||
|
hits = value;
|
||||||
|
|
||||||
|
uint32_t newHitCounterIteration = hits / counterTreshold;
|
||||||
|
if (newHitCounterIteration != lastHitCounterIteration || value == 0)
|
||||||
|
{
|
||||||
|
hitCounterOffset++;
|
||||||
|
if (counterLocation(hitCounterOffset) > EEPROM.length() - sizeof(uint32_t))
|
||||||
|
{
|
||||||
|
hitCounterOffset = 0;
|
||||||
|
if (hitCounterOffset == shotCounterOffset)
|
||||||
|
hitCounterOffset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
EEPROM.write(1, hitCounterOffset);
|
||||||
|
lastHitCounterIteration = newHitCounterIteration;
|
||||||
|
}
|
||||||
|
|
||||||
|
EEPROM.write(counterLocation(hitCounterOffset), hits);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void addHit()
|
||||||
|
{
|
||||||
|
setHits(hits + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void resetShots()
|
||||||
|
{
|
||||||
|
setShots(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void resetHits()
|
||||||
|
{
|
||||||
|
setHits(0);
|
||||||
|
}
|
@ -21,4 +21,10 @@ void setCurrentState(AbstractStateHandler* value);
|
|||||||
void update();
|
void update();
|
||||||
void sleep();
|
void sleep();
|
||||||
|
|
||||||
|
void readCounters();
|
||||||
|
void addShot();
|
||||||
|
void addHit();
|
||||||
|
void resetShots();
|
||||||
|
void resetHits();
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -20,6 +20,7 @@ void setup()
|
|||||||
display->setLatchPin(NerfLatchPin);
|
display->setLatchPin(NerfLatchPin);
|
||||||
display->setDigits(NerfDigits);
|
display->setDigits(NerfDigits);
|
||||||
display->begin();
|
display->begin();
|
||||||
|
display->clear();
|
||||||
|
|
||||||
|
|
||||||
// Configure buttons
|
// Configure buttons
|
||||||
@ -33,6 +34,7 @@ void setup()
|
|||||||
buttonArmed->init(NerfButtonArmed, LOW);
|
buttonArmed->init(NerfButtonArmed, LOW);
|
||||||
|
|
||||||
|
|
||||||
|
readCounters();
|
||||||
setCurrentState(new DefaultState());
|
setCurrentState(new DefaultState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,4 +46,11 @@
|
|||||||
#define NerfDefaultSleepTime 10000
|
#define NerfDefaultSleepTime 10000
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset state configuration
|
||||||
|
**/
|
||||||
|
#define NerfResetIntroTime 1000
|
||||||
|
#define NerfResetOutroTime 2000
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -3,6 +3,7 @@
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "StateLoseTheGame.h"
|
#include "StateLoseTheGame.h"
|
||||||
#include "StateUserUnknown.h"
|
#include "StateUserUnknown.h"
|
||||||
|
#include "StateReset.h"
|
||||||
|
|
||||||
|
|
||||||
bool DefaultState::ShowHits = true;
|
bool DefaultState::ShowHits = true;
|
||||||
@ -24,10 +25,10 @@ void DefaultState::loop()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buttonA->changed() && !buttonA->pressed())
|
// A short (triggered on release)
|
||||||
|
if (buttonA->changed() && !buttonA->pressed() && buttonA->pressedMillis(currentTime) <= NerfButtonLongPressThreshold)
|
||||||
{
|
{
|
||||||
// A (triggered on release)
|
addHit();
|
||||||
hits++;
|
|
||||||
|
|
||||||
if (!DefaultState::ShowHits)
|
if (!DefaultState::ShowHits)
|
||||||
setShowHits(true);
|
setShowHits(true);
|
||||||
@ -35,6 +36,12 @@ void DefaultState::loop()
|
|||||||
lastAction = currentTime;
|
lastAction = currentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A long
|
||||||
|
if (buttonA->pressed() && buttonA->pressedMillis(currentTime) > NerfButtonLongPressThreshold)
|
||||||
|
{
|
||||||
|
setCurrentState(new ResetState());
|
||||||
|
}
|
||||||
|
|
||||||
// B short (triggered on release)
|
// B short (triggered on release)
|
||||||
if (buttonB->changed() && !buttonB->pressed() && buttonB->pressedMillis(currentTime) <= NerfButtonLongPressThreshold)
|
if (buttonB->changed() && !buttonB->pressed() && buttonB->pressedMillis(currentTime) <= NerfButtonLongPressThreshold)
|
||||||
{
|
{
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
* Start by showing the current counter mode (hits or shots),
|
* Start by showing the current counter mode (hits or shots),
|
||||||
* then display the value.
|
* then display the value.
|
||||||
*
|
*
|
||||||
* A: Add hit
|
* A short: Add hit
|
||||||
|
* A long: Go to reset state
|
||||||
* B short: Toggle between hits and shots and restart state
|
* B short: Toggle between hits and shots and restart state
|
||||||
* A + B: Display "Error user unknwn"
|
* A + B: Display "Error user unknwn"
|
||||||
* B long: Display "You lost the game" animation (losethegame.com - you're welcome!)
|
* B long: Display "You lost the game" animation (losethegame.com - you're welcome!)
|
||||||
|
114
StateReset.cpp
Normal file
114
StateReset.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include "StateReset.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "NerfStatTrakConfig.h"
|
||||||
|
#include "StateDefault.h"
|
||||||
|
|
||||||
|
|
||||||
|
void ResetState::setup()
|
||||||
|
{
|
||||||
|
intro = true;
|
||||||
|
introStart = currentTime;
|
||||||
|
|
||||||
|
outro = false;
|
||||||
|
selected = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ResetState::loop()
|
||||||
|
{
|
||||||
|
if (intro)
|
||||||
|
{
|
||||||
|
if (currentTime - introStart >= NerfResetIntroTime)
|
||||||
|
intro = false;
|
||||||
|
|
||||||
|
char text[] = "Reset";
|
||||||
|
display->writeTextLeft(text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outro)
|
||||||
|
{
|
||||||
|
loopOutro();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (buttonA->changed() && !buttonA->pressed())
|
||||||
|
{
|
||||||
|
switch (selected)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
setCurrentState(new DefaultState());
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
resetHits();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
resetShots();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
resetHits();
|
||||||
|
resetShots();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
outroStart = currentTime;
|
||||||
|
outro = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttonB->changed() && !buttonB->pressed())
|
||||||
|
{
|
||||||
|
selected++;
|
||||||
|
if (selected > 3)
|
||||||
|
selected = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch (selected)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
char text[] = "Cancel";
|
||||||
|
display->writeTextLeft(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
char text[] = "Hits";
|
||||||
|
display->writeTextLeft(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
char text[] = "Shots";
|
||||||
|
display->writeTextLeft(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
char text[] = "Both";
|
||||||
|
display->writeTextLeft(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ResetState::loopOutro()
|
||||||
|
{
|
||||||
|
if (currentTime - outroStart >= NerfResetOutroTime)
|
||||||
|
{
|
||||||
|
setCurrentState(new DefaultState());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char text[] = "Done";
|
||||||
|
display->writeTextLeft(text);
|
||||||
|
}
|
31
StateReset.h
Normal file
31
StateReset.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef StateReset_h
|
||||||
|
#define StateReset_h
|
||||||
|
|
||||||
|
#include "StateHandler.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset state
|
||||||
|
*
|
||||||
|
* Shows a menu providing reset options. A confirms the
|
||||||
|
* selection, B switches to the next.
|
||||||
|
**/
|
||||||
|
class ResetState : public AbstractStateHandler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bool intro;
|
||||||
|
unsigned long introStart;
|
||||||
|
bool outro;
|
||||||
|
unsigned long outroStart;
|
||||||
|
byte selected;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void loopOutro();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setup();
|
||||||
|
void loop();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
51
reset/NerfStatTrakReset.ino
Normal file
51
reset/NerfStatTrakReset.ino
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "EEPROM.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
How the EEPROM is used:
|
||||||
|
|
||||||
|
|
||||||
|
First byte: shot counter offset
|
||||||
|
Second byte: hit counter offset
|
||||||
|
|
||||||
|
Each counter is a 32-bit unsigned integer (4 bytes). When it reaches a treshold
|
||||||
|
which is < 100,000 (the recommended EEPROM cell write limit) a new offset is calculated.
|
||||||
|
This way we ensure no cell is written over 100,000 times (assuming the EEPROM is
|
||||||
|
new) and you can click away until you run out of EEPROM.
|
||||||
|
|
||||||
|
|
||||||
|
For initialisation set ShotCounterOffset and HitCounterOffset to
|
||||||
|
different values. Keep in mind that Offset * 4 must not be greater than
|
||||||
|
the amount of available EEPROM!
|
||||||
|
|
||||||
|
Shot/HitCounterInitial defines the default value to write for
|
||||||
|
each counters.
|
||||||
|
|
||||||
|
*/
|
||||||
|
#define ShotCounterOffset 0
|
||||||
|
#define HitCounterOffset 1
|
||||||
|
|
||||||
|
#define ShotCounterInitial 0
|
||||||
|
#define HitCounterInitial 0
|
||||||
|
|
||||||
|
#define counterLocation(offset) 2 + (offset * sizeof(uint32_t))
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
EEPROM.update(0, ShotCounterOffset);
|
||||||
|
EEPROM.update(1, HitCounterOffset);
|
||||||
|
|
||||||
|
EEPROM.put(counterLocation(ShotCounterOffset), (uint32_t)ShotCounterInitial);
|
||||||
|
EEPROM.put(counterLocation(HitCounterOffset), (uint32_t)HitCounterInitial);
|
||||||
|
|
||||||
|
pinMode(LED_BUILTIN, OUTPUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
digitalWrite(LED_BUILTIN, HIGH);
|
||||||
|
delay(1000);
|
||||||
|
digitalWrite(LED_BUILTIN, LOW);
|
||||||
|
delay(1000);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user