parent
e79cbc265a
commit
211740d51a
95
Globals.cpp
95
Globals.cpp
@ -2,6 +2,7 @@
|
||||
#include "Globals.h"
|
||||
#include "StateHandler.h"
|
||||
#include "LowPower.h"
|
||||
#include "EEPROM.h"
|
||||
|
||||
|
||||
SegmentDisplay* display;
|
||||
@ -15,6 +16,13 @@ uint32_t hits = 0;
|
||||
unsigned long currentTime;
|
||||
AbstractStateHandler* currentState;
|
||||
|
||||
byte shotCounterOffset;
|
||||
byte hitCounterOffset;
|
||||
|
||||
|
||||
#define counterTreshold (uint32_t)10000
|
||||
uint32_t lastShotCounterIteration;
|
||||
uint32_t lastHitCounterIteration;
|
||||
|
||||
void setCurrentState(AbstractStateHandler* value)
|
||||
{
|
||||
@ -36,7 +44,7 @@ void update()
|
||||
|
||||
// Count the shot no matter which state we're in
|
||||
if (buttonArmed->changed() && !buttonArmed->pressed())
|
||||
shots++;
|
||||
addShot();
|
||||
}
|
||||
|
||||
|
||||
@ -72,4 +80,89 @@ void sleep()
|
||||
buttonB->update(currentTime);
|
||||
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 sleep();
|
||||
|
||||
void readCounters();
|
||||
void addShot();
|
||||
void addHit();
|
||||
void resetShots();
|
||||
void resetHits();
|
||||
|
||||
#endif
|
@ -20,6 +20,7 @@ void setup()
|
||||
display->setLatchPin(NerfLatchPin);
|
||||
display->setDigits(NerfDigits);
|
||||
display->begin();
|
||||
display->clear();
|
||||
|
||||
|
||||
// Configure buttons
|
||||
@ -33,6 +34,7 @@ void setup()
|
||||
buttonArmed->init(NerfButtonArmed, LOW);
|
||||
|
||||
|
||||
readCounters();
|
||||
setCurrentState(new DefaultState());
|
||||
}
|
||||
|
||||
|
@ -46,4 +46,11 @@
|
||||
#define NerfDefaultSleepTime 10000
|
||||
|
||||
|
||||
/**
|
||||
* Reset state configuration
|
||||
**/
|
||||
#define NerfResetIntroTime 1000
|
||||
#define NerfResetOutroTime 2000
|
||||
|
||||
|
||||
#endif
|
@ -3,6 +3,7 @@
|
||||
#include "Globals.h"
|
||||
#include "StateLoseTheGame.h"
|
||||
#include "StateUserUnknown.h"
|
||||
#include "StateReset.h"
|
||||
|
||||
|
||||
bool DefaultState::ShowHits = true;
|
||||
@ -24,10 +25,10 @@ void DefaultState::loop()
|
||||
return;
|
||||
}
|
||||
|
||||
if (buttonA->changed() && !buttonA->pressed())
|
||||
// A short (triggered on release)
|
||||
if (buttonA->changed() && !buttonA->pressed() && buttonA->pressedMillis(currentTime) <= NerfButtonLongPressThreshold)
|
||||
{
|
||||
// A (triggered on release)
|
||||
hits++;
|
||||
addHit();
|
||||
|
||||
if (!DefaultState::ShowHits)
|
||||
setShowHits(true);
|
||||
@ -35,6 +36,12 @@ void DefaultState::loop()
|
||||
lastAction = currentTime;
|
||||
}
|
||||
|
||||
// A long
|
||||
if (buttonA->pressed() && buttonA->pressedMillis(currentTime) > NerfButtonLongPressThreshold)
|
||||
{
|
||||
setCurrentState(new ResetState());
|
||||
}
|
||||
|
||||
// B short (triggered on release)
|
||||
if (buttonB->changed() && !buttonB->pressed() && buttonB->pressedMillis(currentTime) <= NerfButtonLongPressThreshold)
|
||||
{
|
||||
|
@ -10,7 +10,8 @@
|
||||
* Start by showing the current counter mode (hits or shots),
|
||||
* 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
|
||||
* A + B: Display "Error user unknwn"
|
||||
* 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